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