You are viewing a plain text version of this content. The canonical link for it is here.
Posted to triplesoup-commits@incubator.apache.org by le...@apache.org on 2007/04/13 08:56:16 UTC

svn commit: r528394 [4/35] - in /incubator/triplesoup/donations/TRIPLES-3-RDFStore: ./ dbms/ dbms/client/ dbms/client/t/ dbms/dbmsproxy/ dbms/deamon/ dbms/doc/ dbms/include/ dbms/libdbms/ dbms/utils/ doc/ include/ lib/ lib/DBD/ lib/RDFStore/ lib/RDFSto...

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_bdb_store.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_bdb_store.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_bdb_store.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_bdb_store.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,1272 @@
+/*
+##############################################################################
+# 	Copyright (c) 2000-2006 All rights reserved
+# 	Alberto Reggiori <ar...@webweaving.org>
+#	Dirk-Willem van Gulik <di...@webweaving.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The end-user documentation included with the redistribution,
+#    if any, must include the following acknowledgment:
+#       "This product includes software developed by
+#        Alberto Reggiori <ar...@webweaving.org> and
+#        Dirk-Willem van Gulik <di...@webweaving.org>."
+#    Alternately, this acknowledgment may appear in the software itself,
+#    if and wherever such third-party acknowledgments normally appear.
+#
+# 4. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#    This product includes software developed by the University of
+#    California, Berkeley and its contributors.
+#
+# 5. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# 6. Products derived from this software may not be called "RDFStore"
+#    nor may "RDFStore" appear in their names without prior written
+#    permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# ====================================================================
+#
+# This software consists of work developed by Alberto Reggiori and
+# Dirk-Willem van Gulik. The RDF specific part is based based on public
+# domain software written at the Stanford University Database Group by
+# Sergey Melnik. For more information on the RDF API Draft work,
+# please see <http://www-db.stanford.edu/~melnik/rdf/api.html>
+# The DBMS TCP/IP server part is based on software originally written
+# by Dirk-Willem van Gulik for Web Weaving Internet Engineering m/v Enschede,
+# The Netherlands.
+#
+##############################################################################
+#
+# $Id: backend_bdb_store.c,v 1.21 2006/06/19 10:10:21 areggiori Exp $
+*/
+
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+
+#include "rdfstore_flat_store.h"
+#include "rdfstore_log.h"
+#include "rdfstore.h"
+
+#include "backend_store.h"
+
+#include "backend_bdb_store.h"
+#include "backend_bdb_store_private.h"
+
+#include <sys/stat.h>
+
+static char    *mkpath(char *base, char *infile);
+
+/*
+ * Some default call back functions.
+ */
+static void
+default_myfree(void *adr)
+{
+	RDFSTORE_FREE(adr);
+}
+static void    *
+default_mymalloc(size_t x)
+{
+	return RDFSTORE_MALLOC(x);
+}
+static void
+default_myerror(char *err, int erx)
+{
+	fprintf(stderr, "backend_bdb Error[%d]: %s\n", erx, err);
+}
+
+/* backend_bdb error management */
+static char     _backend_bdb_erm[256] = "\0";
+
+/* human-readable error codes */
+static char    *backend_bdb_error[] = {
+	/* FLAT_STORE_E_UNDEF         2000 */
+	"Not defined",
+	/* FLAT_STORE_E_NONNUL        2001 */
+	"Undefined Error",
+	/* FLAT_STORE_E_NOMEM         2002 */
+	"Out of memory",
+	/* FLAT_STORE_E_NOPE          2003 */
+	"No such database",
+	/* FLAT_STORE_E_KEYEMPTY      2004 */
+	"Key/data deleted or never created",
+	/* FLAT_STORE_E_KEYEXIST      2005 */
+	"The key/data pair already exists",
+	/* FLAT_STORE_E_NOTFOUND      2006 */
+	"Key/data pair not found",
+	/* FLAT_STORE_E_OLD_VERSION   2007 */
+	"Out-of-date version",
+	/* FLAT_STORE_E_DBMS          2008 */
+	"DBMS error",
+	/* FLAT_STORE_E_CANNOTOPEN    2009 */
+	"Cannot open database",
+	/* FLAT_STORE_E_BUG           2010 */
+	"Conceptual error"
+};
+
+void
+backend_bdb_set_error(void *eme, char *msg, rdfstore_flat_store_error_t erx)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	bzero(me->err, sizeof(me->err));
+	if (erx == FLAT_STORE_E_DBMS) {
+		snprintf(me->err, sizeof(me->err), "DBMS Error %s: %s\n", msg,
+			 errno == 0 ? "" : (strlen(strerror(errno)) <= sizeof(me->err)) ? strerror(errno) : "");	/* not enough... */
+	} else {
+		if ((erx > FLAT_STORE_E_UNDEF) && (erx <= FLAT_STORE_E_BUG)) {
+			strcpy(me->err, backend_bdb_error[erx - FLAT_STORE_E_UNDEF]);
+		} else {
+			if (strlen(strerror(erx)) <= sizeof(me->err))
+				strcpy(me->err, strerror(erx));
+		};
+	};
+	if (strlen(me->err) <= sizeof(_backend_bdb_erm))
+		strcpy(_backend_bdb_erm, me->err);
+
+#ifdef VERBOSE
+	if (me->error)
+		(*(me->error)) (me->err, erx);
+#endif
+}
+
+
+char           *
+backend_bdb_get_error(void *eme)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	if (me == NULL)
+		return _backend_bdb_erm;
+	else
+		return me->err;
+};
+
+/* clone a key or value for older BDB */
+DBT
+backend_bdb_kvdup(void *eme, DBT data)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	DBT             dup;
+
+	memset(&dup, 0, sizeof(dup));
+
+	if (data.size == 0) {
+		dup.data = NULL;
+		return dup;
+	};
+
+	dup.size = data.size;
+
+	if ((dup.data = (char *) me->malloc(data.size + 1)) == NULL) {
+		perror("Out of memory");
+		exit(1);
+	}; 	
+
+
+	memcpy(dup.data, data.data, data.size);
+	memcpy(dup.data + data.size, "\0", 1);
+
+	return dup;
+};
+
+void
+backend_bdb_reset_debuginfo(
+			    void *eme
+)
+{
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	me->num_store = 0;
+	me->num_fetch = 0;
+	me->num_inc = 0;
+	me->num_dec = 0;
+	me->num_sync = 0;
+	me->num_next = 0;
+	me->num_from = 0;
+	me->num_first = 0;
+	me->num_delete = 0;
+	me->num_clear = 0;
+	me->num_exists = 0;
+#endif
+};
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_bdb_compare_int(
+        const DBT *a,
+        const DBT *b );
+#else
+static int rdfstore_backend_bdb_compare_int(
+        DB *file,
+        const DBT *a,
+        const DBT *b );
+#endif
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_bdb_compare_double(
+        const DBT *a,
+        const DBT *b );
+#else
+static int rdfstore_backend_bdb_compare_double(
+        DB *file,
+        const DBT *a,
+        const DBT *b );
+#endif
+
+/*
+ * NOTE: all the functions return 0 on success and non zero value if error
+ * (see above and include/backend_bdb.h for known error codes)
+ */
+rdfstore_flat_store_error_t
+backend_bdb_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
+)
+{
+	backend_bdb_t **mme = (backend_bdb_t **) emme;
+	backend_bdb_t  *me;
+	char           *buff;
+	struct stat s;
+#if 0
+	HASHINFO        priv = {
+		16 * 1024,	/* bsize; hash bucked size */
+		8,		/* ffactor, # keys/bucket */
+		3000,		/* nelements, guestimate */
+		512 * 1024,	/* cache size */
+		NULL,		/* hash function */
+		0		/* use current host order */
+	};
+#endif
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
+#ifdef DB_VERSION_MAJOR
+	DB_INFO       btreeinfo;
+	memset(&btreeinfo, 0, sizeof(btreeinfo));
+	btreeinfo.bt_compare = ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_bdb_compare_int : ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_bdb_compare_double : NULL ;
+#else
+	BTREEINFO       btreeinfo;
+	memset(&btreeinfo, 0, sizeof(btreeinfo));
+	btreeinfo.compare = ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_bdb_compare_int : ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_bdb_compare_double : NULL ;
+#endif
+#endif
+
+	*mme = NULL;
+
+	if (_my_error == NULL)
+		_my_error = default_myerror;
+
+	if (_my_malloc == NULL)
+		_my_malloc = default_mymalloc;
+
+	if (_my_free == NULL)
+		_my_free = default_myfree;
+
+	me = (backend_bdb_t *) _my_malloc(sizeof(backend_bdb_t));
+	if (me == NULL) {
+		perror("backend_bdb_open");
+		return FLAT_STORE_E_NOMEM;
+	};
+
+	me->error = _my_error;
+	me->malloc = _my_malloc;
+	me->free = _my_free;
+
+	me->bt_compare_fcn_type = bt_compare_fcn_type;
+
+	bzero(me->err, sizeof(me->err));
+
+	if (_my_report != NULL)
+		me->callback = _my_report;
+
+	backend_bdb_reset_debuginfo(me);
+
+	if (remote) {
+		backend_bdb_set_error(me, "BDB backend does not do remote storage", FLAT_STORE_E_DBMS);
+		perror("backend_bdb_open");
+		_my_free(me);
+		return FLAT_STORE_E_CANNOTOPEN;
+	};
+
+	/* use local Berkeley DB either in-memory or physical files on disk */
+	if ((dir) &&
+	    (name)) {
+		if(ro==1) { /* do not even try to go further if open read-only */
+			if (	(stat(dir, &s) != 0) ||
+				((s.st_mode & S_IFDIR) == 0) ) {
+				backend_bdb_set_error(me, "Could not open database", FLAT_STORE_E_NOPE);
+				perror("backend_bdb_open");
+				fprintf(stderr, "Could not open database'%s'\n", dir);
+				_my_free(me);
+				return FLAT_STORE_E_CANNOTOPEN;
+				};
+			};
+		/* make path */
+		if (!(buff = mkpath(dir, name))) {
+			backend_bdb_set_error(me, "Could not create or open database", FLAT_STORE_E_NOPE);
+			perror("backend_bdb_open");
+			fprintf(stderr, "Could not create or open database'%s'\n", dir);
+			_my_free(me);
+			return FLAT_STORE_E_CANNOTOPEN;
+		};
+		strcpy(me->filename, buff);
+		umask(0);
+	} else {
+		strcpy(me->filename, "\0");
+		buff = NULL;
+	};
+
+	/* something strange with BDB - it gives 'Bus error' if DB file not there and open in DB_RDONLY - why seg fault? must be DB_ENV stuff... */
+	if(	(buff!=NULL) &&
+		(ro==1) ) {
+		if (	(stat(buff, &s) != 0) ||
+			((s.st_mode & S_IFREG) == 0) ) {
+			backend_bdb_set_error(me, "Could not open database", FLAT_STORE_E_NOPE);
+			perror("backend_bdb_open");
+			fprintf(stderr, "Could not open database '%s'\n", dir);
+			_my_free(me);
+			return FLAT_STORE_E_CANNOTOPEN;
+			};
+		};
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
+
+#ifdef DB_VERSION_MAJOR
+		if ( 	(db_open( buff, 
+					DB_BTREE, ((ro==0 || buff==NULL) ? ( DB_CREATE ) : ( DB_RDONLY ) ),
+					0666, NULL, &btreeinfo, &me->bdb )) ||
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
+            		((me->bdb->cursor)(me->bdb, NULL, &me->cursor))
+#else
+            		((me->bdb->cursor)(me->bdb, NULL, &me->cursor, 0))
+#endif
+			) {
+#else
+
+#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
+		if (!(me->bdb = (DB *)__db185_open(	buff, 
+						((ro==0 || buff==NULL) ? (O_RDWR | O_CREAT) : ( O_RDONLY ) ),
+						0666, DB_BTREE, &btreeinfo ))) {
+#else
+		/* for unpatched db-1.85 when use in-memory DB_BTREE due to mkstemp() call in hash/hash_page.c open_temp() 
+		   i.e. HASHVERSION==2 we use DB_BTREE instead in CGI/mod_perl environments to avoid problems with errors
+		   like 'Permission denied' due the Web server running in a different user under a different directory */
+
+#if DIRKX_DEBUG
+BTREEINFO openinfo = {
+	0,
+	32 * 1024 * 1024,
+	0,
+	atoi(getenv("PSIZE")),
+	64 * 1024,
+	NULL, NULL, 0
+};
+#endif
+		if (!(me->bdb = (DB *)dbopen(	buff, 
+						((ro==0 || buff==NULL) ? (O_RDWR | O_CREAT) : ( O_RDONLY ) ),
+						0666,
+#if HASHVERSION == 2
+						( ( (buff==NULL) && (getenv("GATEWAY_INTERFACE") != NULL) ) ? DB_BTREE : DB_BTREE ),
+#else
+						DB_BTREE,
+#endif
+#if DIRKX_DEBUG
+						&openinfo))) {
+#else
+						&btreeinfo ))) {
+#endif
+
+#endif /* DB_LIBRARY_COMPATIBILITY_API */
+
+#endif
+
+#else /* Berkeley DB Version > 2 */
+		if (db_create(&me->bdb, NULL,0)) {
+			rdfstore_flat_store_set_error((void*)me,"Could not create environment",FLAT_STORE_E_CANNOTOPEN);
+			perror("rdfstore_flat_store_open");
+                	fprintf(stderr,"Could not open/create '%s':\n",buff); 
+			_my_free(me);
+                	return FLAT_STORE_E_CANNOTOPEN;
+			};
+
+		/* set the b-tree comparinson function to the one passed */
+		if( bt_compare_fcn_type != 0 ) {
+			me->bdb->set_bt_compare(me->bdb, ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? 
+							rdfstore_backend_bdb_compare_int : ( bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? 
+												rdfstore_backend_bdb_compare_double : NULL );
+			};
+
+		me->bdb->set_errfile(me->bdb,stderr);
+		me->bdb->set_errpfx(me->bdb,"BerkelyDB");
+#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3
+		me->bdb->set_malloc( me->bdb, me->malloc );
+#elif DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR >= 3
+        	/* This interface appeared in 3.3 */
+        	me->bdb->set_alloc( me->bdb, me->malloc, NULL, NULL ); /* could also pass me->free as 4th param but not sure how memoeyr is managed still */
+#endif
+
+#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR > 0 && DB_VERSION_PATCH >= 17
+		if ( 	(me->bdb->open( me->bdb,
+					NULL, 
+					buff,
+					NULL,
+					DB_BTREE, ((ro==0 || buff==NULL) ? ( DB_CREATE ) : ( DB_RDONLY ) ),
+					0666 )) ||
+#else
+		if ( 	(me->bdb->open( me->bdb,
+					buff, 
+					NULL,
+					DB_BTREE, ((ro==0 || buff==NULL) ? ( DB_CREATE ) : ( DB_RDONLY ) ),
+					0666 )) ||
+#endif
+			((me->bdb->cursor)(me->bdb, NULL, &me->cursor, 0)) ) {
+#endif /* Berkeley DB Version > 2 */
+
+			rdfstore_flat_store_set_error((void*)me,"Could not open/create database",FLAT_STORE_E_CANNOTOPEN);
+			perror("rdfstore_flat_store_open");
+                	fprintf(stderr,"Could not open/create '%s':\n",buff); 
+			_my_free(me);
+                	return FLAT_STORE_E_CANNOTOPEN;
+			};
+
+#ifndef BERKELEY_DB_1_OR_2 /* Berkeley DB Version > 2 */
+/*
+		(void)me->bdb->set_h_ffactor(me->bdb, 1024);
+		(void)me->bdb->set_h_nelem(me->bdb, (u_int32_t)6000);
+*/
+#endif
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+        fprintf(stderr,"rdfstore_flat_store_open '%s'\n",me->filename);
+#endif
+
+	*mme = me;
+	return 0;
+}
+
+rdfstore_flat_store_error_t
+backend_bdb_close(
+		  void *eme
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	void            (*_my_free) (void *) = me->free;
+	int             retval = 0;
+
+#ifdef DB_VERSION_MAJOR
+	me->cursor->c_close(me->cursor);
+	(me->bdb->close) (me->bdb, 0);
+#else
+	(me->bdb->close) (me->bdb);
+#endif
+	_my_free(me);
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_close '%s'\n", me->filename);
+#endif
+
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_fetch(
+		  void * eme,
+		  DBT key,
+		  DBT * val
+)
+{
+	backend_bdb_t  * me = (backend_bdb_t *) eme;
+	int             retval = 0;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_fetch num=%d from '%s'\n", ++(me->num_fetch), me->filename);
+#endif
+
+#if DB_VERSION_MAJOR >= 2
+	memset(val, 0, sizeof(*val));
+	(*val).flags = DB_DBT_MALLOC;
+	retval = ((me->bdb)->get) (me->bdb, NULL, &key, val, 0);
+#else
+	retval = ((me->bdb)->get) (me->bdb, &key, val, 0);
+#endif
+
+	/* need to add proper client side BDB error management */
+	if (retval != 0) {
+#if DB_VERSION_MAJOR >= 2
+		if ((*val).data && (*val).size)
+			me->free((*val).data);
+#endif
+		memset(val, 0, sizeof(*val));
+		(*val).data = NULL;
+
+#ifdef DB_VERSION_MAJOR
+		if (retval == DB_NOTFOUND) 
+#else
+		if (retval == 1) 
+#endif	
+		{
+			backend_bdb_set_error(me, "Could not fetch key/value", FLAT_STORE_E_NOTFOUND);
+			return FLAT_STORE_E_NOTFOUND;
+		} else {
+			backend_bdb_set_error(me, "Could not fetch key/value", FLAT_STORE_E_NOTFOUND);
+			perror("backend_bdb_fetch");
+			fprintf(stderr, "Could not fetch '%s': %s\n", me->filename, (char *) key.data);
+			return FLAT_STORE_E_NOTFOUND;
+		};
+	} else {
+#if DB_VERSION_MAJOR < 2
+		/*
+		 * Berkeley DB 1.85 don't malloc the data for the caller
+		 * application duplicate the returned value to ensure
+		 * reentrancy
+		 */
+		(*val) = backend_bdb_kvdup(me, *val);
+#endif
+		return retval;
+	};
+}
+
+rdfstore_flat_store_error_t
+backend_bdb_fetch_compressed(
+		  void * eme,
+        	  void (*func_decode)(unsigned int,unsigned char*, unsigned int *, unsigned char *),
+		  DBT key,
+		  unsigned int * outsize_p, unsigned char * outchar
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval = 0;
+	DBT 		val;
+	memset(&val,0,sizeof(val));
+
+	if ((retval = backend_bdb_fetch(eme,key,&val)))
+		return retval;
+
+	(*func_decode)(val.size,val.data,outsize_p,outchar);
+	(me->free)(val.data);
+
+	return retval;
+}
+
+rdfstore_flat_store_error_t
+backend_bdb_store(
+		  void *eme,
+		  DBT key,
+		  DBT val
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval = 0;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_store num=%d in '%s'\n", ++(me->num_store), me->filename);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+	retval = ((me->bdb)->put) (me->bdb, NULL, &key, &val, 0);
+#else
+	retval = ((me->bdb)->put) (me->bdb, &key, &val, 0);
+#endif
+	if (retval != 0) {
+#ifdef DB_VERSION_MAJOR
+		if (retval == DB_KEYEXIST) 
+#else
+		if (retval == 1) 
+#endif
+		{
+			backend_bdb_set_error(me, "Could not store key/value", FLAT_STORE_E_KEYEXIST);
+			return FLAT_STORE_E_KEYEXIST;
+		};
+
+		backend_bdb_set_error(me, "Could not store key/value", FLAT_STORE_E_NONNUL);
+		fprintf(stderr, "Could not store '%s': %s(%d) = %s(%d) E=%d\n", me->filename, 
+			(char *) key.data, (int)key.size,
+			(char *) val.data, (int)val.size,
+			retval);
+		return FLAT_STORE_E_NONNUL;
+	}
+	return 0;
+}
+
+rdfstore_flat_store_error_t
+backend_bdb_store_compressed(
+		  void * eme,
+        	  void (*func_encode)(unsigned int,unsigned char*, unsigned int *, unsigned char *),
+		  DBT key,
+		  unsigned int insize , unsigned char * inchar,
+		  unsigned char * outbuff
+)
+{
+	unsigned int	outsize;
+	DBT 		val;
+	memset(&val,0,sizeof(val));
+
+	(*func_encode)(insize, inchar, &outsize, outbuff);
+
+	val.data = outbuff;
+	val.size = outsize;
+
+	return backend_bdb_store(eme,key,val);
+}
+
+rdfstore_flat_store_error_t
+backend_bdb_exists(
+		   void *eme,
+		   DBT key
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	DBT             val;
+	memset(&val,0,sizeof(val));
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_exists num=%d from '%s'\n", ++(me->num_exists), me->filename);
+#endif
+
+
+	memset(&val, 0, sizeof(val));
+
+	/*
+	 * here we do not care about memory management due that we just want
+	 * to know whether or not the given key exists
+	 */
+
+#if DB_VERSION_MAJOR >= 2
+	retval = ((me->bdb)->get) (me->bdb, NULL, &key, &val, 0);
+#else
+	retval = ((me->bdb)->get) (me->bdb, &key, &val, 0);
+#endif
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_delete(
+		   void *eme,
+		   DBT key
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_delete num=%d from '%s'\n", ++(me->num_delete), me->filename);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+	retval = ((me->bdb)->del) (me->bdb, NULL, &key, 0);
+	if( retval == DB_NOTFOUND )
+		return FLAT_STORE_E_NOTFOUND;
+#else
+	retval = ((me->bdb)->del) (me->bdb, &key, 0);
+	if ( retval == 1 )
+		return FLAT_STORE_E_NOTFOUND;
+#endif
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_clear(
+		  void *eme
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	char           *buff;
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
+#ifdef DB_VERSION_MAJOR
+        DB_INFO       btreeinfo;
+        memset(&btreeinfo, 0, sizeof(btreeinfo));
+        btreeinfo.bt_compare = ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_bdb_compare_int : ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_bdb_compare_double : NULL ;
+#else
+        BTREEINFO       btreeinfo;
+        memset(&btreeinfo, 0, sizeof(btreeinfo));
+        btreeinfo.compare = ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_bdb_compare_int : ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_bdb_compare_double : NULL  ;
+#endif
+#endif
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	me->num_store = 0;
+	me->num_fetch = 0;
+	me->num_inc = 0;
+	me->num_dec = 0;
+	me->num_sync = 0;
+	me->num_next = 0;
+	me->num_from = 0;
+	me->num_first = 0;
+	me->num_delete = 0;
+	me->num_exists = 0;
+	fprintf(stderr, "backend_bdb_clear num=%d in '%s'\n", ++(me->num_clear), me->filename);
+#endif
+
+
+	/* close the database, remove the file, and repoen... ? */
+	/* close */
+#ifdef DB_VERSION_MAJOR
+	me->cursor->c_close(me->cursor);
+	(me->bdb->close) (me->bdb, 0);
+#else
+	(me->bdb->close) (me->bdb);
+#endif
+
+	if (strcmp(me->filename, "\0") != 0) {
+		/* remove db file (not the directory!) */
+		if (unlink(me->filename)) {
+			perror("backend_bdb_clear");
+			fprintf(stderr, "Could not remove '%s' while clearing\n", me->filename);
+			return -1;
+		};
+		buff = me->filename;
+		umask(0);
+	} else {
+		buff = NULL;
+	};
+
+	/* re-open */
+
+#ifdef BERKELEY_DB_1_OR_2	/* Berkeley DB Version 1  or 2 */
+
+#ifdef DB_VERSION_MAJOR
+	if ((db_open(buff,
+		     DB_BTREE, DB_CREATE,
+		     0666, NULL, &btreeinfo, &me->bdb)) ||
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
+	    ((me->bdb->cursor) (me->bdb, NULL, &me->cursor))
+#else
+	    ((me->bdb->cursor) (me->bdb, NULL, &me->cursor, 0))
+#endif
+		) {
+#else
+
+#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
+	if (!(me->bdb = (DB *) __db185_open(buff,
+					    O_RDWR | O_CREAT,
+					    0666, DB_BTREE, &btreeinfo))) {
+#else
+	if (!(me->bdb = (DB *) dbopen(buff,
+				      O_RDWR | O_CREAT,
+				      0666, DB_BTREE, &btreeinfo))) {
+#endif				/* DB_LIBRARY_COMPATIBILITY_API */
+
+#endif
+
+#else				/* Berkeley DB Version > 2 */
+	if (db_create(&me->bdb, NULL, 0)) {
+		backend_bdb_set_error(me, "Could not open/create database", FLAT_STORE_E_CANNOTOPEN);
+		perror("backend_bdb_open");
+		fprintf(stderr, "Could not open/create '%s':\n", buff);
+		return FLAT_STORE_E_CANNOTOPEN;
+	};
+
+	/* set the b-tree comparinson function to the one passed */
+	if( me->bt_compare_fcn_type != 0 ) {
+		me->bdb->set_bt_compare(me->bdb, ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? 
+						rdfstore_backend_bdb_compare_int : ( me->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? 
+											rdfstore_backend_bdb_compare_double : NULL );
+		};
+
+	me->bdb->set_errfile(me->bdb,stderr);
+	me->bdb->set_errpfx(me->bdb,"BerkelyDB");
+#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3
+	me->bdb->set_malloc(me->bdb, me->malloc);
+#elif DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR >= 3
+	/* This interface appeared in 3.3 */
+	me->bdb->set_alloc(me->bdb, me->malloc, NULL, NULL);	/* could also pass
+								 * me->free as 4th param
+								 * but not sure how
+								 * memoeyr is managed
+								 * still */
+#endif
+
+#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR > 0 && DB_VERSION_PATCH >= 17
+	if ((me->bdb->open(me->bdb,
+			   NULL,
+			   buff,
+			   NULL,
+			   DB_BTREE, DB_CREATE,
+			   0666)) ||
+#else
+	if ((me->bdb->open(me->bdb,
+			   buff,
+			   NULL,
+			   DB_BTREE, DB_CREATE,
+			   0666)) ||
+#endif
+	    ((me->bdb->cursor) (me->bdb, NULL, &me->cursor, 0))) {
+#endif				/* Berkeley DB Version > 2 */
+
+		perror("backend_bdb_clear");
+		fprintf(stderr, "Could not open/create '%s' while clearing\n", buff);
+		return -1;
+	};
+	return 0;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_from(
+		  void *eme,
+		  DBT closest_key,
+		  DBT * key
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	DBT             val;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_from num=%d from '%s'\n", ++(me->num_from), me->filename);
+#endif
+
+	memset(&val, 0, sizeof(val));
+
+	/* seek to closest_key and discard val */
+	memcpy(key, &closest_key, sizeof(closest_key));
+
+#if DB_VERSION_MAJOR >= 2
+	retval = (me->cursor->c_get) (me->cursor, key, &val, DB_SET_RANGE);
+#else
+	retval = (me->bdb->seq) (me->bdb, key, &val, R_CURSOR);
+#endif
+
+	if (retval == 0) {
+                /*
+                 * to ensure reentrancy we do a copy into caller space of what BDB layer returns
+                 */
+		(*key) = backend_bdb_kvdup(me, *key);
+                };
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_first(
+		  void *eme,
+		  DBT * first_key
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	DBT             val;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_first num=%d from '%s'\n", ++(me->num_first), me->filename);
+#endif
+
+	memset(first_key, 0, sizeof(*first_key));
+	memset(&val, 0, sizeof(val));
+
+#if DB_VERSION_MAJOR >= 2
+	retval = (me->cursor->c_get) (me->cursor, first_key, &val, DB_FIRST);
+#else
+	retval = (me->bdb->seq) (me->bdb, first_key, &val, R_FIRST);
+#endif
+
+	if (retval == 0) {
+		/*
+		 * to ensure reentrancy we do a copy into caller space of what BDB layer returns
+		 */
+		(*first_key) = backend_bdb_kvdup(me, *first_key);
+		};
+
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_next(
+		 void *eme,
+		 DBT previous_key,
+		 DBT * next_key
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	DBT             val;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_next num=%d from '%s'\n", ++(me->num_next), me->filename);
+#endif
+
+	memset(next_key, 0, sizeof(*next_key));
+	memset(&val, 0, sizeof(val));
+
+	/* we really do not use/consider previous_key to carry out next_key - val is discarded */
+
+#if DB_VERSION_MAJOR >= 2
+	retval = (me->cursor->c_get) (me->cursor, next_key, &val, DB_NEXT);
+#else
+	retval = (me->bdb->seq) (me->bdb, next_key, &val, R_NEXT);
+#endif
+
+	if (retval == 0) {
+                /*
+                 * to ensure reentrancy we do a copy into caller space of what BDB layer returns
+                 */
+		(*next_key) = backend_bdb_kvdup(me, *next_key);
+                };
+
+	return retval;
+};
+
+/* packed rdf_store_counter_t increment */
+rdfstore_flat_store_error_t
+backend_bdb_inc(
+		void *eme,
+		DBT key,
+		DBT * new_value
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	rdf_store_counter_t l = 0;
+	unsigned char   outbuf[256];
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_inc num=%d in '%s'\n", ++(me->num_inc), me->filename);
+#endif
+
+
+	/* it should be atomic with locking here... */
+#if DB_VERSION_MAJOR >= 2
+	memset(new_value, 0, sizeof(*new_value));
+	(*new_value).flags = DB_DBT_MALLOC;
+	if ((((me->bdb)->get) (me->bdb, NULL, &key, new_value, 0)) != 0) {
+		return -1;
+	};
+#else
+	if ((((me->bdb)->get) (me->bdb, &key, new_value, 0)) != 0) {
+		return -1;
+	};
+#endif
+	unpackInt(new_value->data, &l);
+	l++;
+#if DB_VERSION_MAJOR >= 2
+	if ((*new_value).data && (*new_value).size)
+		me->free((*new_value).data);
+#endif
+	(*new_value).data = outbuf;
+	(*new_value).size = sizeof(rdf_store_counter_t);
+	packInt(l, new_value->data);
+
+#ifdef DB_VERSION_MAJOR
+	retval = ((me->bdb)->put) (me->bdb, NULL, &key, new_value, 0);
+#else
+	retval = ((me->bdb)->put) (me->bdb, &key, new_value, 0);
+#endif
+
+	if (retval != 0) {
+		memset(new_value, 0, sizeof(*new_value));
+		(*new_value).data = NULL;
+	} else {
+		(*new_value) = backend_bdb_kvdup(me, *new_value);
+	};
+	return retval;
+};
+
+/* packed rdf_store_counter_t decrement */
+rdfstore_flat_store_error_t
+backend_bdb_dec(
+		void *eme,
+		DBT key,
+		DBT * new_value
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+	rdf_store_counter_t l = 0;
+	unsigned char   outbuf[256];
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_dec num=%d from '%s'\n", ++(me->num_dec), me->filename);
+#endif
+
+
+	/* it should be atomic with locking here... */
+#if DB_VERSION_MAJOR >= 2
+	memset(new_value, 0, sizeof(*new_value));
+	(*new_value).flags = DB_DBT_MALLOC;
+	if ((((me->bdb)->get) (me->bdb, NULL, &key, new_value, 0)) != 0) {
+		return -1;
+	};
+#else
+	if ((((me->bdb)->get) (me->bdb, &key, new_value, 0)) != 0) {
+		return -1;
+	};
+#endif
+	unpackInt(new_value->data, &l);
+	assert(l > 0);
+	l--;
+#if DB_VERSION_MAJOR >= 2
+	if ((*new_value).data && (*new_value).size)
+		me->free((*new_value).data);
+#endif
+	(*new_value).data = outbuf;
+	(*new_value).size = sizeof(rdf_store_counter_t);
+	packInt(l, new_value->data);
+
+#ifdef DB_VERSION_MAJOR
+	retval = ((me->bdb)->put) (me->bdb, NULL, &key, new_value, 0);
+#else
+	retval = ((me->bdb)->put) (me->bdb, &key, new_value, 0);
+#endif
+
+	if (retval != 0) {
+		memset(new_value, 0, sizeof(*new_value));
+		(*new_value).data = NULL;
+	} else {
+		(*new_value) = backend_bdb_kvdup(me, *new_value);
+	};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_bdb_sync(
+		 void *eme
+)
+{
+	backend_bdb_t  *me = (backend_bdb_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_bdb_sync num=%d in '%s'\n", ++(me->num_sync), me->filename);
+#endif
+
+	retval = (me->bdb->sync) (me->bdb, 0);
+#ifdef DB_VERSION_MAJOR
+	if (retval > 0)
+		retval = -1;
+#endif
+	return retval;
+}
+
+int
+backend_bdb_isremote(
+		     void *eme
+)
+{
+	return 0;
+}
+
+/* misc subroutines */
+
+/*
+ * The following compare function are used for btree(s) for basic
+ * XML-Schema data types xsd:integer, xsd:double (and will xsd:date)
+ *
+ * They return:
+ *      < 0 if a < b
+ *      = 0 if a = b
+ *      > 0 if a > b
+ */
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_bdb_compare_int(
+        const DBT *a,
+        const DBT *b ) {
+#else
+static int rdfstore_backend_bdb_compare_int(
+        DB *file,
+        const DBT *a,
+        const DBT *b ) {
+#endif
+        long ai, bi;
+
+        memcpy(&ai, a->data, sizeof(long));
+        memcpy(&bi, b->data, sizeof(long));
+
+        return (ai - bi);
+        };
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_bdb_compare_double(
+        const DBT *a,
+        const DBT *b ) {
+#else
+static int rdfstore_backend_bdb_compare_double(
+        DB *file,
+        const DBT *a,
+        const DBT *b ) {
+#endif
+        double ad,bd;
+
+        memcpy(&ad, a->data, sizeof(double));
+        memcpy(&bd, b->data, sizeof(double));
+
+        if (  ad <  bd ) {
+                return -1;
+        } else if (  ad  >  bd) {
+                return 1;
+                };
+
+        return 0;
+        };
+
+/*
+ * returns null and/or full path to a hashed directory tree. the final
+ * filename is hashed out within that three. Way to complex by now. Lifted
+ * from another project which needed more.
+ */
+static char    *
+mkpath(char *base, char *infile)
+{
+	char           *file;
+	int             i, j;
+	int             last;
+	struct stat     s;
+	char           *slash, *dirname;
+	char           *inpath;
+	static char     tmp[MAXPATHLEN];
+	char            tmp2[MAXPATHLEN];
+#define MAXHASH 2
+	static char     hash[MAXHASH + 1];
+
+	tmp[0] = '\0';
+
+	strcpy(inpath = tmp2, infile);
+
+	memset(hash, '_', MAXHASH);
+	hash[MAXHASH] = '\0';
+
+	if (base == NULL)
+		base = "./";
+
+	if (inpath == NULL || inpath[0] == '\0') {
+		fprintf(stderr, "No filename or path for the database specified\n");
+		return NULL;
+	};
+
+	/*
+	 * remove our standard docroot if present so we can work with
+	 * something relative. really a legacy thing from older perl DBMS.pm
+	 * versions. Can go now.
+	 */
+	if (!(strncmp(base, inpath, strlen(base))))
+		inpath += strlen(base);
+
+	/*
+	 * fetch the last leaf name
+	 */
+	if ((file = strrchr(inpath, '/')) != NULL) {
+		*file = '\0';
+		file++;
+	} else {
+		file = inpath;
+		inpath = "/";
+	};
+
+	if (!strlen(file)) {
+		fprintf(stderr, "No filename for the database specified\n");
+		return NULL;
+	};
+
+	strncpy(hash, file, MIN(strlen(file), MAXHASH));
+
+	/*
+	        strcpy(tmp,"./");
+	*/
+	strcat(tmp, base);
+	strcat(tmp, "/");
+	strcat(tmp, inpath);
+	strcat(tmp, "/");
+	strcat(tmp, hash);
+	strcat(tmp, "/");
+	strcat(tmp, file);
+
+	if ((slash = strrchr(tmp, '.')) != NULL) {
+		if ((!strcasecmp(slash + 1, "db")) ||
+		    (!strcasecmp(slash + 1, "dbm")) ||
+		    (!strcasecmp(slash + 1, "gdb"))
+			)
+			*slash = '\0';
+	};
+
+	strcat(tmp, ".db");
+
+	for (i = 0, j = 0; tmp[i]; i++) {
+		if (i && tmp[i] == '/' && tmp[i - 1] == '/')
+			continue;
+		if (i != j)
+			tmp[j] = tmp[i];
+		j++;
+	};
+	tmp[j] = '\0';
+
+	dirname = tmp;
+
+	/* Skip leading './'. */
+	if (dirname[0] == '.')
+		++dirname;
+	if (dirname[0] == '/')
+		++dirname;
+
+	for (last = 0; !last; ++dirname) {
+		if (dirname[0] == '\0')
+			break;
+		else if (dirname[0] != '/')
+			continue;
+		*dirname = '\0';
+		if (dirname[1] == '\0')
+			last = 1;
+
+		/*
+		 * check if tmp exists and is a directory (or a link to one..
+		 * if not, create it, else give an error
+		 */
+		if (stat(tmp, &s) == 0) {
+			/*
+			 * something exists.. it must be a directory
+			 */
+			if ((s.st_mode & S_IFDIR) == 0) {
+				fprintf(stderr, "Creation of %s failed; path element not directory\n", tmp);
+				return NULL;
+			};
+		} else if (errno == ENOENT) {
+			if ((mkdir(tmp, (S_IRWXU | S_IRWXG | S_IRWXO))) != 0) {
+				fprintf(stderr, "Creation of %s failed; %s\n", tmp, strerror(errno));
+				return NULL;
+			};
+		} else {
+			fprintf(stderr, "Path creation to failed at %s:%s\n", tmp, strerror(errno));
+			return NULL;
+		};
+		if (!last)
+			*dirname = '/';
+	}
+
+	return tmp;
+}
+
+#define BDB_VERSION (100)
+DECLARE_MODULE_BACKEND(backend_bdb, "BerkelyDB", BDB_VERSION)

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_caching_store.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_caching_store.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_caching_store.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_caching_store.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,1055 @@
+/*
+##############################################################################
+# 	Copyright (c) 2000-2006 All rights reserved
+# 	Alberto Reggiori <ar...@webweaving.org>
+#	Dirk-Willem van Gulik <di...@webweaving.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The end-user documentation included with the redistribution,
+#    if any, must include the following acknowledgment:
+#       "This product includes software developed by
+#        Alberto Reggiori <ar...@webweaving.org> and
+#        Dirk-Willem van Gulik <di...@webweaving.org>."
+#    Alternately, this acknowledgment may appear in the software itself,
+#    if and wherever such third-party acknowledgments normally appear.
+#
+# 4. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#    This product includes software developed by the University of
+#    California, Berkeley and its contributors.
+#
+# 5. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# 6. Products derived from this software may not be called "RDFStore"
+#    nor may "RDFStore" appear in their names without prior written
+#    permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# ====================================================================
+#
+# This software consists of work developed by Alberto Reggiori and
+# Dirk-Willem van Gulik. The RDF specific part is based based on public
+# domain software written at the Stanford University Database Group by
+# Sergey Melnik. For more information on the RDF API Draft work,
+# please see <http://www-db.stanford.edu/~melnik/rdf/api.html>
+# The DBMS TCP/IP server part is based on software originally written
+# by Dirk-Willem van Gulik for Web Weaving Internet Engineering m/v Enschede,
+# The Netherlands.
+#
+##############################################################################
+#
+# $Id: backend_caching_store.c,v 1.13 2006/06/19 10:10:21 areggiori Exp $
+*/
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+
+#include "rdfstore_flat_store.h"
+#include "rdfstore_log.h"
+#include "rdfstore.h"
+
+#include "backend_store.h"
+#include "backend_caching_store.h"
+
+#include "backend_bdb_store.h"
+#include "backend_dbms_store.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+typedef struct backend_caching_struct {
+	char * name;				/* name - for debugging */
+	backend_store_t	 * store;		/* the real store */
+	void * 		   instance;		/* instance of the real store */
+	struct caching_store_rec * cache;	/* My cache */
+
+        void (* free)(void * adr);              
+        void * (* malloc)(size_t size);
+	} backend_caching_t;
+
+typedef enum { UNDEF, EXISTS, CHANGED, NOTFOUND, DELETED } cstate;
+
+/* as refered to above as * data */
+typedef struct data_rec {			/* Payload of the cache */
+	DBT 		key,val;		
+	cstate		state;			/* Cache positives and negatives */
+} data_t;
+
+/* forward declarations */
+static int _dup(void * conf, void * from, void * * to);
+static int _store(void * conf, void * data);
+static int _delete(void * conf, void * data);
+static int _fetch(void * conf, void * data, void ** dout);
+static int _cmp(const void *a, const void *b);
+
+
+/* Caching infrastructure:
+ *
+ * Up to maxcache keys are cached.
+ *
+ * --> head->*cdll_t
+ * 	circular double linked list - element pointed to by head
+ *	was the most recently used.
+ * --> idx
+ *      sorted list circular double linked list elements - sorted
+ *	by their 'data's key.
+ */
+
+/* START of Fairly generic caching section.. */
+
+#ifndef DEFAULTMAXCACHE
+#define DEFAULTMAXCACHE (1000)
+#endif
+
+/* Element in a circular double linked list */
+typedef struct cdll_rec {
+	void * data;				/* data payload -- actual stuff we cache */
+
+	unsigned int cnt;			/* counter - for debugging */
+
+	struct cdll_rec * prev;
+	struct cdll_rec * nxt;
+} cdll_t;
+
+typedef struct caching_store_rec {
+	char * name;				/* name - for debugging */
+	void * conf;				/* Callee's own book keeping */
+
+	int hit,miss,drop;
+
+	unsigned int 	maxcache;		/* Max numer of keys to cache. */
+	unsigned int	cached;			/* Currently cached */
+	cdll_t * * 	idx;			/* Sorted list (on keys) */
+
+	struct cdll_rec * head;		/* Start of the circular double linked list. */
+
+        void (* free)(void * adr);              
+        void * (* malloc)(size_t size);
+
+	/* Comparison functions specific to the data 
+	 */
+	int (*cmp)(const void * a, const void * b);	
+
+	/* fetch/store functions specific to the data 
+	 */
+	int (*fetch)(void * conf, void * data, void ** out);	/* implies dup into new out */
+	int (*store)(void * conf, void * data);
+	int (*delete)(void * conf, void * data);
+
+	/* Create a copy into existence, or drop it. */
+	int (*dup)(void * conf, void * from, void * * to);	/* malloc and cpy */
+	int (*cpy)(void * conf, void * from, void * to);	/* just copy refs */
+	int (*drp)(backend_caching_t * me, void * conf, void * data);
+	
+	} caching_store_t;
+
+typedef enum { BC_READ, BC_WRITE, BC_EXISTS, BC_DELETE } bc_ops;
+
+static int cmp_pair(const void * a, const void * b);
+static int cmp_key(const void * in, const void * pair);
+
+static int 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)
+	)
+{
+	me->maxcache = max_cache_nelems ? max_cache_nelems : DEFAULTMAXCACHE;
+
+	me->idx = (cdll_t **) (*cachingmalloc)( sizeof((*(me->idx))) * me->maxcache );
+	if (me->idx == NULL)
+		return -1;
+
+	memset(me->idx, 0, sizeof((*(me->idx))) * me->maxcache );
+
+	me->cached = 0;
+	me->head = NULL;
+
+	me->hit = me->miss = me->drop = 0;
+
+	me->cmp = cmp;	
+	me->fetch = fetch;
+	me->store = store;
+	me->delete = delete;
+	me->dup = dup;
+	me->cpy = cpy;
+	me->drp = drp;
+	me->name = (char *)(*cachingmalloc)( strlen(name)+1 );
+	if( me->name == NULL )
+		return -1;
+	strcpy( me->name, name );
+	me->conf = conf;
+
+	me->free = cachingfree;
+	me->malloc = cachingmalloc;
+
+	return 0;
+}
+
+/* iswrite == 1
+ *	cache key+val
+ * iswrite == 0
+ *	if cached - update val
+ *	otherwise fetch from backend
+ *		and cache - update val
+ */
+
+const char * _x(DBT v) {
+	int i;
+	if (v.size == 4) return "<int>";
+	for(i=0;i<v.size;i++)
+		if ((((char *)(v.data))[i]) && (((((char *)(v.data))[i])< 32) || ( ((((char *)(v.data))[i])>126))))
+			return "<bin>";
+	return (char *)(v.data);
+}
+
+int cachekey(backend_caching_t * mme, caching_store_t * me, void * data, void ** out, bc_ops op) 
+{
+	cdll_t * * i = NULL;
+	int e = 0;
+
+#if 0
+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);
+#endif
+	/* Check if this key is already cached */
+	if (me->cached > 0)
+		i = (cdll_t **)bsearch( (void *) data, me->idx, me->cached, sizeof(cdll_t *), &cmp_key);
+#if  0
+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"); };
+#endif
+
+	/* Add this to the cache if it is a new key */
+	if (!i) {
+		/* Remove last key if cache is already full. */
+#if 0
+fprintf(stderr,"Cache miss\n");
+#endif
+		me->miss++;
+		if (me->cached >= me->maxcache) {
+			/* Remove from the tail */
+			cdll_t * last = me->head->prev;
+			me->head = last->nxt;
+			me->head->prev = last->prev;
+			me->head->prev->nxt = me->head;
+
+			/* find the corresponding entry in the idx - as this is the slot which we will
+			 * reuse (to save a malloc) for the new key.
+			 */
+			i = (cdll_t **)bsearch((void *)(last->data), me->idx, me->cached, sizeof(cdll_t *), &cmp_key);
+			assert(i);
+
+			/* allow the backend to store and drop it */
+			me->store(me->conf,last->data);
+			me->drp(mme, me->conf,last->data);
+			me->drop++;
+		} else {
+			/* Still space - add it to the end of the IDX */
+			if ((me->idx[ me->cached ] = me->malloc(sizeof(cdll_t))) == NULL) {
+				return -1;
+			};
+			i = &(me->idx[ me->cached ]);
+			me->cached ++;
+		};
+
+		switch(op) {
+		case BC_WRITE: 	/* DUP our new item into it */
+			me->dup(me->conf, data, &((*i)->data));
+			break;
+		case BC_DELETE:
+			me->dup(me->conf, data, &((*i)->data));
+			e = me->delete(me->conf, (*i)->data);
+			break;
+		case BC_READ:
+		case BC_EXISTS:
+			e = me->fetch(me->conf, data, &((*i)->data));
+			break;
+		default:
+			assert(0);
+			break;
+		};
+
+		/* virig item. */
+		(*i)->cnt = 0;
+
+		/* And insert our item at the head */
+		if( me->head ) {
+			(*i)->nxt = me->head;
+			(*i)->prev = me->head->prev;
+			me->head->prev->nxt = *i;
+			me->head->prev = *i;
+		} else {
+			(*i)->nxt = *i;
+			(*i)->prev= *i;
+		}
+		/* And update the head pointer */
+		me->head = *i;
+		
+		/* and sort the list again  -- XXXX note this should be replaced
+	 	 * by a binary search and a N-shift/insert (ordered insertion search)
+		 * at some point.
+		 */
+		if (me->cached > 1)
+			qsort(me->idx,me->cached,sizeof(cdll_t*),&cmp_pair);
+	} else {
+#if 0
+fprintf(stderr,"Cache hit\n");
+#endif
+		me->hit++;
+		/* if not already in front - move to the front 
+		 */
+		if (me->head && (me->head != *i)) {
+			/* remove item from the list */
+			(*i)->nxt->prev = (*i)->prev;
+			(*i)->prev->nxt = (*i)->nxt;
+
+			/* squeeze it in at head */
+			(*i)->nxt = me->head;
+			(*i)->prev = me->head->prev;
+			me->head->prev->nxt = *i;
+			me->head->prev = *i;
+
+			/* move head to the right place */
+			me->head = *i;
+		}
+		/* If it is a write through - update the value if it has changed.
+		 */
+		switch(op) {
+		case BC_WRITE:
+if (0) fprintf(stderr,"Write through\n");
+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)));
+
+			me->drp(mme, me->conf, (*i)->data);		/* drop the old value */
+			me->dup(me->conf, data, &((*i)->data));	/* replace by the new one */
+			break;
+		case BC_DELETE:
+			me->dup(me->conf, data, &((*i)->data));
+			e = me->delete(me->conf, (*i)->data);
+			break;
+		case BC_EXISTS:
+		case BC_READ:
+			break;
+		default:
+			assert(0);
+		}
+		(*i)->cnt ++;
+	}
+
+	switch(op) {
+	case BC_EXISTS: 	/* exists */
+		me->cpy(me->conf,me->head->data,data);
+		break;
+	case BC_DELETE:		/* no need to update */
+	case BC_WRITE:		/* no need to update */
+		break;
+	case BC_READ: 		/* update data - so the callee can use it */
+		me->dup(me->conf,me->head->data,out);
+		break;
+	default:	
+		/* error really */
+		assert(0);
+		break;
+	}
+#if 0
+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"); };
+#endif
+	return e;
+}
+
+void stats(caching_store_t *me) 
+{
+	fprintf(stderr,"%s: hit: %d miss: %d drop: %d\n",me->name,me->hit,me->miss,me->drop);
+}
+
+void purgecache(backend_caching_t   *me, caching_store_t *c) 
+{
+	cdll_t * p;
+	if (c->head == NULL)
+		return;
+
+	for(p=c->head;;) {
+		cdll_t * q = p;
+		p=p->nxt;
+		c->store(c->conf,q->data);
+		c->drp(me, c->conf,q->data);
+		(*(me->free))(q);
+		if (p == c->head)
+			break;
+	}
+	c->head = NULL;
+	c->cached = 0;
+}
+
+static int cmp_pair(const void * a, const void * b) 
+{	
+	return _cmp((*(cdll_t**) a)->data,(*(cdll_t**) b)->data);
+}
+
+static int cmp_key(const void * in, const void * pair) 
+{
+	return _cmp(in, (*((cdll_t**) pair))->data );
+}
+/* END of caching code */
+
+static int _cmp(const void *a, const void *b)
+{
+	DBT * k = &(((data_t *)a)->key);
+	DBT * l = &(((data_t *)b)->key);
+
+	int c;
+
+	if ((a == NULL) || (b == NULL)) {
+		if (a == NULL) 
+			return (b == NULL) ? 0 : -1;
+		else
+			return (b == NULL) ? 0 : +1;
+	};
+
+	c = memcmp(k->data,l->data,MIN(k->size,l->size));
+
+	if (c)
+		return c;
+
+	if (k->size < l->size)
+		return -1;
+
+	if (k->size > l->size)
+		return +1;
+
+	return 0;
+}
+
+static int _fetch(void * conf, void * data, void ** dout)
+{
+	backend_caching_t   *me = (backend_caching_t *) conf;
+	data_t * in = (data_t *) data;
+	data_t ** out = (data_t **) dout;
+	int e;
+
+	if (_dup(conf, (void *)in, (void **)out))
+		return -1;
+
+	e = (me->store->fetch)(me->instance,in->key,&((*out)->val));
+
+	/* Cache both positives and negatives. */
+	switch(e) {
+	case 0:				/* found - no error */
+		(*out)->state = EXISTS;
+		break;
+	case FLAT_STORE_E_NOTFOUND:	/* not found - but not an error */
+		(*out)->state = NOTFOUND;
+		e = 0;
+		break;
+	default:
+		/* keep error code */
+		fprintf(stderr,"DEBUG -- error %d\n",e);
+	}
+if (0) fprintf(stderr,"BE fetch %s - returning %d - and exists is %d\n",
+		_x((*out)->key),e,(*out)->state);
+	return e;
+}
+
+static int _store(void * conf, void * data)
+{
+	backend_caching_t   *me = (backend_caching_t *) conf;
+	data_t * in = (data_t *) data;
+	int e;
+
+	if (in->state != CHANGED)
+		return 0;
+
+	e = (me->store->store)(me->instance,in->key,in->val);
+	switch(e) {
+	case 0:
+		/* ignore */
+		break;
+	case FLAT_STORE_E_KEYEXIST:
+		/* XXXXXXXXXXXXXXXXXXXXXXXXX we lose track of this ****XXXXXXXXXXXXXXXXX */
+		e = 0;
+		break;
+	default:
+		/* keep error code */
+		break;
+	}
+	return e;
+}
+
+static int _delete(void * conf, void * data)
+{
+	backend_caching_t   *me = (backend_caching_t *) conf;
+	data_t * in = (data_t *) data;
+	int e = (me->store->delete)(me->instance,in->key);	/* xxx we could also do this on a purge.. */
+	switch(e) {
+	case 0:
+		/* ignore */
+		break;
+	case FLAT_STORE_E_KEYEXIST:
+		e = 0;
+		break;
+	default:
+		/* keep error code */
+		break;
+	}
+	in->state = NOTFOUND;	/* set to DELETE and do later on purge ?? */
+	return e;
+}
+
+static int _cpy(void * conf, void * from, void * to)
+{
+	*(data_t *)to = *(data_t *)from;
+	return 0;
+}
+
+static int _dup(void * conf, void * from, void * * to)
+{
+	backend_caching_t   *me = (backend_caching_t *) conf;
+	data_t * p = (data_t *) from;
+	data_t * q;
+
+	if (!(q = me->malloc(sizeof(data_t))))
+		return -1;
+	
+	memset(&(q->key),0,sizeof(q->key));
+	memset(&(q->val),0,sizeof(q->val));
+
+	if (p->key.data) {
+		if (!(q->key.data = me->malloc(p->key.size)))
+			return -1;
+		bcopy(p->key.data,q->key.data,p->key.size);
+		q->key.size = p->key.size;
+	} else {
+		q->key.data = NULL;
+		q->key.size = 0;
+	}
+
+	if (p->val.data) {
+		if (!(q->val.data = me->malloc(p->val.size)))
+			return -1;
+		bcopy(p->val.data,q->val.data,p->val.size);
+		q->val.size = p->val.size;
+	} else {
+		q->val.data = NULL;
+		q->val.size = 0;
+	}
+
+	q->state = p->state ;
+
+#if 0
+if (0) fprintf(stderr,"DUPed %s(%d,%d)==%s(%d,%d) exists=%d/%d\n",
+		_x(p->key), p->key.size,p->val.size,
+		_x(q->key), q->key.size,q->val.size,
+		p->state, q->state);
+#endif
+
+	*to = q;
+	return 0;
+}
+
+static int _drp(backend_caching_t * me, void * conf, void * data)
+{
+	data_t * p = (data_t *) data;
+	if (p->key.data) 
+		(*(me->free))(p->key.data);
+	if (p->val.data) 
+		(*(me->free))(p->val.data);
+	(*(me->free))(p);
+	return 0;
+}
+
+/*
+ * Some default call back functions.
+ */
+static void
+default_myfree(void *adr)
+{
+	RDFSTORE_FREE(adr);
+}
+static void    *
+default_mymalloc(size_t x)
+{
+	return RDFSTORE_MALLOC(x);
+}
+static void
+default_myerror(char *err, int erx)
+{
+	fprintf(stderr, "backend_caching_ Error[%d]: %s\n", erx, err);
+}
+
+void
+backend_caching_set_error(
+		       void *eme,
+		       char *msg,
+		       rdfstore_flat_store_error_t erx)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	(me->store->set_error)(me->instance,msg,erx);
+}
+
+char           *
+backend_caching_get_error(void *eme)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	return (me->store->get_error)(me->instance);
+}
+
+/* clone a key or value for older BDB */
+DBT
+backend_caching_kvdup(
+		   void *eme,
+		   DBT data)
+{
+	backend_caching_t  * me = (backend_caching_t *) eme;
+	return (me->store->kvdup)(me->instance,data);
+}
+
+void
+backend_caching_reset_debuginfo(
+			     void *eme
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	(me->store->reset_debuginfo)(me->instance);
+}
+
+/*
+ * NOTE: all the functions return 0 on success and non zero value if error
+ * (see above and include/backend_caching_.h for known error codes)
+ */
+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
+)
+{
+	backend_caching_t   **mme = (backend_caching_t **) emme;
+	backend_caching_t   *me;
+	char buff[1024];
+	int err;
+
+	*mme = NULL;
+
+	if (_my_error == NULL)
+		_my_error = default_myerror;
+
+	if (_my_malloc == NULL)
+		_my_malloc = default_mymalloc;
+
+	if (_my_free == NULL)
+		_my_free = default_myfree;
+
+	me = (backend_caching_t *) _my_malloc(sizeof(backend_caching_t));
+	if (me == NULL) {
+		perror("backend_caching_open");
+		return FLAT_STORE_E_NOMEM;
+	};
+
+	snprintf(buff,sizeof(buff)-1,"%p@%s:%d/%s/%s",
+		me,
+		host ? host : "<nohost>",
+		port ? port : 0,
+		dir ? dir : "<nodir>",
+		name ? name : "<inmemory>"
+	);
+	me->name = (char *)(*_my_malloc)( strlen(buff)+1 );
+	if( me->name == NULL )
+		return -1;
+	strcpy( me->name, buff );
+
+	me->malloc = _my_malloc;
+	me->free = _my_free;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	backend_caching_reset_debuginfo(me);
+#endif
+
+        switch (remote & 0xF) {
+        case 0:
+                me->store = backend_bdb;
+                break;
+        case 1:
+                me->store = backend_dbms;
+                break;
+        default:
+                perror("Backend type is not available");
+                return FLAT_STORE_E_NOMEM;
+                break;
+        };
+
+	/* Map to the real backend. */
+        err = (*(me->store->open)) (
+                                remote & 0xF, ro, (void **) &(me->instance),
+                                dir, name, local_hash_flags, host, port,
+                               _my_malloc, _my_free, _my_report, _my_error,
+				bt_compare_fcn_type
+        );
+        if (err) {
+                (*_my_free) (me);
+                return err;
+        }
+        me->free = _my_free;
+
+	me->cache = (caching_store_t *)me->malloc(sizeof(caching_store_t));
+
+	/* Init with default cache size */
+	init_cachingstore(me->cache,0,
+		/* Functions to manage 'my' data */
+		me,
+		buff,
+		&_cmp,
+		&_fetch,
+		&_store,
+		&_delete,
+		&_dup,
+		&_cpy,
+		&_drp,
+		me->free,
+		me->malloc
+	);
+
+	* mme = me;
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	if (0) fprintf(stderr, "backend_caching_open '%s'\n", me->filename);
+#endif
+	return 0;
+}
+
+rdfstore_flat_store_error_t
+backend_caching_close(
+		   void *eme
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	int e;
+if (0) fprintf(stderr,"%s: close\n",me->name);
+	purgecache(me, me->cache);
+	stats(me->cache);
+	e = (me->store->close)(me->instance);
+
+	me->free(me->name);
+	me->free(me->cache);
+	me->free(me);
+
+	return e;
+};
+
+rdfstore_flat_store_error_t
+backend_caching_fetch(
+		   void *eme,
+		   DBT key,
+		   DBT * val
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	data_t  d, * out = NULL;
+	int e;
+
+#if 0
+fprintf(stderr,"%s: fetch %s(%d,%d)\n",me->name,_x(key),(int)key.size,(int)val->size);
+#endif
+
+	/* Build a record */
+	d.key = key;
+	memset(&(d.val),0,sizeof(d.val));
+	d.val.data =NULL;
+	d.val.size = 0;
+	d.state = UNDEF;	/* unkown */
+
+	if ((e = cachekey(me, me->cache,&d,(void **)&out, BC_READ))) {
+		return e;
+	}
+
+	val->data = out->val.data;
+	val->size = out->val.size;
+
+#if 0
+if (0) fprintf(stderr,"Cachekey returned e=%d and exits=%d val=%p,%d\n",e,out->state,val->data,val->size);
+#endif
+
+	if (out->state == NOTFOUND) {
+		me->free(out);
+		return FLAT_STORE_E_NOTFOUND;
+	};
+
+	if (out->key.data)
+		me->free(out->key.data);
+	me->free(out); 
+
+	return 0;
+}
+
+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
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	return (me->store->fetch_compressed)(me->instance,func_decode,key,outsize_p,outchar);
+}
+
+rdfstore_flat_store_error_t
+backend_caching_store(
+		   void *eme,
+		   DBT key,
+		   DBT val
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	data_t d;
+	int e;
+
+        d.key = key;
+        d.val = val;
+        d.state = CHANGED;   
+
+	e = cachekey(me, me->cache,&d,NULL,BC_WRITE);
+#if 0
+fprintf(stderr,"%s: store %s(%d,%d) E=%d\n",me->name,_x(key),(int)key.size,(int)val.size,e);
+#endif
+	return e;
+}
+
+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
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	return (me->store->store_compressed)(me->instance,func_decode,key,insize,inchar,outbuff);
+}
+
+rdfstore_flat_store_error_t
+backend_caching_exists(
+		    void *eme,
+		    DBT key
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	data_t  d;
+	int e;
+
+	/* Build a record */
+	d.key = key;
+	memset(&(d.val),0,sizeof(d.val));
+	d.val.data =NULL;
+	d.val.size = 0;
+	d.state = UNDEF;	/* unkown */
+
+	e = cachekey(me, me->cache,&d,NULL, BC_EXISTS);
+
+if (0) fprintf(stderr,"%s: exists %s ==> e=%d and d.exists=%d\n",me->name,_x(key),e,d.state);
+
+	if (e) 
+		return e;
+
+
+	return (d.state == EXISTS || d.state == CHANGED) ? 0 : FLAT_STORE_E_NOTFOUND;
+}
+
+rdfstore_flat_store_error_t
+backend_caching_delete(
+		    void *eme,
+		    DBT key
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	data_t d;
+if (0) fprintf(stderr,"%s: delete\n",me->name);
+	
+	d.key = key;
+	memset(&(d.val),0,sizeof(d.val));
+	d.state = UNDEF;
+	
+	return cachekey(me, me->cache,&d,NULL, BC_DELETE);
+};
+
+rdfstore_flat_store_error_t
+backend_caching_clear(
+		   void *eme
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+if (0) fprintf(stderr,"%s: clear\n",me->name);
+assert(0);
+	return (me->store->clear)(me->instance);
+}
+
+rdfstore_flat_store_error_t
+backend_caching_from(
+		   void *eme,
+		   DBT closest_key,
+		   DBT * key
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+if (0) fprintf(stderr,"%s: from\n",me->name);
+	purgecache(me, me->cache);
+	return (me->store->from)(me->instance,closest_key,key);
+}
+
+rdfstore_flat_store_error_t
+backend_caching_first(
+		   void *eme,
+		   DBT * first_key
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+if (0) fprintf(stderr,"%s: first\n",me->name);
+	purgecache(me, me->cache);
+	return (me->store->first)(me->instance,first_key);
+}
+
+rdfstore_flat_store_error_t
+backend_caching_next(
+		  void *eme,
+		  DBT previous_key,
+		  DBT * next_key
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+if (0) fprintf(stderr,"%s: next\n",me->name);
+	purgecache(me, me->cache);
+	return (me->store->next)(me->instance,previous_key,next_key);
+}
+
+/* packed rdf_store_counter_t increment */
+rdfstore_flat_store_error_t
+backend_caching_inc(
+		 void *eme,
+		 DBT key,
+		 DBT * new_value
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+        rdf_store_counter_t l = 0;
+	int e;
+	memset(new_value, 0, sizeof(*new_value));
+#if 0
+fprintf(stderr,"%s: inc %s\n",me->name,_x(key));
+#endif
+
+	e = backend_caching_fetch(eme,key,new_value);
+	if (e) 
+		return e;
+
+        unpackInt(new_value->data, &l);
+	l++;
+        packInt(l, new_value->data);
+
+	if ((e = backend_caching_store(eme,key,*new_value))) {
+		memset(new_value, 0, sizeof(*new_value));
+	} else {
+		(*new_value) = backend_caching_kvdup(me, *new_value);
+	}
+	return e;
+}
+
+/* packed rdf_store_counter_t decrement */
+rdfstore_flat_store_error_t
+backend_caching_dec(
+		 void *eme,
+		 DBT key,
+		 DBT * new_value
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+        rdf_store_counter_t l = 0;
+	int e;
+
+	memset(new_value, 0, sizeof(*new_value));
+
+if (0) fprintf(stderr,"%s: dec\n",me->name);
+	e = backend_caching_fetch(eme,key,new_value);
+	if (e) 
+		return e;
+
+        unpackInt(new_value->data, &l);
+	l--;
+        packInt(l, new_value->data);
+
+	if ((e = backend_caching_store(eme,key,*new_value))) {
+		memset(new_value, 0, sizeof(*new_value));
+	} else {
+		(*new_value) = backend_caching_kvdup(me, *new_value);
+	}
+
+	return e;
+}
+
+rdfstore_flat_store_error_t
+backend_caching_sync(
+		  void *eme
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+if (0) fprintf(stderr,"%s: sync\n",me->name);
+	purgecache(me, me->cache);
+	return (me->store->sync)(me->instance);
+}
+
+int
+backend_caching_isremote(
+		      void *eme
+)
+{
+	backend_caching_t   *me = (backend_caching_t *) eme;
+	return (me->store->isremote)(me->instance);
+}
+
+
+#define CACHING_VERSION (100)
+DECLARE_MODULE_BACKEND(backend_caching, "Caching", CACHING_VERSION)
+

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_dbms_store.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_dbms_store.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_dbms_store.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/backend_dbms_store.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,695 @@
+/*
+##############################################################################
+# 	Copyright (c) 2000-2006 All rights reserved
+# 	Alberto Reggiori <ar...@webweaving.org>
+#	Dirk-Willem van Gulik <di...@webweaving.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+#
+# 3. The end-user documentation included with the redistribution,
+#    if any, must include the following acknowledgment:
+#       "This product includes software developed by
+#        Alberto Reggiori <ar...@webweaving.org> and
+#        Dirk-Willem van Gulik <di...@webweaving.org>."
+#    Alternately, this acknowledgment may appear in the software itself,
+#    if and wherever such third-party acknowledgments normally appear.
+#
+# 4. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#    This product includes software developed by the University of
+#    California, Berkeley and its contributors.
+#
+# 5. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# 6. Products derived from this software may not be called "RDFStore"
+#    nor may "RDFStore" appear in their names without prior written
+#    permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# ====================================================================
+#
+# This software consists of work developed by Alberto Reggiori and
+# Dirk-Willem van Gulik. The RDF specific part is based based on public
+# domain software written at the Stanford University Database Group by
+# Sergey Melnik. For more information on the RDF API Draft work,
+# please see <http://www-db.stanford.edu/~melnik/rdf/api.html>
+# The DBMS TCP/IP server part is based on software originally written
+# by Dirk-Willem van Gulik for Web Weaving Internet Engineering m/v Enschede,
+# The Netherlands.
+#
+##############################################################################
+#
+# $Id: backend_dbms_store.c,v 1.10 2006/06/19 10:10:21 areggiori Exp $
+*/
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+
+#include "db.h"
+
+#include "rdfstore_flat_store.h"
+#include "rdfstore_log.h"
+#include "rdfstore.h"
+
+#include "backend_store.h"
+#include "backend_dbms_store.h"
+#include "backend_dbms_store_private.h"
+
+/* dbms_store error management */
+static char     _dbms_store_erm[256] = "\0";
+
+/* human-readable error codes */
+static char    *dbms_store_error[] = {
+	/* FLAT_STORE_E_UNDEF         2000 */
+	"Not defined",
+	/* FLAT_STORE_E_NONNUL        2001 */
+	"Undefined Error",
+	/* FLAT_STORE_E_NOMEM         2002 */
+	"Out of memory",
+	/* FLAT_STORE_E_NOPE          2003 */
+	"No such database",
+	/* FLAT_STORE_E_KEYEMPTY      2004 */
+	"Key/data deleted or never created",
+	/* FLAT_STORE_E_KEYEXIST      2005 */
+	"The key/data pair already exists",
+	/* FLAT_STORE_E_NOTFOUND      2006 */
+	"Key/data pair not found",
+	/* FLAT_STORE_E_OLD_VERSION   2007 */
+	"Out-of-date version",
+	/* FLAT_STORE_E_DBMS          2008 */
+	"DBMS error",
+	/* FLAT_STORE_E_CANNOTOPEN    2009 */
+	"Cannot open database",
+	/* FLAT_STORE_E_BUG           2010 */
+	"Conceptual error"
+};
+
+/*
+ * Some default call back functions.
+ */
+static void
+default_myfree(void *adr)
+{
+	RDFSTORE_FREE(adr);
+}
+static void    *
+default_mymalloc(size_t x)
+{
+	return RDFSTORE_MALLOC(x);
+}
+static void
+default_myerror(char *err, int erx)
+{
+	fprintf(stderr, "backend_dbms_ Error[%d]: %s\n", erx, err);
+}
+
+void
+backend_dbms_set_error(
+		       void *eme,
+		       char *msg,
+		       rdfstore_flat_store_error_t erx)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	bzero(me->err, sizeof(me->err));
+	if (erx == FLAT_STORE_E_DBMS) {
+		snprintf(me->err, sizeof(me->err), "DBMS Error %s: %s\n", msg,
+			 errno == 0 ? "" : (strlen(strerror(errno)) <= sizeof(me->err)) ? strerror(errno) : "");	/* not enough... */
+	} else {
+		if ((erx > FLAT_STORE_E_UNDEF) && (erx <= FLAT_STORE_E_BUG)) {
+			strcpy(me->err, dbms_store_error[erx - FLAT_STORE_E_UNDEF]);
+		} else {
+			if (strlen(strerror(erx)) <= sizeof(me->err))
+				strcpy(me->err, strerror(erx));
+		};
+	};
+	if (strlen(me->err) <= sizeof(_dbms_store_erm))
+		strcpy(_dbms_store_erm, me->err);
+
+#ifdef VERBOSE
+	if (me->error)
+		(*(me->error)) (me->err, erx);
+#endif
+}
+
+
+char           *
+backend_dbms_get_error(void *eme)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	if (me == NULL)
+		return _dbms_store_erm;
+	else
+		return me->err;
+}
+
+/* clone a key or value for older BDB */
+DBT
+backend_dbms_kvdup(
+		   void *eme,
+		   DBT data)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	DBT             dup;
+	memset(&dup, 0, sizeof(dup));
+
+	if (data.size == 0) {
+		dup.data = NULL;
+		return dup;
+	};
+
+	dup.size = data.size;
+
+	if ((dup.data = (char *) me->malloc(data.size + 1)) != NULL) {
+		memcpy(dup.data, data.data, data.size);
+		memcpy(dup.data + data.size, "\0", 1);
+	};
+
+	return dup;
+};
+
+void
+backend_dbms_reset_debuginfo(
+			     void *eme
+)
+{
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	me->num_store = 0;
+	me->num_fetch = 0;
+	me->num_inc = 0;
+	me->num_dec = 0;
+	me->num_sync = 0;
+	me->num_next = 0;
+	me->num_from = 0;
+	me->num_first = 0;
+	me->num_delete = 0;
+	me->num_clear = 0;
+	me->num_exists = 0;
+#endif
+}
+
+/*
+ * NOTE: all the functions return 0 on success and non zero value if error
+ * (see above and include/backend_dbms_.h for known error codes)
+ */
+rdfstore_flat_store_error_t
+backend_dbms_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
+)
+{
+	dbms_store_t   **mme = (dbms_store_t **) emme;
+	dbms_store_t   *me;
+	char           *buff;
+
+	*mme = NULL;
+
+	if (_my_error == NULL)
+		_my_error = default_myerror;
+
+	if (_my_malloc == NULL)
+		_my_malloc = default_mymalloc;
+
+	if (_my_free == NULL)
+		_my_free = default_myfree;
+
+	me = (dbms_store_t *) _my_malloc(sizeof(dbms_store_t));
+	if (me == NULL) {
+		perror("backend_dbms_open");
+		return FLAT_STORE_E_NOMEM;
+	};
+
+	me->error = _my_error;
+	bzero(me->err, sizeof(me->err));
+	me->malloc = _my_malloc;
+	me->free = _my_free;
+
+	if (_my_report != NULL)
+		me->callback = _my_report;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	backend_dbms_reset_debuginfo(me);
+#endif
+
+	if (!remote) {
+		backend_dbms_set_error(me, "DBMS can only be remote", FLAT_STORE_E_CANNOTOPEN);
+		perror("backend_dbms_open");
+		_my_free(me);
+		return FLAT_STORE_E_CANNOTOPEN;
+	};
+
+	if ((dir) &&
+	    (name)) {
+		strcpy(me->filename, dir);
+		strcat(me->filename, "/");
+		strcat(me->filename, name);
+	} else {
+		strcpy(me->filename, "\0");
+		buff = NULL;
+	};
+
+	if (((me->dbms = dbms_connect(
+				      me->filename,
+				      host, port,
+		   ((ro == 0) ? (DBMS_XSMODE_CREAT) : (DBMS_XSMODE_RDONLY)),
+				      _my_malloc, _my_free,	/* malloc/free to use */
+				      _my_report,	/* Callback for warnings */
+				      _my_error,	/* Calllback to set error(variables) */
+				      bt_compare_fcn_type
+				      ))) == NULL) {
+		backend_dbms_set_error(me, "Could not open/create database", FLAT_STORE_E_CANNOTOPEN);
+		perror("backend_dbms_open");
+		fprintf(stderr, "Could not open/create '%s': %s\n", me->filename, backend_dbms_get_error(me));
+		_my_free(me);
+		return FLAT_STORE_E_CANNOTOPEN;
+	};
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_open '%s'\n", me->filename);
+#endif
+
+	*mme = me;
+	return 0;
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_close(
+		   void *eme
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	void            (*_my_free) (void *) = me->free;
+	int             retval = 0;
+
+	dbms_disconnect(me->dbms);
+	_my_free(me);
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_close '%s'\n", me->filename);
+#endif
+
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_fetch(
+		   void *eme,
+		   DBT key,
+		   DBT * val
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval = 0;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_fetch num=%d from '%s'\n", ++(me->num_fetch), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_FETCH, &retval, &key, NULL, NULL, val)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_fetch");
+		fprintf(stderr, "Could not fetch '%s': %s\n", me->filename, (char *) key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+
+	/* to duplicate rertun value */
+
+	return retval;
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_fetch_compressed(
+                  void * eme,
+                  void (*func_decode)(unsigned int,unsigned char*, unsigned int *, unsigned char *),
+                  DBT key,
+                  unsigned int * outsize_p, unsigned char * outchar
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+        int             retval = 0;
+        DBT             val;
+	memset(&val, 0, sizeof(val));
+
+        if ((retval = backend_dbms_fetch(eme,key,&val)))
+                return retval;
+
+        (*func_decode)(val.size,val.data,outsize_p,outchar);
+	(me->free)(val.data);
+
+        return retval;
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_store(
+		   void *eme,
+		   DBT key,
+		   DBT val
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval = 0;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_store num=%d in '%s'\n", ++(me->num_store), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_STORE, &retval, &key, &val, NULL, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_store");
+		fprintf(stderr, "Could not store '%s': %s = %s\n", me->filename, (char *) key.data, (char *) val.data);
+		return FLAT_STORE_E_DBMS;
+	};
+	if (retval != 0) {
+		if (retval == 1) {
+			backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_KEYEXIST);
+			return FLAT_STORE_E_KEYEXIST;
+		} else {
+			backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+			perror("backend_dbms_store");
+			fprintf(stderr, "Could not store '%s': %s = %s\n", me->filename, (char *) key.data, (char *) val.data);
+			return FLAT_STORE_E_NOTFOUND;
+		};
+	};
+
+	return retval;
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_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
+)
+{
+        int             outsize;
+        DBT             val;
+
+        (*func_decode)(insize,inchar, &outsize, outbuff);
+
+	memset(&val, 0, sizeof(val));
+        val.data = outbuff;
+        val.size = outsize;
+
+        return backend_dbms_store(eme,key,val);
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_exists(
+		    void *eme,
+		    DBT key
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_exists num=%d from '%s'\n", ++(me->num_exists), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_EXISTS, &retval, &key, NULL, NULL, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_exists");
+		fprintf(stderr, "Could not exists '%s': %s\n", me->filename, (char *) key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_delete(
+		    void *eme,
+		    DBT key
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_delete num=%d from '%s'\n", ++(me->num_delete), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_DELETE, &retval, &key, NULL, NULL, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_delete");
+		fprintf(stderr, "Could not delete '%s': %s\n", me->filename, (char *) key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval != 0) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_clear(
+		   void *eme
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	me->num_store = 0;
+	me->num_fetch = 0;
+	me->num_inc = 0;
+	me->num_dec = 0;
+	me->num_sync = 0;
+	me->num_next = 0;
+	me->num_from = 0;
+	me->num_first = 0;
+	me->num_delete = 0;
+	me->num_exists = 0;
+	fprintf(stderr, "backend_dbms_clear num=%d in '%s'\n", ++(me->num_clear), me->filename);
+#endif
+
+	int             retval;
+
+	if (dbms_comms(me->dbms, TOKEN_CLEAR, &retval, NULL, NULL, NULL, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_clear");
+		fprintf(stderr, "Could not clear '%s'\n", me->filename);
+		return FLAT_STORE_E_DBMS;
+	};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_from(
+		   void *eme,
+		   DBT   closest_key,
+		   DBT * key
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_from num=%d from '%s'\n", ++(me->num_from), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_FROM, &retval, &closest_key, NULL, key, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_from");
+		fprintf(stderr, "Could not from '%s'\n", me->filename);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_first(
+		   void *eme,
+		   DBT * first_key
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_first num=%d from '%s'\n", ++(me->num_first), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_FIRSTKEY, &retval, NULL, NULL, first_key, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_first");
+		fprintf(stderr, "Could not first '%s'\n", me->filename);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+};
+
+rdfstore_flat_store_error_t
+backend_dbms_next(
+		  void *eme,
+		  DBT previous_key,
+		  DBT * next_key
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_next num=%d from '%s'\n", ++(me->num_next), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_NEXTKEY, &retval, &previous_key, NULL, next_key, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_next");
+		fprintf(stderr, "Could not next '%s': %s\n", me->filename, (char *) previous_key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+};
+
+/* packed rdf_store_counter_t increment */
+rdfstore_flat_store_error_t
+backend_dbms_inc(
+		 void *eme,
+		 DBT key,
+		 DBT * new_value
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_inc num=%d in '%s'\n", ++(me->num_inc), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_PACKINC, &retval, &key, NULL, NULL, new_value)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_inc");
+		fprintf(stderr, "Could not inc '%s': %s\n", me->filename, (char *) key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+}
+
+/* packed rdf_store_counter_t decrement */
+rdfstore_flat_store_error_t
+backend_dbms_dec(
+		 void *eme,
+		 DBT key,
+		 DBT * new_value
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_dec num=%d from '%s'\n", ++(me->num_dec), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_PACKDEC, &retval, &key, NULL, NULL, new_value)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_dec");
+		fprintf(stderr, "Could not dec '%s': %s\n", me->filename, (char *) key.data);
+		return FLAT_STORE_E_DBMS;
+	};
+
+	if (retval == 1) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_NOTFOUND);
+		return FLAT_STORE_E_NOTFOUND;
+		};
+	return retval;
+}
+
+rdfstore_flat_store_error_t
+backend_dbms_sync(
+		  void *eme
+)
+{
+	dbms_store_t   *me = (dbms_store_t *) eme;
+	int             retval;
+
+#ifdef RDFSTORE_FLAT_STORE_DEBUG
+	fprintf(stderr, "backend_dbms_sync num=%d in '%s'\n", ++(me->num_sync), me->filename);
+#endif
+
+	if (dbms_comms(me->dbms, TOKEN_SYNC, &retval, NULL, NULL, NULL, NULL)) {
+		backend_dbms_set_error(me, dbms_get_error(me->dbms), FLAT_STORE_E_DBMS);
+		perror("backend_dbms_sync");
+		fprintf(stderr, "Could not sync '%s'\n", me->filename);
+		return FLAT_STORE_E_DBMS;
+	}
+	return retval;
+}
+
+int
+backend_dbms_isremote(
+		      void *eme
+)
+{
+	/* dbms_store_t * me = (dbms_store_t *)eme; */
+	return 1;
+}
+
+#define DBMS_VERSION (100)
+DECLARE_MODULE_BACKEND(backend_dbms, "DBMS", DBMS_VERSION);

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/.cvsignore
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/.cvsignore?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/.cvsignore (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/.cvsignore Fri Apr 13 01:56:01 2007
@@ -0,0 +1 @@
+arch.conf

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/AUTHORS
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/AUTHORS?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/AUTHORS (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/AUTHORS Fri Apr 13 01:56:01 2007
@@ -0,0 +1,2 @@
+Dirk-Willem van Gulik <di...@webweaving.org>
+Alberto Reggiori <ar...@webweaving.org>

Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/CHANGES
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/CHANGES?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/CHANGES (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/CHANGES Fri Apr 13 01:56:01 2007
@@ -0,0 +1,127 @@
+Revision history for RDFStore tcp/ip backend storage
+
+version 1.7 (version taken from dbms/veersion.c)
+-------------------------------------------------------------------------------------------
+
+	utils/
+		- added dbms_mirror.pl to copy/mirror DBMS tables either locally or remotely
+
+	dbmsproxy/
+		- added dbmsproxy to use cheap local unix socket for reads if possible.
+
+	client/t/*
+		- updated to receive bt_compare_fcn_type paramter after mode
+
+	include/dbms.h
+		- added bt_compare_fcn_type to dbms struct
+
+	include/dbms_comms.h
+		- added TOKEN_FROM
+
+	deamon/hanlder.c
+		- added TOKEN_FROM handler for from() operation
+		- added bt_compare_fcn_type paramter management to receive from client
+                - fixed bug in frist(), next() methods to use the right macros depending on BDB version
+
+        libdbms/libdbms.c
+                - updated to use debug malloc/free
+		- added TOKEN_FROM
+		- added bt_compare_fcn_type paramter management to send to server
+
+version 1.2.
+-------------------------------------------------------------------------------------------
+
+	Abstracted out a libdbms(.a) which contains all
+	the communciation code and does better error handling.
+	the perl side is now just a wrapper.
+
+	Abstracted/moved all specific things into a compat header 
+	file (see include/*compat*).
+
+	Renamed directory DBMS to client and added client/stub.[ch]
+
+	include/dbms.h
+		- added TOKEN_DEC for atomic decrement
+		- added TOKEN_PACKINC for atomic packed increment
+		- added TOKEN_PACKDEC for atomic packed decrement
+
+	deamon/deamon.h
+		- added definitions for BDB > 1.8x support
+
+	deamon/hanlder.c
+		- added basic BDB > 1.8x support
+		- added atomic decrement support via do_dec()
+		- added atomic packed increment support via do_packinc()
+		- added atomic packed decrement support via do_packdec()
+
+	client/DBMS.xs
+		- updated perl/XS glue code
+		- added atomic decrement - see DEC()
+		- moved client related definitions in client/stub.h
+		- moved code to main RDFStore.xs to avoid dynamic linking problems of libdbms.so
+
+	client/DBMS.pm
+		- added atomic decrement - see dec()
+		- moved one level up to main rdfstore dist dir (see ../lib)
+
+version 1.1.1.1 - 2001/01/18 09:53:20
+-------------------------------------------------------------------------------------------
+
+	A a new version of dbmsd has been made. Most of this code come from one of the
+	leatest version authored by Dirk Willem-van Gulik early 1999. Since version 0.1
+	I simpy posted his code almost untouched, but due the fact dirk left since a year
+	ago I will take over the dbmsd project. I am not a C guru and volunteers are
+	welcome. What is new:
+
+		- dirk started with multi-thread supported but it was never finished that
+		  I know of
+		- some bug fixing to get it compiled on Irix and Solaris has been made
+		- dbmsd still use BerkeleyDB 1.x style interface
+
+	Now DBMS runs fine on Linux platforms (tested on SuSE Linux Linux 2.2.16) by using the
+	Sleepycat BDB 1.85 compatibility API (namely libdb1 and db_185.h). The user needs to edit
+	the deamon/Makefile to link with the right library.
+
+	DBMS/typemap
+		- Fixed bug to make it compile on old and recent Perl5 versions
+
+	Makefile
+		- general update. Added make depend for deamon
+
+	deamon/children.c
+		- added platform check to include compatibility code db_185.h
+
+	deamon/deamon.c
+		- added platform check to include compatibility code db_185.h
+
+	deamon/deamon.h
+		- added platform check to include compatibility code db_185.h
+
+	deamon/handler.c
+		- added platform check to include compatibility code db_185.h
+
+	deamon/loop.c
+		- added platform check to include compatibility code db_185.h
+
+	deamon/main.c
+		- added platform check to include compatibility code db_185.h
+
+	deamon/Makefile
+		- commented out a few options and cleaned up a few things
+		- added (optional) libdb1 to get DBMS compile on Linux
+
+	deamon/README
+		- included README file originally written by dirk
+	
+	utils
+		- moved original utils/dbcat_raw utils to dbsm dirs
+
+	doc
+		- added documentation section
+		- added dbms.html contribution by dirkx@webweaving.org
+	
+	INSTALL
+		- added installation instructions
+
+	deamon/handler.c
+		- commented out sys/syslimits.h (already included by sys/param.h)