ZOOM: save record schema per request; fix caching
[yaz-moved-to-github.git] / src / zoom-record-cache.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 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 void ZOOM_record_cache_add(ZOOM_resultset r, Z_NamePlusRecord *npr,
60                            int pos,
61                            const char *syntax, const char *elementSetName,
62                            const char *schema,
63                            Z_SRW_diagnostic *diag)
64 {
65     ZOOM_record_cache rc = 0;
66
67     ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_RECV_RECORD);
68     ZOOM_connection_put_event(r->connection, event);
69
70     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
71     {
72         if (pos == rc->pos
73             && yaz_strcmp_null(schema, rc->schema) == 0
74             && yaz_strcmp_null(elementSetName,rc->elementSetName) == 0
75             && yaz_strcmp_null(syntax, rc->syntax) == 0)
76             break;
77     }
78     if (!rc)
79     {
80         rc = (ZOOM_record_cache) odr_malloc(r->odr, sizeof(*rc));
81         rc->rec.odr = 0;
82 #if SHPTR
83         YAZ_SHPTR_INC(r->record_wrbuf);
84         rc->rec.record_wrbuf = r->record_wrbuf;
85 #else
86         rc->rec.wrbuf = 0;
87 #endif
88         rc->elementSetName = odr_strdup_null(r->odr, elementSetName);
89
90         rc->syntax = odr_strdup_null(r->odr, syntax);
91
92         rc->schema = odr_strdup_null(r->odr, schema);
93
94         rc->pos = pos;
95         rc->next = r->record_hash[record_hash(pos)];
96         r->record_hash[record_hash(pos)] = rc;
97     }
98     rc->rec.npr = npr;
99     rc->rec.schema = odr_strdup_null(r->odr, schema);
100     rc->rec.diag_set = 0;
101     rc->rec.diag_uri = 0;
102     rc->rec.diag_message = 0;
103     rc->rec.diag_details = 0;
104     if (diag)
105     {
106         if (diag->uri)
107         {
108             char *cp;
109             rc->rec.diag_set = odr_strdup(r->odr, diag->uri);
110             if ((cp = strrchr(rc->rec.diag_set, '/')))
111                 *cp = '\0';
112             rc->rec.diag_uri = odr_strdup(r->odr, diag->uri);
113         }
114         rc->rec.diag_message = odr_strdup_null(r->odr, diag->message);
115         rc->rec.diag_details = odr_strdup_null(r->odr, diag->details);
116     }
117 }
118
119 ZOOM_record ZOOM_record_cache_lookup(ZOOM_resultset r, int pos,
120                                      const char *syntax,
121                                      const char *elementSetName,
122                                      const char *schema)
123 {
124     ZOOM_record_cache rc;
125
126     for (rc = r->record_hash[record_hash(pos)]; rc; rc = rc->next)
127     {
128         if (pos == rc->pos)
129         {
130             if (yaz_strcmp_null(schema, rc->schema))
131                 continue;
132             if (yaz_strcmp_null(elementSetName,rc->elementSetName))
133                 continue;
134             if (yaz_strcmp_null(syntax, rc->syntax))
135                 continue;
136             return &rc->rec;
137         }
138     }
139     return 0;
140 }
141
142 ZOOM_API(ZOOM_record)
143     ZOOM_record_clone(ZOOM_record srec)
144 {
145     char *buf;
146     int size;
147     ODR odr_enc;
148     ZOOM_record nrec;
149
150     odr_enc = odr_createmem(ODR_ENCODE);
151     if (!z_NamePlusRecord(odr_enc, &srec->npr, 0, 0))
152         return 0;
153     buf = odr_getbuf(odr_enc, &size, 0);
154
155     nrec = (ZOOM_record) xmalloc(sizeof(*nrec));
156     nrec->odr = odr_createmem(ODR_DECODE);
157 #if SHPTR
158     nrec->record_wrbuf = 0;
159 #else
160     nrec->wrbuf = 0;
161 #endif
162     odr_setbuf(nrec->odr, buf, size, 0);
163     z_NamePlusRecord(nrec->odr, &nrec->npr, 0, 0);
164
165     nrec->schema = odr_strdup_null(nrec->odr, srec->schema);
166     nrec->diag_uri = odr_strdup_null(nrec->odr, srec->diag_uri);
167     nrec->diag_message = odr_strdup_null(nrec->odr, srec->diag_message);
168     nrec->diag_details = odr_strdup_null(nrec->odr, srec->diag_details);
169     nrec->diag_set = odr_strdup_null(nrec->odr, srec->diag_set);
170     odr_destroy(odr_enc);
171     return nrec;
172 }
173
174 static void ZOOM_record_release(ZOOM_record rec)
175 {
176     if (!rec)
177         return;
178
179 #if SHPTR
180     if (rec->record_wrbuf)
181         YAZ_SHPTR_DEC(rec->record_wrbuf, wrbuf_destroy);
182 #else
183     if (rec->wrbuf)
184         wrbuf_destroy(rec->wrbuf);
185 #endif
186
187     if (rec->odr)
188         odr_destroy(rec->odr);
189 }
190
191 ZOOM_API(void)
192     ZOOM_resultset_cache_reset(ZOOM_resultset r)
193 {
194     int i;
195     for (i = 0; i<RECORD_HASH_SIZE; i++)
196     {
197         ZOOM_record_cache rc;
198         for (rc = r->record_hash[i]; rc; rc = rc->next)
199         {
200             ZOOM_record_release(&rc->rec);
201         }
202         r->record_hash[i] = 0;
203     }
204 }
205
206
207 ZOOM_API(const char *)
208     ZOOM_record_get(ZOOM_record rec, const char *type_spec, int *len)
209 {
210     WRBUF wrbuf;
211
212     if (len)
213         *len = 0; /* default return */
214
215     if (!rec || !rec->npr)
216         return 0;
217
218 #if SHPTR
219     if (!rec->record_wrbuf)
220     {
221         WRBUF w = wrbuf_alloc();
222         YAZ_SHPTR_INIT(rec->record_wrbuf, w);
223     }
224     wrbuf = rec->record_wrbuf->ptr;
225 #else
226     if (!rec->wrbuf)
227         rec->wrbuf = wrbuf_alloc();
228     wrbuf = rec->wrbuf;
229 #endif
230     return yaz_record_render(rec->npr, rec->schema, wrbuf, type_spec, len);
231 }
232
233 ZOOM_API(int)
234     ZOOM_record_error(ZOOM_record rec, const char **cp,
235                       const char **addinfo, const char **diagset)
236 {
237     Z_NamePlusRecord *npr;
238
239     if (!rec)
240         return 0;
241
242     npr = rec->npr;
243     if (rec->diag_uri)
244     {
245         if (cp)
246             *cp = rec->diag_message;
247         if (addinfo)
248             *addinfo = rec->diag_details;
249         if (diagset)
250             *diagset = rec->diag_set;
251         return ZOOM_uri_to_code(rec->diag_uri);
252     }
253     if (npr && npr->which == Z_NamePlusRecord_surrogateDiagnostic)
254     {
255         Z_DiagRec *diag_rec = npr->u.surrogateDiagnostic;
256         int error = YAZ_BIB1_UNSPECIFIED_ERROR;
257         const char *add = 0;
258
259         if (diag_rec->which == Z_DiagRec_defaultFormat)
260         {
261             Z_DefaultDiagFormat *ddf = diag_rec->u.defaultFormat;
262             oid_class oclass;
263
264             error = *ddf->condition;
265             switch (ddf->which)
266             {
267             case Z_DefaultDiagFormat_v2Addinfo:
268                 add = ddf->u.v2Addinfo;
269                 break;
270             case Z_DefaultDiagFormat_v3Addinfo:
271                 add = ddf->u.v3Addinfo;
272                 break;
273             }
274             if (diagset)
275                 *diagset =
276                     yaz_oid_to_string(yaz_oid_std(),
277                                       ddf->diagnosticSetId, &oclass);
278         }
279         else
280         {
281             if (diagset)
282                 *diagset = "Bib-1";
283         }
284         if (addinfo)
285             *addinfo = add ? add : "";
286         if (cp)
287             *cp = diagbib1_str(error);
288         return error;
289     }
290     return 0;
291 }
292
293 ZOOM_API(void)
294     ZOOM_record_destroy(ZOOM_record rec)
295 {
296     ZOOM_record_release(rec);
297     xfree(rec);
298 }
299
300 /*
301  * Local variables:
302  * c-basic-offset: 4
303  * c-file-style: "Stroustrup"
304  * indent-tabs-mode: nil
305  * End:
306  * vim: shiftwidth=4 tabstop=8 expandtab
307  */
308