1 /*
2 ##############################################################################
3 # Copyright (c) 2000-2006 All rights reserved
4 # Alberto Reggiori <areggiori@webweaving.org>
5 # Dirk-Willem van Gulik <dirkx@webweaving.org>
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in
16 # the documentation and/or other materials provided with the
17 # distribution.
18 #
19 # 3. The end-user documentation included with the redistribution,
20 # if any, must include the following acknowledgment:
21 # "This product includes software developed by
22 # Alberto Reggiori <areggiori@webweaving.org> and
23 # Dirk-Willem van Gulik <dirkx@webweaving.org>."
24 # Alternately, this acknowledgment may appear in the software itself,
25 # if and wherever such third-party acknowledgments normally appear.
26 #
27 # 4. All advertising materials mentioning features or use of this software
28 # must display the following acknowledgement:
29 # This product includes software developed by the University of
30 # California, Berkeley and its contributors.
31 #
32 # 5. Neither the name of the University nor the names of its contributors
33 # may be used to endorse or promote products derived from this software
34 # without specific prior written permission.
35 #
36 # 6. Products derived from this software may not be called "RDFStore"
37 # nor may "RDFStore" appear in their names without prior written
38 # permission.
39 #
40 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 # ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 # FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 # OF THE POSSIBILITY OF SUCH DAMAGE.
52 #
53 # ====================================================================
54 #
55 # This software consists of work developed by Alberto Reggiori and
56 # Dirk-Willem van Gulik. The RDF specific part is based based on public
57 # domain software written at the Stanford University Database Group by
58 # Sergey Melnik. For more information on the RDF API Draft work,
59 # please see <http://www-db.stanford.edu/~melnik/rdf/api.html>
60 # The DBMS TCP/IP server part is based on software originally written
61 # by Dirk-Willem van Gulik for Web Weaving Internet Engineering m/v Enschede,
62 # The Netherlands.
63 #
64 ##############################################################################
65 #
66 # $Id: backend_caching_store.c,v 1.13 2006/06/19 10:10:21 areggiori Exp $
67 */
68 #include "dbms.h"
69 #include "dbms_compat.h"
70 #include "dbms_comms.h"
71
72 #include "rdfstore_flat_store.h"
73 #include "rdfstore_log.h"
74 #include "rdfstore.h"
75
76 #include "backend_store.h"
77 #include "backend_caching_store.h"
78
79 #include "backend_bdb_store.h"
80 #include "backend_dbms_store.h"
81
82 #include <stdlib.h>
83 #include <stdio.h>
84 #include <string.h>
85 #include <assert.h>
86
87 typedef struct backend_caching_struct {
88 char * name; /* name - for debugging */
89 backend_store_t * store; /* the real store */
90 void * instance; /* instance of the real store */
91 struct caching_store_rec * cache; /* My cache */
92
93 void (* free)(void * adr);
94 void * (* malloc)(size_t size);
95 } backend_caching_t;
96
97 typedef enum { UNDEF, EXISTS, CHANGED, NOTFOUND, DELETED } cstate;
98
99 /* as refered to above as * data */
100 typedef struct data_rec { /* Payload of the cache */
101 DBT key,val;
102 cstate state; /* Cache positives and negatives */
103 } data_t;
104
105 /* forward declarations */
106 static int _dup(void * conf, void * from, void * * to);
107 static int _store(void * conf, void * data);
108 static int _delete(void * conf, void * data);
109 static int _fetch(void * conf, void * data, void ** dout);
110 static int _cmp(const void *a, const void *b);
111
112
113 /* Caching infrastructure:
114 *
115 * Up to maxcache keys are cached.
116 *
117 * --> head->*cdll_t
118 * circular double linked list - element pointed to by head
119 * was the most recently used.
120 * --> idx
121 * sorted list circular double linked list elements - sorted
122 * by their 'data's key.
123 */
124
125 /* START of Fairly generic caching section.. */
126
127 #ifndef DEFAULTMAXCACHE
128 #define DEFAULTMAXCACHE (1000)
129 #endif
130
131 /* Element in a circular double linked list */
132 typedef struct cdll_rec {
133 void * data; /* data payload -- actual stuff we cache */
134
135 unsigned int cnt; /* counter - for debugging */
136
137 struct cdll_rec * prev;
138 struct cdll_rec * nxt;
139 } cdll_t;
140
141 typedef struct caching_store_rec {
142 char * name; /* name - for debugging */
143 void * conf; /* Callee's own book keeping */
144
145 int hit,miss,drop;
146
147 unsigned int maxcache; /* Max numer of keys to cache. */
148 unsigned int cached; /* Currently cached */
149 cdll_t * * idx; /* Sorted list (on keys) */
150
151 struct cdll_rec * head; /* Start of the circular double linked list. */
152
153 void (* free)(void * adr);
154 void * (* malloc)(size_t size);
155
156 /* Comparison functions specific to the data
157 */
158 int (*cmp)(const void * a, const void * b);
159
160 /* fetch/store functions specific to the data
161 */
162 int (*fetch)(void * conf, void * data, void ** out); /* implies dup into new out */
163 int (*store)(void * conf, void * data);
164 int (*delete)(void * conf, void * data);
165
166 /* Create a copy into existence, or drop it. */
167 int (*dup)(void * conf, void * from, void * * to); /* malloc and cpy */
168 int (*cpy)(void * conf, void * from, void * to); /* just copy refs */
169 int (*drp)(backend_caching_t * me, void * conf, void * data);
170
171 } caching_store_t;
172
173 typedef enum { BC_READ, BC_WRITE, BC_EXISTS, BC_DELETE } bc_ops;
174
175 static int cmp_pair(const void * a, const void * b);
176 static int cmp_key(const void * in, const void * pair);
177
init_cachingstore(caching_store_t * me,int max_cache_nelems,void * conf,char * name,int (* cmp)(const void * a,const void * b),int (* fetch)(void * conf,void * data,void ** out),int (* store)(void * conf,void * data),int (* delete)(void * conf,void * data),int (* dup)(void * conf,void * from,void ** to),int (* cpy)(void * conf,void * from,void * to),int (* drp)(backend_caching_t * me,void * conf,void * data),void (* cachingfree)(void * adr),void * (* cachingmalloc)(size_t size))178 static int init_cachingstore(
179 caching_store_t *me,
180 int max_cache_nelems,
181 void * conf,
182 char * name,
183 int (*cmp)(const void * a, const void * b),
184 int (*fetch)(void * conf, void * data, void ** out),
185 int (*store)(void * conf, void * data),
186 int (*delete)(void * conf, void * data),
187 int (*dup)(void * conf, void * from, void * * to),
188 int (*cpy)(void * conf, void * from, void * to),
189 int (*drp)(backend_caching_t * me, void * conf, void * data),
190 void (* cachingfree)(void * adr),
191 void * (* cachingmalloc)(size_t size)
192 )
193 {
194 me->maxcache = max_cache_nelems ? max_cache_nelems : DEFAULTMAXCACHE;
195
196 me->idx = (cdll_t **) (*cachingmalloc)( sizeof((*(me->idx))) * me->maxcache );
197 if (me->idx == NULL)
198 return -1;
199
200 memset(me->idx, 0, sizeof((*(me->idx))) * me->maxcache );
201
202 me->cached = 0;
203 me->head = NULL;
204
205 me->hit = me->miss = me->drop = 0;
206
207 me->cmp = cmp;
208 me->fetch = fetch;
209 me->store = store;
210 me->delete = delete;
211 me->dup = dup;
212 me->cpy = cpy;
213 me->drp = drp;
214 me->name = (char *)(*cachingmalloc)( strlen(name)+1 );
215 if( me->name == NULL )
216 return -1;
217 strcpy( me->name, name );
218 me->conf = conf;
219
220 me->free = cachingfree;
221 me->malloc = cachingmalloc;
222
223 return 0;
224 }
225
226 /* iswrite == 1
227 * cache key+val
228 * iswrite == 0
229 * if cached - update val
230 * otherwise fetch from backend
231 * and cache - update val
232 */
233
_x(DBT v)234 const char * _x(DBT v) {
235 int i;
236 if (v.size == 4) return "<int>";
237 for(i=0;i<v.size;i++)
238 if ((((char *)(v.data))[i]) && (((((char *)(v.data))[i])< 32) || ( ((((char *)(v.data))[i])>126))))
239 return "<bin>";
240 return (char *)(v.data);
241 }
242
cachekey(backend_caching_t * mme,caching_store_t * me,void * data,void ** out,bc_ops op)243 int cachekey(backend_caching_t * mme, caching_store_t * me, void * data, void ** out, bc_ops op)
244 {
245 cdll_t * * i = NULL;
246 int e = 0;
247
248 #if 0
249 if(0)fprintf(stderr,"Working on %s[%d,%d]\n",_x(((data_t *)data)->key),((data_t *)data)->key.size,((data_t *)data)->val.size);
250 #endif
251 /* Check if this key is already cached */
252 if (me->cached > 0)
253 i = (cdll_t **)bsearch( (void *) data, me->idx, me->cached, sizeof(cdll_t *), &cmp_key);
254 #if 0
255 if (0) { int i; fprintf(stderr," PRE --- %d\n",me->cached); for(i=0;i < me->cached;i++) { data_t * p = (data_t *)(me->idx[i]->data); fprintf(stderr," # %d %p %p '%s'[%d] %d\n",i,me->idx[i],p,p->key.data,p->key.size,p->state); }; fprintf(stderr,"--- end\n"); };
256 #endif
257
258 /* Add this to the cache if it is a new key */
259 if (!i) {
260 /* Remove last key if cache is already full. */
261 #if 0
262 fprintf(stderr,"Cache miss\n");
263 #endif
264 me->miss++;
265 if (me->cached >= me->maxcache) {
266 /* Remove from the tail */
267 cdll_t * last = me->head->prev;
268 me->head = last->nxt;
269 me->head->prev = last->prev;
270 me->head->prev->nxt = me->head;
271
272 /* find the corresponding entry in the idx - as this is the slot which we will
273 * reuse (to save a malloc) for the new key.
274 */
275 i = (cdll_t **)bsearch((void *)(last->data), me->idx, me->cached, sizeof(cdll_t *), &cmp_key);
276 assert(i);
277
278 /* allow the backend to store and drop it */
279 me->store(me->conf,last->data);
280 me->drp(mme, me->conf,last->data);
281 me->drop++;
282 } else {
283 /* Still space - add it to the end of the IDX */
284 if ((me->idx[ me->cached ] = me->malloc(sizeof(cdll_t))) == NULL) {
285 return -1;
286 };
287 i = &(me->idx[ me->cached ]);
288 me->cached ++;
289 };
290
291 switch(op) {
292 case BC_WRITE: /* DUP our new item into it */
293 me->dup(me->conf, data, &((*i)->data));
294 break;
295 case BC_DELETE:
296 me->dup(me->conf, data, &((*i)->data));
297 e = me->delete(me->conf, (*i)->data);
298 break;
299 case BC_READ:
300 case BC_EXISTS:
301 e = me->fetch(me->conf, data, &((*i)->data));
302 break;
303 default:
304 assert(0);
305 break;
306 };
307
308 /* virig item. */
309 (*i)->cnt = 0;
310
311 /* And insert our item at the head */
312 if( me->head ) {
313 (*i)->nxt = me->head;
314 (*i)->prev = me->head->prev;
315 me->head->prev->nxt = *i;
316 me->head->prev = *i;
317 } else {
318 (*i)->nxt = *i;
319 (*i)->prev= *i;
320 }
321 /* And update the head pointer */
322 me->head = *i;
323
324 /* and sort the list again -- XXXX note this should be replaced
325 * by a binary search and a N-shift/insert (ordered insertion search)
326 * at some point.
327 */
328 if (me->cached > 1)
329 qsort(me->idx,me->cached,sizeof(cdll_t*),&cmp_pair);
330 } else {
331 #if 0
332 fprintf(stderr,"Cache hit\n");
333 #endif
334 me->hit++;
335 /* if not already in front - move to the front
336 */
337 if (me->head && (me->head != *i)) {
338 /* remove item from the list */
339 (*i)->nxt->prev = (*i)->prev;
340 (*i)->prev->nxt = (*i)->nxt;
341
342 /* squeeze it in at head */
343 (*i)->nxt = me->head;
344 (*i)->prev = me->head->prev;
345 me->head->prev->nxt = *i;
346 me->head->prev = *i;
347
348 /* move head to the right place */
349 me->head = *i;
350 }
351 /* If it is a write through - update the value if it has changed.
352 */
353 switch(op) {
354 case BC_WRITE:
355 if (0) fprintf(stderr,"Write through\n");
356 if (0) if (((data_t *)data)->val.size == 4) fprintf(stderr,"%s == %d\n",_x(((data_t *)data)->key),*((int *)(((data_t *)data)->val.data)));
357
358 me->drp(mme, me->conf, (*i)->data); /* drop the old value */
359 me->dup(me->conf, data, &((*i)->data)); /* replace by the new one */
360 break;
361 case BC_DELETE:
362 me->dup(me->conf, data, &((*i)->data));
363 e = me->delete(me->conf, (*i)->data);
364 break;
365 case BC_EXISTS:
366 case BC_READ:
367 break;
368 default:
369 assert(0);
370 }
371 (*i)->cnt ++;
372 }
373
374 switch(op) {
375 case BC_EXISTS: /* exists */
376 me->cpy(me->conf,me->head->data,data);
377 break;
378 case BC_DELETE: /* no need to update */
379 case BC_WRITE: /* no need to update */
380 break;
381 case BC_READ: /* update data - so the callee can use it */
382 me->dup(me->conf,me->head->data,out);
383 break;
384 default:
385 /* error really */
386 assert(0);
387 break;
388 }
389 #if 0
390 if (0) { int i; fprintf(stderr,"POST --- %d\n",me->cached); for(i=0;i < me->cached;i++) { data_t * p = (data_t *)(me->idx[i]->data); fprintf(stderr," %d '%s'[%d] %d\n",i,p->key.data,p->key.size,p->state); }; fprintf(stderr,"--- end\n"); };
391 #endif
392 return e;
393 }
394
stats(caching_store_t * me)395 void stats(caching_store_t *me)
396 {
397 fprintf(stderr,"%s: hit: %d miss: %d drop: %d\n",me->name,me->hit,me->miss,me->drop);
398 }
399
purgecache(backend_caching_t * me,caching_store_t * c)400 void purgecache(backend_caching_t *me, caching_store_t *c)
401 {
402 cdll_t * p;
403 if (c->head == NULL)
404 return;
405
406 for(p=c->head;;) {
407 cdll_t * q = p;
408 p=p->nxt;
409 c->store(c->conf,q->data);
410 c->drp(me, c->conf,q->data);
411 (*(me->free))(q);
412 if (p == c->head)
413 break;
414 }
415 c->head = NULL;
416 c->cached = 0;
417 }
418
cmp_pair(const void * a,const void * b)419 static int cmp_pair(const void * a, const void * b)
420 {
421 return _cmp((*(cdll_t**) a)->data,(*(cdll_t**) b)->data);
422 }
423
cmp_key(const void * in,const void * pair)424 static int cmp_key(const void * in, const void * pair)
425 {
426 return _cmp(in, (*((cdll_t**) pair))->data );
427 }
428 /* END of caching code */
429
_cmp(const void * a,const void * b)430 static int _cmp(const void *a, const void *b)
431 {
432 DBT * k = &(((data_t *)a)->key);
433 DBT * l = &(((data_t *)b)->key);
434
435 int c;
436
437 if ((a == NULL) || (b == NULL)) {
438 if (a == NULL)
439 return (b == NULL) ? 0 : -1;
440 else
441 return (b == NULL) ? 0 : +1;
442 };
443
444 c = memcmp(k->data,l->data,MIN(k->size,l->size));
445
446 if (c)
447 return c;
448
449 if (k->size < l->size)
450 return -1;
451
452 if (k->size > l->size)
453 return +1;
454
455 return 0;
456 }
457
_fetch(void * conf,void * data,void ** dout)458 static int _fetch(void * conf, void * data, void ** dout)
459 {
460 backend_caching_t *me = (backend_caching_t *) conf;
461 data_t * in = (data_t *) data;
462 data_t ** out = (data_t **) dout;
463 int e;
464
465 if (_dup(conf, (void *)in, (void **)out))
466 return -1;
467
468 e = (me->store->fetch)(me->instance,in->key,&((*out)->val));
469
470 /* Cache both positives and negatives. */
471 switch(e) {
472 case 0: /* found - no error */
473 (*out)->state = EXISTS;
474 break;
475 case FLAT_STORE_E_NOTFOUND: /* not found - but not an error */
476 (*out)->state = NOTFOUND;
477 e = 0;
478 break;
479 default:
480 /* keep error code */
481 fprintf(stderr,"DEBUG -- error %d\n",e);
482 }
483 if (0) fprintf(stderr,"BE fetch %s - returning %d - and exists is %d\n",
484 _x((*out)->key),e,(*out)->state);
485 return e;
486 }
487
_store(void * conf,void * data)488 static int _store(void * conf, void * data)
489 {
490 backend_caching_t *me = (backend_caching_t *) conf;
491 data_t * in = (data_t *) data;
492 int e;
493
494 if (in->state != CHANGED)
495 return 0;
496
497 e = (me->store->store)(me->instance,in->key,in->val);
498 switch(e) {
499 case 0:
500 /* ignore */
501 break;
502 case FLAT_STORE_E_KEYEXIST:
503 /* XXXXXXXXXXXXXXXXXXXXXXXXX we lose track of this ****XXXXXXXXXXXXXXXXX */
504 e = 0;
505 break;
506 default:
507 /* keep error code */
508 break;
509 }
510 return e;
511 }
512
_delete(void * conf,void * data)513 static int _delete(void * conf, void * data)
514 {
515 backend_caching_t *me = (backend_caching_t *) conf;
516 data_t * in = (data_t *) data;
517 int e = (me->store->delete)(me->instance,in->key); /* xxx we could also do this on a purge.. */
518 switch(e) {
519 case 0:
520 /* ignore */
521 break;
522 case FLAT_STORE_E_KEYEXIST:
523 e = 0;
524 break;
525 default:
526 /* keep error code */
527 break;
528 }
529 in->state = NOTFOUND; /* set to DELETE and do later on purge ?? */
530 return e;
531 }
532
_cpy(void * conf,void * from,void * to)533 static int _cpy(void * conf, void * from, void * to)
534 {
535 *(data_t *)to = *(data_t *)from;
536 return 0;
537 }
538
_dup(void * conf,void * from,void ** to)539 static int _dup(void * conf, void * from, void * * to)
540 {
541 backend_caching_t *me = (backend_caching_t *) conf;
542 data_t * p = (data_t *) from;
543 data_t * q;
544
545 if (!(q = me->malloc(sizeof(data_t))))
546 return -1;
547
548 memset(&(q->key),0,sizeof(q->key));
549 memset(&(q->val),0,sizeof(q->val));
550
551 if (p->key.data) {
552 if (!(q->key.data = me->malloc(p->key.size)))
553 return -1;
554 bcopy(p->key.data,q->key.data,p->key.size);
555 q->key.size = p->key.size;
556 } else {
557 q->key.data = NULL;
558 q->key.size = 0;
559 }
560
561 if (p->val.data) {
562 if (!(q->val.data = me->malloc(p->val.size)))
563 return -1;
564 bcopy(p->val.data,q->val.data,p->val.size);
565 q->val.size = p->val.size;
566 } else {
567 q->val.data = NULL;
568 q->val.size = 0;
569 }
570
571 q->state = p->state ;
572
573 #if 0
574 if (0) fprintf(stderr,"DUPed %s(%d,%d)==%s(%d,%d) exists=%d/%d\n",
575 _x(p->key), p->key.size,p->val.size,
576 _x(q->key), q->key.size,q->val.size,
577 p->state, q->state);
578 #endif
579
580 *to = q;
581 return 0;
582 }
583
_drp(backend_caching_t * me,void * conf,void * data)584 static int _drp(backend_caching_t * me, void * conf, void * data)
585 {
586 data_t * p = (data_t *) data;
587 if (p->key.data)
588 (*(me->free))(p->key.data);
589 if (p->val.data)
590 (*(me->free))(p->val.data);
591 (*(me->free))(p);
592 return 0;
593 }
594
595 /*
596 * Some default call back functions.
597 */
598 static void
default_myfree(void * adr)599 default_myfree(void *adr)
600 {
601 RDFSTORE_FREE(adr);
602 }
603 static void *
default_mymalloc(size_t x)604 default_mymalloc(size_t x)
605 {
606 return RDFSTORE_MALLOC(x);
607 }
608 static void
default_myerror(char * err,int erx)609 default_myerror(char *err, int erx)
610 {
611 fprintf(stderr, "backend_caching_ Error[%d]: %s\n", erx, err);
612 }
613
614 void
backend_caching_set_error(void * eme,char * msg,rdfstore_flat_store_error_t erx)615 backend_caching_set_error(
616 void *eme,
617 char *msg,
618 rdfstore_flat_store_error_t erx)
619 {
620 backend_caching_t *me = (backend_caching_t *) eme;
621 (me->store->set_error)(me->instance,msg,erx);
622 }
623
624 char *
backend_caching_get_error(void * eme)625 backend_caching_get_error(void *eme)
626 {
627 backend_caching_t *me = (backend_caching_t *) eme;
628 return (me->store->get_error)(me->instance);
629 }
630
631 /* clone a key or value for older BDB */
632 DBT
backend_caching_kvdup(void * eme,DBT data)633 backend_caching_kvdup(
634 void *eme,
635 DBT data)
636 {
637 backend_caching_t * me = (backend_caching_t *) eme;
638 return (me->store->kvdup)(me->instance,data);
639 }
640
641 void
backend_caching_reset_debuginfo(void * eme)642 backend_caching_reset_debuginfo(
643 void *eme
644 )
645 {
646 backend_caching_t *me = (backend_caching_t *) eme;
647 (me->store->reset_debuginfo)(me->instance);
648 }
649
650 /*
651 * NOTE: all the functions return 0 on success and non zero value if error
652 * (see above and include/backend_caching_.h for known error codes)
653 */
654 rdfstore_flat_store_error_t
backend_caching_open(int remote,int ro,void ** emme,char * dir,char * name,unsigned int local_hash_flags,char * host,int port,void * (* _my_malloc)(size_t size),void (* _my_free)(void *),void (* _my_report)(dbms_cause_t cause,int count),void (* _my_error)(char * err,int erx),int bt_compare_fcn_type)655 backend_caching_open(
656 int remote,
657 int ro,
658 void **emme,
659 char *dir,
660 char *name,
661 unsigned int local_hash_flags,
662 char *host,
663 int port,
664 void *(*_my_malloc) (size_t size),
665 void (*_my_free) (void *),
666 void (*_my_report) (dbms_cause_t cause, int count),
667 void (*_my_error) (char *err, int erx),
668 int bt_compare_fcn_type
669 )
670 {
671 backend_caching_t **mme = (backend_caching_t **) emme;
672 backend_caching_t *me;
673 char buff[1024];
674 int err;
675
676 *mme = NULL;
677
678 if (_my_error == NULL)
679 _my_error = default_myerror;
680
681 if (_my_malloc == NULL)
682 _my_malloc = default_mymalloc;
683
684 if (_my_free == NULL)
685 _my_free = default_myfree;
686
687 me = (backend_caching_t *) _my_malloc(sizeof(backend_caching_t));
688 if (me == NULL) {
689 perror("backend_caching_open");
690 return FLAT_STORE_E_NOMEM;
691 };
692
693 snprintf(buff,sizeof(buff)-1,"%p@%s:%d/%s/%s",
694 me,
695 host ? host : "<nohost>",
696 port ? port : 0,
697 dir ? dir : "<nodir>",
698 name ? name : "<inmemory>"
699 );
700 me->name = (char *)(*_my_malloc)( strlen(buff)+1 );
701 if( me->name == NULL )
702 return -1;
703 strcpy( me->name, buff );
704
705 me->malloc = _my_malloc;
706 me->free = _my_free;
707
708 #ifdef RDFSTORE_FLAT_STORE_DEBUG
709 backend_caching_reset_debuginfo(me);
710 #endif
711
712 switch (remote & 0xF) {
713 case 0:
714 me->store = backend_bdb;
715 break;
716 case 1:
717 me->store = backend_dbms;
718 break;
719 default:
720 perror("Backend type is not available");
721 return FLAT_STORE_E_NOMEM;
722 break;
723 };
724
725 /* Map to the real backend. */
726 err = (*(me->store->open)) (
727 remote & 0xF, ro, (void **) &(me->instance),
728 dir, name, local_hash_flags, host, port,
729 _my_malloc, _my_free, _my_report, _my_error,
730 bt_compare_fcn_type
731 );
732 if (err) {
733 (*_my_free) (me);
734 return err;
735 }
736 me->free = _my_free;
737
738 me->cache = (caching_store_t *)me->malloc(sizeof(caching_store_t));
739
740 /* Init with default cache size */
741 init_cachingstore(me->cache,0,
742 /* Functions to manage 'my' data */
743 me,
744 buff,
745 &_cmp,
746 &_fetch,
747 &_store,
748 &_delete,
749 &_dup,
750 &_cpy,
751 &_drp,
752 me->free,
753 me->malloc
754 );
755
756 * mme = me;
757 #ifdef RDFSTORE_FLAT_STORE_DEBUG
758 if (0) fprintf(stderr, "backend_caching_open '%s'\n", me->filename);
759 #endif
760 return 0;
761 }
762
763 rdfstore_flat_store_error_t
backend_caching_close(void * eme)764 backend_caching_close(
765 void *eme
766 )
767 {
768 backend_caching_t *me = (backend_caching_t *) eme;
769 int e;
770 if (0) fprintf(stderr,"%s: close\n",me->name);
771 purgecache(me, me->cache);
772 stats(me->cache);
773 e = (me->store->close)(me->instance);
774
775 me->free(me->name);
776 me->free(me->cache);
777 me->free(me);
778
779 return e;
780 };
781
782 rdfstore_flat_store_error_t
backend_caching_fetch(void * eme,DBT key,DBT * val)783 backend_caching_fetch(
784 void *eme,
785 DBT key,
786 DBT * val
787 )
788 {
789 backend_caching_t *me = (backend_caching_t *) eme;
790 data_t d, * out = NULL;
791 int e;
792
793 #if 0
794 fprintf(stderr,"%s: fetch %s(%d,%d)\n",me->name,_x(key),(int)key.size,(int)val->size);
795 #endif
796
797 /* Build a record */
798 d.key = key;
799 memset(&(d.val),0,sizeof(d.val));
800 d.val.data =NULL;
801 d.val.size = 0;
802 d.state = UNDEF; /* unkown */
803
804 if ((e = cachekey(me, me->cache,&d,(void **)&out, BC_READ))) {
805 return e;
806 }
807
808 val->data = out->val.data;
809 val->size = out->val.size;
810
811 #if 0
812 if (0) fprintf(stderr,"Cachekey returned e=%d and exits=%d val=%p,%d\n",e,out->state,val->data,val->size);
813 #endif
814
815 if (out->state == NOTFOUND) {
816 me->free(out);
817 return FLAT_STORE_E_NOTFOUND;
818 };
819
820 if (out->key.data)
821 me->free(out->key.data);
822 me->free(out);
823
824 return 0;
825 }
826
827 rdfstore_flat_store_error_t
backend_caching_fetch_compressed(void * eme,void (* func_decode)(unsigned int,unsigned char *,unsigned int *,unsigned char *),DBT key,unsigned int * outsize_p,unsigned char * outchar)828 backend_caching_fetch_compressed(
829 void * eme,
830 void (*func_decode)(unsigned int,unsigned char*, unsigned int *, unsigned char *),
831 DBT key,
832 unsigned int * outsize_p, unsigned char * outchar
833 )
834 {
835 backend_caching_t *me = (backend_caching_t *) eme;
836 return (me->store->fetch_compressed)(me->instance,func_decode,key,outsize_p,outchar);
837 }
838
839 rdfstore_flat_store_error_t
backend_caching_store(void * eme,DBT key,DBT val)840 backend_caching_store(
841 void *eme,
842 DBT key,
843 DBT val
844 )
845 {
846 backend_caching_t *me = (backend_caching_t *) eme;
847 data_t d;
848 int e;
849
850 d.key = key;
851 d.val = val;
852 d.state = CHANGED;
853
854 e = cachekey(me, me->cache,&d,NULL,BC_WRITE);
855 #if 0
856 fprintf(stderr,"%s: store %s(%d,%d) E=%d\n",me->name,_x(key),(int)key.size,(int)val.size,e);
857 #endif
858 return e;
859 }
860
861 rdfstore_flat_store_error_t
backend_caching_store_compressed(void * eme,void (* func_decode)(unsigned int,unsigned char *,unsigned int *,unsigned char *),DBT key,unsigned int insize,unsigned char * inchar,unsigned char * outbuff)862 backend_caching_store_compressed(
863 void * eme,
864 void (*func_decode)(unsigned int,unsigned char*, unsigned int *, unsigned char *),
865 DBT key,
866 unsigned int insize , unsigned char * inchar,
867 unsigned char * outbuff
868 )
869 {
870 backend_caching_t *me = (backend_caching_t *) eme;
871 return (me->store->store_compressed)(me->instance,func_decode,key,insize,inchar,outbuff);
872 }
873
874 rdfstore_flat_store_error_t
backend_caching_exists(void * eme,DBT key)875 backend_caching_exists(
876 void *eme,
877 DBT key
878 )
879 {
880 backend_caching_t *me = (backend_caching_t *) eme;
881 data_t d;
882 int e;
883
884 /* Build a record */
885 d.key = key;
886 memset(&(d.val),0,sizeof(d.val));
887 d.val.data =NULL;
888 d.val.size = 0;
889 d.state = UNDEF; /* unkown */
890
891 e = cachekey(me, me->cache,&d,NULL, BC_EXISTS);
892
893 if (0) fprintf(stderr,"%s: exists %s ==> e=%d and d.exists=%d\n",me->name,_x(key),e,d.state);
894
895 if (e)
896 return e;
897
898
899 return (d.state == EXISTS || d.state == CHANGED) ? 0 : FLAT_STORE_E_NOTFOUND;
900 }
901
902 rdfstore_flat_store_error_t
backend_caching_delete(void * eme,DBT key)903 backend_caching_delete(
904 void *eme,
905 DBT key
906 )
907 {
908 backend_caching_t *me = (backend_caching_t *) eme;
909 data_t d;
910 if (0) fprintf(stderr,"%s: delete\n",me->name);
911
912 d.key = key;
913 memset(&(d.val),0,sizeof(d.val));
914 d.state = UNDEF;
915
916 return cachekey(me, me->cache,&d,NULL, BC_DELETE);
917 };
918
919 rdfstore_flat_store_error_t
backend_caching_clear(void * eme)920 backend_caching_clear(
921 void *eme
922 )
923 {
924 backend_caching_t *me = (backend_caching_t *) eme;
925 if (0) fprintf(stderr,"%s: clear\n",me->name);
926 assert(0);
927 return (me->store->clear)(me->instance);
928 }
929
930 rdfstore_flat_store_error_t
backend_caching_from(void * eme,DBT closest_key,DBT * key)931 backend_caching_from(
932 void *eme,
933 DBT closest_key,
934 DBT * key
935 )
936 {
937 backend_caching_t *me = (backend_caching_t *) eme;
938 if (0) fprintf(stderr,"%s: from\n",me->name);
939 purgecache(me, me->cache);
940 return (me->store->from)(me->instance,closest_key,key);
941 }
942
943 rdfstore_flat_store_error_t
backend_caching_first(void * eme,DBT * first_key)944 backend_caching_first(
945 void *eme,
946 DBT * first_key
947 )
948 {
949 backend_caching_t *me = (backend_caching_t *) eme;
950 if (0) fprintf(stderr,"%s: first\n",me->name);
951 purgecache(me, me->cache);
952 return (me->store->first)(me->instance,first_key);
953 }
954
955 rdfstore_flat_store_error_t
backend_caching_next(void * eme,DBT previous_key,DBT * next_key)956 backend_caching_next(
957 void *eme,
958 DBT previous_key,
959 DBT * next_key
960 )
961 {
962 backend_caching_t *me = (backend_caching_t *) eme;
963 if (0) fprintf(stderr,"%s: next\n",me->name);
964 purgecache(me, me->cache);
965 return (me->store->next)(me->instance,previous_key,next_key);
966 }
967
968 /* packed rdf_store_counter_t increment */
969 rdfstore_flat_store_error_t
backend_caching_inc(void * eme,DBT key,DBT * new_value)970 backend_caching_inc(
971 void *eme,
972 DBT key,
973 DBT * new_value
974 )
975 {
976 backend_caching_t *me = (backend_caching_t *) eme;
977 rdf_store_counter_t l = 0;
978 int e;
979 memset(new_value, 0, sizeof(*new_value));
980 #if 0
981 fprintf(stderr,"%s: inc %s\n",me->name,_x(key));
982 #endif
983
984 e = backend_caching_fetch(eme,key,new_value);
985 if (e)
986 return e;
987
988 unpackInt(new_value->data, &l);
989 l++;
990 packInt(l, new_value->data);
991
992 if ((e = backend_caching_store(eme,key,*new_value))) {
993 memset(new_value, 0, sizeof(*new_value));
994 } else {
995 (*new_value) = backend_caching_kvdup(me, *new_value);
996 }
997 return e;
998 }
999
1000 /* packed rdf_store_counter_t decrement */
1001 rdfstore_flat_store_error_t
backend_caching_dec(void * eme,DBT key,DBT * new_value)1002 backend_caching_dec(
1003 void *eme,
1004 DBT key,
1005 DBT * new_value
1006 )
1007 {
1008 backend_caching_t *me = (backend_caching_t *) eme;
1009 rdf_store_counter_t l = 0;
1010 int e;
1011
1012 memset(new_value, 0, sizeof(*new_value));
1013
1014 if (0) fprintf(stderr,"%s: dec\n",me->name);
1015 e = backend_caching_fetch(eme,key,new_value);
1016 if (e)
1017 return e;
1018
1019 unpackInt(new_value->data, &l);
1020 l--;
1021 packInt(l, new_value->data);
1022
1023 if ((e = backend_caching_store(eme,key,*new_value))) {
1024 memset(new_value, 0, sizeof(*new_value));
1025 } else {
1026 (*new_value) = backend_caching_kvdup(me, *new_value);
1027 }
1028
1029 return e;
1030 }
1031
1032 rdfstore_flat_store_error_t
backend_caching_sync(void * eme)1033 backend_caching_sync(
1034 void *eme
1035 )
1036 {
1037 backend_caching_t *me = (backend_caching_t *) eme;
1038 if (0) fprintf(stderr,"%s: sync\n",me->name);
1039 purgecache(me, me->cache);
1040 return (me->store->sync)(me->instance);
1041 }
1042
1043 int
backend_caching_isremote(void * eme)1044 backend_caching_isremote(
1045 void *eme
1046 )
1047 {
1048 backend_caching_t *me = (backend_caching_t *) eme;
1049 return (me->store->isremote)(me->instance);
1050 }
1051
1052
1053 #define CACHING_VERSION (100)
1054 DECLARE_MODULE_BACKEND(backend_caching, "Caching", CACHING_VERSION)
1055
1056