Enable memcahced binary protocol
[yaz-moved-to-github.git] / src / zoom-record-cache.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file zoom-record-cache.c
7  * \brief Implements ZOOM record caching
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <assert.h>
14 #include <string.h>
15 #include <errno.h>
16 #include "zoom-p.h"
17
18 #include <yaz/diagbib1.h>
19 #include <yaz/record_render.h>
20 #include <yaz/shptr.h>
21
22 #if SHPTR
23 YAZ_SHPTR_TYPE(WRBUF)
24 #endif
25
26 struct ZOOM_record_p {
27     ODR odr;
28 #if SHPTR
29     struct WRBUF_shptr *record_wrbuf;
30 #else
31     WRBUF wrbuf;
32 #endif
33
34     Z_NamePlusRecord *npr;
35     const char *schema;
36
37     const char *diag_uri;
38     const char *diag_message;
39     const char *diag_details;
40     const char *diag_set;
41 };
42
43 struct ZOOM_record_cache_p {
44     struct ZOOM_record_p rec;
45     char *elementSetName;
46     char *syntax;
47     char *schema;
48     int pos;
49     ZOOM_record_cache next;
50 };
51
52 static size_t record_hash(int pos)
53 {
54     if (pos < 0)
55         pos = 0;
56     return pos % RECORD_HASH_SIZE;
57 }
58
59 static ZOOM_record record_cache_add(ZOOM_resultset r,
60                                     Z_NamePlusRecord *npr,
61                                     int pos,
62                                     const char *syntax,
63                                     const char *elementSetName,
64                                     const char *schema,
65                                     Z_SRW_diagnostic *diag)
66 {
67     ZOOM_record_cache rc = 0;
68
69     ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
70     ZOOM_connection_put_event(r->connection, event);
71
72     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
73     {
74         if (pos == rc->pos
75             && yaz_strcmp_null(schema, rc->schema) == 0
76             && yaz_strcmp_null(elementSetName,rc->elementSetName) == 0
77             && yaz_strcmp_null(syntax, rc->syntax) == 0)
78             break;
79     }
80     if (!rc)
81     {
82         rc = (ZOOM_record_cache) odr_malloc(r->odr, sizeof(*rc));
83         rc->rec.odr = 0;
84 #if SHPTR
85         YAZ_SHPTR_INC(r->record_wrbuf);
86         rc->rec.record_wrbuf = r->record_wrbuf;
87 #else
88         rc->rec.wrbuf = 0;
89 #endif
90         rc->elementSetName = odr_strdup_null(r->odr, elementSetName);
91
92         rc->syntax = odr_strdup_null(r->odr, syntax);
93
94         rc->schema = odr_strdup_null(r->odr, schema);
95
96         rc->pos = pos;
97         rc->next = r->record_hash[record_hash(pos)];
98         r->record_hash[record_hash(pos)] = rc;
99
100     }
101
102     rc->rec.npr = npr;
103     rc->rec.schema = odr_strdup_null(r->odr, schema);
104     rc->rec.diag_set = 0;
105     rc->rec.diag_uri = 0;
106     rc->rec.diag_message = 0;
107     rc->rec.diag_details = 0;
108     if (diag)
109     {
110         if (diag->uri)
111         {
112             char *cp;
113             rc->rec.diag_set = odr_strdup(r->odr, diag->uri);
114             if ((cp = strrchr(rc->rec.diag_set, '/')))
115                 *cp = '\0';
116             rc->rec.diag_uri = odr_strdup(r->odr, diag->uri);
117         }
118         rc->rec.diag_message = odr_strdup_null(r->odr, diag->message);
119         rc->rec.diag_details = odr_strdup_null(r->odr, diag->details);
120     }
121     return &rc->rec;
122 }
123
124 void ZOOM_record_cache_add(ZOOM_resultset r, Z_NamePlusRecord *npr,
125                            int pos,
126                            const char *syntax, const char *elementSetName,
127                            const char *schema,
128                            Z_SRW_diagnostic *diag)
129 {
130     record_cache_add(r, npr, pos, syntax, elementSetName, schema, diag);
131     ZOOM_memcached_add(r, npr, pos, syntax, elementSetName, schema, diag);
132 }
133
134 ZOOM_record ZOOM_record_cache_lookup(ZOOM_resultset r, int pos,
135                                      const char *syntax,
136                                      const char *elementSetName,
137                                      const char *schema)
138 {
139     ZOOM_record_cache rc;
140     Z_NamePlusRecord *npr;
141
142     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
143     {
144         if (pos == rc->pos)
145         {
146             if (yaz_strcmp_null(schema, rc->schema))
147                 continue;
148             if (yaz_strcmp_null(elementSetName,rc->elementSetName))
149                 continue;
150             if (yaz_strcmp_null(syntax, rc->syntax))
151                 continue;
152             return &rc->rec;
153         }
154     }
155     npr = ZOOM_memcached_lookup(r, pos, syntax, elementSetName, schema);
156     if (npr)
157         return record_cache_add(r, npr, pos, syntax, elementSetName,
158                                 schema, 0);
159     return 0;
160 }
161
162 ZOOM_API(ZOOM_record)
163     ZOOM_record_clone(ZOOM_record srec)
164 {
165     char *buf;
166     int size;
167     ODR odr_enc;
168     ZOOM_record nrec;
169
170     odr_enc = odr_createmem(ODR_ENCODE);
171     if (!z_NamePlusRecord(odr_enc, &srec->npr, 0, 0))
172         return 0;
173     buf = odr_getbuf(odr_enc, &size, 0);
174
175     nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
176     nrec->odr = odr_createmem(ODR_DECODE);
177 #if SHPTR
178     nrec->record_wrbuf = 0;
179 #else
180     nrec->wrbuf = 0;
181 #endif
182     odr_setbuf(nrec->odr, buf, size, 0);
183     z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
184
185     nrec->schema = odr_strdup_null(nrec->odr, srec->schema);
186     nrec->diag_uri = odr_strdup_null(nrec->odr, srec->diag_uri);
187     nrec->diag_message = odr_strdup_null(nrec->odr, srec->diag_message);
188     nrec->diag_details = odr_strdup_null(nrec->odr, srec->diag_details);
189     nrec->diag_set = odr_strdup_null(nrec->odr, srec->diag_set);
190     odr_destroy(odr_enc);
191     return nrec;
192 }
193
194 static void ZOOM_record_release(ZOOM_record rec)
195 {
196     if (!rec)
197         return;
198
199 #if SHPTR
200     if (rec->record_wrbuf)
201         YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
202 #else
203     if (rec->wrbuf)
204         wrbuf_destroy(rec->wrbuf);
205 #endif
206
207     if (rec->odr)
208         odr_destroy(rec->odr);
209 }
210
211 ZOOM_API(void)
212     ZOOM_resultset_cache_reset(ZOOM_resultset r)
213 {
214     int i;
215     for (i = 0; i<RECORD_HASH_SIZE; i++)
216     {
217         ZOOM_record_cache rc;
218         for (rc = r->record_hash[i]; rc; rc = rc->next)
219         {
220             ZOOM_record_release(&rc->rec);
221         }
222         r->record_hash[i] = 0;
223     }
224 }
225
226
227 ZOOM_API(const char *)
228     ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
229 {
230     WRBUF wrbuf;
231
232     if (len)
233         *len = 0; /* default return */
234
235     if (!rec || !rec->npr)
236         return 0;
237
238 #if SHPTR
239     if (!rec->record_wrbuf)
240     {
241         WRBUF w = wrbuf_alloc();
242         YAZ_SHPTR_INIT(rec->record_wrbuf, w);
243     }
244     wrbuf = rec->record_wrbuf->ptr;
245 #else
246     if (!rec->wrbuf)
247         rec->wrbuf = wrbuf_alloc();
248     wrbuf = rec->wrbuf;
249 #endif
250     return yaz_record_render(rec->npr, rec->schema, wrbuf, type_spec, len);
251 }
252
253 ZOOM_API(int)
254     ZOOM_record_error(ZOOM_record rec, const char **cp,
255                       const char **addinfo, const char **diagset)
256 {
257     Z_NamePlusRecord *npr;
258
259     if (!rec)
260         return 0;
261
262     npr = rec->npr;
263     if (rec->diag_uri)
264     {
265         if (cp)
266             *cp = rec->diag_message;
267         if (addinfo)
268             *addinfo = rec->diag_details;
269         if (diagset)
270             *diagset = rec->diag_set;
271         return ZOOM_uri_to_code(rec->diag_uri);
272     }
273     if (npr && npr->which == Z_NamePlusRecord_surrogateDiagnostic)
274     {
275         Z_DiagRec *diag_rec = npr->u.surrogateDiagnostic;
276         int error = YAZ_BIB1_UNSPECIFIED_ERROR;
277         const char *add = 0;
278
279         if (diag_rec->which == Z_DiagRec_defaultFormat)
280         {
281             Z_DefaultDiagFormat *ddf = diag_rec->u.defaultFormat;
282             oid_class oclass;
283
284             error = *ddf->condition;
285             switch (ddf->which)
286             {
287             case Z_DefaultDiagFormat_v2Addinfo:
288                 add = ddf->u.v2Addinfo;
289                 break;
290             case Z_DefaultDiagFormat_v3Addinfo:
291                 add = ddf->u.v3Addinfo;
292                 break;
293             }
294             if (diagset)
295                 *diagset =
296                     yaz_oid_to_string(yaz_oid_std(),
297                                       ddf->diagnosticSetId, &oclass);
298         }
299         else
300         {
301             if (diagset)
302                 *diagset = "Bib-1";
303         }
304         if (addinfo)
305             *addinfo = add ? add : "";
306         if (cp)
307             *cp = diagbib1_str(error);
308         return error;
309     }
310     return 0;
311 }
312
313 ZOOM_API(void)
314     ZOOM_record_destroy(ZOOM_record rec)
315 {
316     ZOOM_record_release(rec);
317     xfree(rec);
318 }
319
320 /*
321  * Local variables:
322  * c-basic-offset: 4
323  * c-file-style: "Stroustrup"
324  * indent-tabs-mode: nil
325  * End:
326  * vim: shiftwidth=4 tabstop=8 expandtab
327  */
328