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