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