8446bd533a8b4c144d685415dacc7d33d0ae64a7
[yazpp-moved-to-github.git] / src / yaz-z-cache.cpp
1 /* This file is part of the yazpp toolkit.
2  * Copyright (C) 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 void RecordCache::add(ODR o, Z_NamePlusRecordList *npr, int start,
104                       Z_RecordComposition *comp)
105 {
106     if (nmem_total(m_p->nmem) > m_p->max_size)
107         return;
108     // Insert individual records in cache
109     int i;
110     for (i = 0; i < npr->num_records; i++)
111     {
112         RecordCache_Entry *entry = (RecordCache_Entry *)
113             nmem_malloc(m_p->nmem, sizeof(*entry));
114         entry->m_record =
115             yaz_clone_z_NamePlusRecord(npr->records[i], m_p->nmem);
116         entry->m_comp = yaz_clone_z_RecordComposition(comp, m_p->nmem);
117         entry->m_offset = i + start;
118         entry->m_next = m_p->entries;
119         m_p->entries = entry;
120     }
121 }
122
123 void RecordCache::add(ODR o, Z_NamePlusRecordList *npr, int start,
124                       int hits)
125 {
126     // Build appropriate compspec for this response
127     Z_RecordComposition *comp = 0;
128     if (hits == -1 && m_p->presentRequest)
129         comp = m_p->presentRequest->recordComposition;
130     else if (hits > 0 && m_p->searchRequest)
131     {
132         Z_ElementSetNames *esn;
133
134         if (hits <= *m_p->searchRequest->smallSetUpperBound)
135             esn = m_p->searchRequest->smallSetElementSetNames;
136         else
137             esn = m_p->searchRequest->mediumSetElementSetNames;
138         comp = (Z_RecordComposition *) nmem_malloc(m_p->nmem, sizeof(*comp));
139         comp->which = Z_RecordComp_simple;
140         comp->u.simple = esn;
141     }
142     add(o, npr, start, comp);
143 }
144
145 int RecordCache::Rep::match(RecordCache_Entry *entry,
146                             Odr_oid *syntax, int offset,
147                             Z_RecordComposition *comp)
148 {
149     // See if our compspec match...
150     int match = 0;
151     ODR o1 = odr_createmem(ODR_ENCODE);
152     ODR o2 = odr_createmem(ODR_ENCODE);
153
154     z_RecordComposition(o1, &comp, 1, 0);
155     z_RecordComposition(o2, &entry->m_comp, 1, 0);
156
157     int len1 = -1;
158     char *buf1 = odr_getbuf(o1, &len1, 0);
159     int len2 = -1;
160     char *buf2 = odr_getbuf(o2, &len2, 0);
161
162     if (buf1 && buf2 && len1 && len1 == len2 && !memcmp(buf1, buf2, len1))
163         match = 1;
164     else if (!buf1 && !buf2 && !len1 && !len2)
165         match = 1;
166
167     odr_destroy(o1);
168     odr_destroy(o2);
169     if (!match)
170         return 0;
171     if (!syntax)
172         return 0;
173     // See if offset, OID match..
174     if (entry->m_offset == offset &&
175         entry->m_record->which == Z_NamePlusRecord_databaseRecord &&
176         !oid_oidcmp(entry->m_record->u.databaseRecord->direct_reference,
177                     syntax))
178         return 1;
179 #if 0
180     char mstr1[100];
181     oid_to_dotstring(entry->m_record->u.databaseRecord->direct_reference, mstr1);
182     char mstr2[100];
183     oid_to_dotstring(syntax, mstr2);
184     yaz_log(YLOG_LOG, "match fail 3 d=%s s=%s", mstr1, mstr2);
185 #endif
186
187     return 0;
188 }
189
190 int RecordCache::lookup(ODR o, Z_NamePlusRecordList **npr,
191                         int start, int num,
192                         Odr_oid *syntax,
193                         Z_RecordComposition *comp)
194 {
195     int i;
196     yaz_log(YLOG_DEBUG, "cache lookup start=%d num=%d", start, num);
197
198     for (i = 0; i<num; i++)
199     {
200         RecordCache_Entry *entry = m_p->entries;
201         for(; entry; entry = entry->m_next)
202             if (m_p->match(entry, syntax, start+i, comp))
203                 break;
204         if (!entry)
205             return 0;
206     }
207     *npr = (Z_NamePlusRecordList *) odr_malloc(o, sizeof(**npr));
208     (*npr)->num_records = num;
209     (*npr)->records = (Z_NamePlusRecord **)
210         odr_malloc(o, num * sizeof(Z_NamePlusRecord *));
211     for (i = 0; i<num; i++)
212     {
213         RecordCache_Entry *entry = m_p->entries;
214         for(; entry; entry = entry->m_next)
215             if (m_p->match(entry, syntax, start+i, comp))
216                 break;
217         if (!entry)
218             return 0;
219         (*npr)->records[i] = (Z_NamePlusRecord *)
220             odr_malloc(o, sizeof(Z_NamePlusRecord));
221         (*npr)->records[i]->databaseName = entry->m_record->databaseName;
222         (*npr)->records[i]->which = entry->m_record->which;
223         (*npr)->records[i]->u.databaseRecord =
224             entry->m_record->u.databaseRecord;
225     }
226     return 1;
227 }
228 /*
229  * Local variables:
230  * c-basic-offset: 4
231  * c-file-style: "Stroustrup"
232  * indent-tabs-mode: nil
233  * End:
234  * vim: shiftwidth=4 tabstop=8 expandtab
235  */
236