Merge branch 'master' into yaz-744
[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_i(ZOOM_resultset r, int pos,
135                                        const char *syntax,
136                                        const char *elementSetName,
137                                        const char *schema)
138 {
139     ZOOM_record_cache rc;
140
141     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
142     {
143         if (pos == rc->pos)
144         {
145             if (yaz_strcmp_null(schema, rc->schema))
146                 continue;
147             if (yaz_strcmp_null(elementSetName,rc->elementSetName))
148                 continue;
149             if (yaz_strcmp_null(syntax, rc->syntax))
150                 continue;
151             return &rc->rec;
152         }
153     }
154     return 0;
155 }
156
157 ZOOM_record ZOOM_record_cache_lookup(ZOOM_resultset r, int pos,
158                                      const char *syntax,
159                                      const char *elementSetName,
160                                      const char *schema)
161 {
162     Z_NamePlusRecord *npr;
163     ZOOM_record rec = ZOOM_record_cache_lookup_i(r, pos, syntax,
164                                                  elementSetName, schema);
165     if (rec)
166     {
167         ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
168         ZOOM_connection_put_event(r->connection, event);
169         return rec;
170     }
171     npr = ZOOM_memcached_lookup(r, pos, syntax, elementSetName, schema);
172     if (npr)
173         return record_cache_add(r, npr, pos, syntax, elementSetName,
174                                 schema, 0);
175     return 0;
176 }
177
178 ZOOM_API(ZOOM_record)
179     ZOOM_record_clone(ZOOM_record srec)
180 {
181     char *buf;
182     int size;
183     ODR odr_enc;
184     ZOOM_record nrec;
185
186     odr_enc = odr_createmem(ODR_ENCODE);
187     if (!z_NamePlusRecord(odr_enc, &srec->npr, 0, 0))
188         return 0;
189     buf = odr_getbuf(odr_enc, &size, 0);
190
191     nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
192     nrec->odr = odr_createmem(ODR_DECODE);
193 #if SHPTR
194     nrec->record_wrbuf = 0;
195 #else
196     nrec->wrbuf = 0;
197 #endif
198     odr_setbuf(nrec->odr, buf, size, 0);
199     z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
200
201     nrec->schema = odr_strdup_null(nrec->odr, srec->schema);
202     nrec->diag_uri = odr_strdup_null(nrec->odr, srec->diag_uri);
203     nrec->diag_message = odr_strdup_null(nrec->odr, srec->diag_message);
204     nrec->diag_details = odr_strdup_null(nrec->odr, srec->diag_details);
205     nrec->diag_set = odr_strdup_null(nrec->odr, srec->diag_set);
206     odr_destroy(odr_enc);
207     return nrec;
208 }
209
210 static void ZOOM_record_release(ZOOM_record rec)
211 {
212     if (!rec)
213         return;
214
215 #if SHPTR
216     if (rec->record_wrbuf)
217         YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
218 #else
219     if (rec->wrbuf)
220         wrbuf_destroy(rec->wrbuf);
221 #endif
222
223     if (rec->odr)
224         odr_destroy(rec->odr);
225 }
226
227 ZOOM_API(void)
228     ZOOM_resultset_cache_reset(ZOOM_resultset r)
229 {
230     int i;
231     for (i = 0; i<RECORD_HASH_SIZE; i++)
232     {
233         ZOOM_record_cache rc;
234         for (rc = r->record_hash[i]; rc; rc = rc->next)
235         {
236             ZOOM_record_release(&rc->rec);
237         }
238         r->record_hash[i] = 0;
239     }
240 }
241
242
243 ZOOM_API(const char *)
244     ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
245 {
246     WRBUF wrbuf;
247
248     if (len)
249         *len = 0; /* default return */
250
251     if (!rec || !rec->npr)
252         return 0;
253
254 #if SHPTR
255     if (!rec->record_wrbuf)
256     {
257         WRBUF w = wrbuf_alloc();
258         YAZ_SHPTR_INIT(rec->record_wrbuf, w);
259     }
260     wrbuf = rec->record_wrbuf->ptr;
261 #else
262     if (!rec->wrbuf)
263         rec->wrbuf = wrbuf_alloc();
264     wrbuf = rec->wrbuf;
265 #endif
266     return yaz_record_render(rec->npr, rec->schema, wrbuf, type_spec, len);
267 }
268
269 ZOOM_API(int)
270     ZOOM_record_error(ZOOM_record rec, const char **cp,
271                       const char **addinfo, const char **diagset)
272 {
273     Z_NamePlusRecord *npr;
274
275     if (!rec)
276         return 0;
277
278     npr = rec->npr;
279     if (rec->diag_uri)
280     {
281         if (cp)
282             *cp = rec->diag_message;
283         if (addinfo)
284             *addinfo = rec->diag_details;
285         if (diagset)
286             *diagset = rec->diag_set;
287         return ZOOM_uri_to_code(rec->diag_uri);
288     }
289     if (npr && npr->which == Z_NamePlusRecord_surrogateDiagnostic)
290     {
291         Z_DiagRec *diag_rec = npr->u.surrogateDiagnostic;
292         int error = YAZ_BIB1_UNSPECIFIED_ERROR;
293         const char *add = 0;
294
295         if (diag_rec->which == Z_DiagRec_defaultFormat)
296         {
297             Z_DefaultDiagFormat *ddf = diag_rec->u.defaultFormat;
298             oid_class oclass;
299
300             error = *ddf->condition;
301             switch (ddf->which)
302             {
303             case Z_DefaultDiagFormat_v2Addinfo:
304                 add = ddf->u.v2Addinfo;
305                 break;
306             case Z_DefaultDiagFormat_v3Addinfo:
307                 add = ddf->u.v3Addinfo;
308                 break;
309             }
310             if (diagset)
311                 *diagset =
312                     yaz_oid_to_string(yaz_oid_std(),
313                                       ddf->diagnosticSetId, &oclass);
314         }
315         else
316         {
317             if (diagset)
318                 *diagset = "Bib-1";
319         }
320         if (addinfo)
321             *addinfo = add ? add : "";
322         if (cp)
323             *cp = diagbib1_str(error);
324         return error;
325     }
326     return 0;
327 }
328
329 ZOOM_API(void)
330     ZOOM_record_destroy(ZOOM_record rec)
331 {
332     ZOOM_record_release(rec);
333     xfree(rec);
334 }
335
336 /*
337  * Local variables:
338  * c-basic-offset: 4
339  * c-file-style: "Stroustrup"
340  * indent-tabs-mode: nil
341  * End:
342  * vim: shiftwidth=4 tabstop=8 expandtab
343  */
344