Happy new year
[yazpp-moved-to-github.git] / src / yaz-z-cache.cpp
1 /* This file is part of the yazpp toolkit.
2  * Copyright (C) 1998-2012 Index Data and Mike Taylor
3  * See the file LICENSE for details.
4  */
5
6 #if HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 #include <yaz/log.h>
10 #include <yaz/proto.h>
11 #include <yaz/copy_types.h>
12 #include <yazpp/record-cache.h>
13
14 using namespace yazpp_1;
15
16 struct yazpp_1::RecordCache_Entry {
17     int m_offset;
18     Z_NamePlusRecord *m_record;
19     Z_RecordComposition *m_comp;
20     RecordCache_Entry *m_next;
21 };
22
23 RecordCache::RecordCache ()
24 {
25     m_mem = nmem_create();
26     m_entries = 0;
27     m_presentRequest = 0;
28     m_searchRequest = 0;
29     m_max_size = 200000;
30 }
31
32 RecordCache::~RecordCache ()
33 {
34     nmem_destroy(m_mem);
35 }
36
37 void RecordCache::set_max_size(size_t sz)
38 {
39     m_max_size = sz;
40 }
41
42 void RecordCache::clear ()
43 {
44     nmem_destroy(m_mem);
45     m_mem = nmem_create();
46     m_entries = 0;
47     m_presentRequest = 0;
48     m_searchRequest = 0;
49 }
50
51 void RecordCache::copy_searchRequest(Z_SearchRequest *sr)
52 {
53     ODR encode = odr_createmem(ODR_ENCODE);
54     ODR decode = odr_createmem(ODR_DECODE);
55
56     m_searchRequest = 0;
57     m_presentRequest = 0;
58     int v = z_SearchRequest (encode, &sr, 1, 0);
59     if (v)
60     {
61         int len;
62         char *buf = odr_getbuf(encode, &len, 0);
63         odr_setbuf(decode, buf, len, 0);
64         z_SearchRequest(decode, &m_searchRequest, 1, 0);
65         nmem_transfer(m_mem, decode->mem);
66     }
67     odr_destroy(encode);
68     odr_destroy(decode);
69 }
70
71 void RecordCache::copy_presentRequest(Z_PresentRequest *pr)
72 {
73     ODR encode = odr_createmem(ODR_ENCODE);
74     ODR decode = odr_createmem(ODR_DECODE);
75     
76     m_searchRequest = 0;
77     m_presentRequest = 0;
78     int v = z_PresentRequest (encode, &pr, 1, 0);
79     if (v)
80     {
81         int len;
82         char *buf = odr_getbuf(encode, &len, 0);
83         odr_setbuf(decode, buf, len, 0);
84         z_PresentRequest(decode, &m_presentRequest, 1, 0);
85         nmem_transfer(m_mem, decode->mem);
86     }
87     odr_destroy(encode);
88     odr_destroy(decode);
89 }
90
91
92 void RecordCache::add (ODR o, Z_NamePlusRecordList *npr, int start,
93                            int hits)
94 {
95     if (nmem_total(m_mem) > m_max_size)
96         return;
97     // Build appropriate compspec for this response
98     Z_RecordComposition *comp = 0;
99     if (hits == -1 && m_presentRequest)
100         comp = m_presentRequest->recordComposition;
101     else if (hits > 0 && m_searchRequest)
102     {
103         Z_ElementSetNames *esn;
104
105         if (hits <= *m_searchRequest->smallSetUpperBound)
106             esn = m_searchRequest->smallSetElementSetNames;
107         else
108             esn = m_searchRequest->mediumSetElementSetNames;
109         comp = (Z_RecordComposition *) nmem_malloc(m_mem, sizeof(*comp));
110         comp->which = Z_RecordComp_simple;
111         comp->u.simple = esn;
112     }
113
114     // Insert individual records in cache
115     int i;
116     for (i = 0; i<npr->num_records; i++)
117     {
118         RecordCache_Entry *entry = (RecordCache_Entry *)
119             nmem_malloc(m_mem, sizeof(*entry));
120         entry->m_record = yaz_clone_z_NamePlusRecord(npr->records[i], m_mem);
121         entry->m_comp = yaz_clone_z_RecordComposition(comp, m_mem);
122         entry->m_offset = i + start;
123         entry->m_next = m_entries;
124         m_entries = entry;
125     }
126 }
127
128 int RecordCache::match (RecordCache_Entry *entry,
129                             Odr_oid *syntax, int offset,
130                             Z_RecordComposition *comp)
131 {
132     // See if our compspec match...
133     int match = 0;
134     ODR o1 = odr_createmem(ODR_ENCODE);
135     ODR o2 = odr_createmem(ODR_ENCODE);
136     
137     z_RecordComposition(o1, &comp, 1, 0);
138     z_RecordComposition(o2, &entry->m_comp, 1, 0);
139
140     int len1 = -1;
141     char *buf1 = odr_getbuf(o1, &len1, 0);
142     int len2 = -1;
143     char *buf2 = odr_getbuf(o2, &len2, 0);
144     
145     if (buf1 && buf2 && len1 && len1 == len2 && !memcmp(buf1, buf2, len1))
146         match = 1;
147     else if (!buf1 && !buf2 && !len1 && !len2)
148         match = 1;
149     
150     odr_destroy(o1);
151     odr_destroy(o2);
152     if (!match)
153         return 0;
154     if (!syntax)
155         return 0;
156     // See if offset, OID match..
157     if (entry->m_offset == offset &&
158         entry->m_record->which == Z_NamePlusRecord_databaseRecord &&
159         !oid_oidcmp(entry->m_record->u.databaseRecord->direct_reference,
160                     syntax))
161         return 1;
162 #if 0
163     char mstr1[100];
164     oid_to_dotstring(entry->m_record->u.databaseRecord->direct_reference, mstr1);
165     char mstr2[100];
166     oid_to_dotstring(syntax, mstr2);
167     yaz_log(YLOG_LOG, "match fail 3 d=%s s=%s", mstr1, mstr2);
168 #endif
169
170     return 0;
171 }
172
173 int RecordCache::lookup (ODR o, Z_NamePlusRecordList **npr,
174                              int start, int num,
175                              Odr_oid *syntax,
176                              Z_RecordComposition *comp)
177 {
178     int i;
179     yaz_log(YLOG_DEBUG, "cache lookup start=%d num=%d", start, num);
180
181     for (i = 0; i<num; i++)
182     {
183         RecordCache_Entry *entry = m_entries;
184         for(; entry; entry = entry->m_next)
185             if (match(entry, syntax, start+i, comp))
186                 break;
187         if (!entry)
188             return 0;
189     }
190     *npr = (Z_NamePlusRecordList *) odr_malloc(o, sizeof(**npr));
191     (*npr)->num_records = num;
192     (*npr)->records = (Z_NamePlusRecord **)
193         odr_malloc(o, num * sizeof(Z_NamePlusRecord *));
194     for (i = 0; i<num; i++)
195     {
196         RecordCache_Entry *entry = m_entries;
197         for(; entry; entry = entry->m_next)
198             if (match(entry, syntax, start+i, comp))
199                 break;
200         if (!entry)
201             return 0;
202         (*npr)->records[i] = (Z_NamePlusRecord *)
203             odr_malloc(o, sizeof(Z_NamePlusRecord));
204         (*npr)->records[i]->databaseName = entry->m_record->databaseName;
205         (*npr)->records[i]->which = entry->m_record->which;
206         (*npr)->records[i]->u.databaseRecord =
207             entry->m_record->u.databaseRecord;
208     }
209     return 1;
210 }
211 /*
212  * Local variables:
213  * c-basic-offset: 4
214  * c-file-style: "Stroustrup"
215  * indent-tabs-mode: nil
216  * End:
217  * vim: shiftwidth=4 tabstop=8 expandtab
218  */
219