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