Blob Blame History Raw
commit 490717dabe58fca268add95e367e0954477c9599
Author: Denny Lin <dennylin93@hs.ntnu.edu.tw>
Date:   Mon Sep 21 15:21:03 2015 +0200

    Add Kyoto Cabinet backend.

diff --git a/configure.ac b/configure.ac
index 933b365..c085e05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -464,7 +464,7 @@ AC_CACHE_SAVE
 WITH_DB_ENGINE=db
 AC_ARG_WITH(database,
 	    AS_HELP_STRING([--with-database=ENGINE],
-	    [choose database engine {db|qdbm|sqlite3|tokyocabinet} [[db]]]),
+	    [choose database engine {db|qdbm|sqlite3|tokyocabinet|kyotocabinet} [[db]]]),
 	    [ WITH_DB_ENGINE=$withval ]
 )
 
@@ -503,6 +503,21 @@ case "x$WITH_DB_ENGINE" in
 	])],,AC_MSG_ERROR(Cannot link to tokyocabinet library.))
 	LIBS="$saveLIBS"
         ;;
+    xkyotocabinet)
+	AC_DEFINE(ENABLE_KYOTOCABINET_DATASTORE,1, [Enable kyotocabinet datastore])
+	DB_TYPE=kyotocabinet
+	DB_EXT=.kct
+	AC_LIB_LINKFLAGS([kyotocabinet])
+	LIBDB="$LIBKYOTOCABINET"
+	saveLIBS="$LIBS"
+	LIBS="$LIBS $LIBDB"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([
+#include <kclangc.h>
+	], [
+	    KCDB *db = kcdbnew();
+	])],,AC_MSG_ERROR(Cannot link to kyotocabinet library.))
+	LIBS="$saveLIBS"
+        ;;
     xqdbm)
 	AC_DEFINE(ENABLE_QDBM_DATASTORE,1, [Enable qdbm datastore])
 	DB_TYPE=qdbm
@@ -653,7 +668,7 @@ shared environments, you can use --disable-dbshared-test.])],true)
 	LIBS="$saveLIBS"
     ;;
     *)
-	AC_MSG_ERROR([Invalid --with-database argument. Supported engines are db, qdbm, sqlite3, tokyocabinet.])
+	AC_MSG_ERROR([Invalid --with-database argument. Supported engines are db, qdbm, sqlite3, tokyocabinet, kyotocabinet.])
     ;;
 esac
 
@@ -679,6 +694,7 @@ AC_SUBST(STATIC_DB)
 AM_CONDITIONAL(ENABLE_QDBM_DATASTORE, test "x$WITH_DB_ENGINE" = "xqdbm")
 AM_CONDITIONAL(ENABLE_SQLITE_DATASTORE, test "x$WITH_DB_ENGINE" = "xsqlite3")
 AM_CONDITIONAL(ENABLE_TOKYOCABINET_DATASTORE, test "x$WITH_DB_ENGINE" = "xtokyocabinet")
+AM_CONDITIONAL(ENABLE_KYOTOCABINET_DATASTORE, test "x$WITH_DB_ENGINE" = "xkyotocabinet")
 
 dnl Use TRIO to replace missing snprintf/vsnprintf.
 needtrio=0
diff --git a/src/Makefile.am b/src/Makefile.am
index 0b2f064..fbce226 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -190,6 +190,11 @@ datastore_SOURCE = datastore_tc.c \
 		   datastore_opthelp_dummies.c \
 		   datastore_dummies.c
 else
+if ENABLE_KYOTOCABINET_DATASTORE
+datastore_SOURCE = datastore_kc.c \
+		   datastore_opthelp_dummies.c \
+		   datastore_dummies.c
+else
 if ENABLE_TRANSACTIONS
 datastore_SOURCE = datastore_db.c datastore_db_trans.c
 else
@@ -203,6 +208,7 @@ endif
 endif
 endif
 endif
+endif
 
 datastore_OBJECT = $(datastore_SOURCE:.c=.o)
 
diff --git a/src/datastore_kc.c b/src/datastore_kc.c
new file mode 100644
index 0000000..66a8f5e
--- /dev/null
+++ b/src/datastore_kc.c
@@ -0,0 +1,315 @@
+/* $Id$ */
+
+/*****************************************************************************
+
+NAME:
+datastore_kc.c -- implements the datastore, using kyotocabinet.
+
+AUTHORS:
+Gyepi Sam <gyepi@praxis-sw.com>          2003
+Matthias Andree <matthias.andree@gmx.de> 2003
+Stefan Bellon <sbellon@sbellon.de>       2003-2004
+Pierre Habouzit <madcoder@debian.org>    2007
+Denny Lin <dennylin93@hs.ntnu.edu.tw>    2015
+
+******************************************************************************/
+
+#include "common.h"
+
+#include <kclangc.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "datastore.h"
+#include "datastore_db.h"
+#include "error.h"
+#include "paths.h"
+#include "xmalloc.h"
+#include "xstrdup.h"
+
+#define UNUSED(x) ((void)(x))
+
+typedef struct {
+    char *name;
+    bool created;
+    bool writable;
+    KCDB *dbp;
+} dbh_t;
+
+static int kc_txn_begin(void *vhandle) {
+    dbh_t *dbh = vhandle;
+    if (!dbh->writable || kcdbbegintran(dbh->dbp, false))
+        return DST_OK;
+    print_error(__FILE__, __LINE__, "kcdbbegintran(%p), err: %d, %s",
+                dbh->dbp,
+                kcdbecode(dbh->dbp), kcdbemsg(dbh->dbp));
+    return DST_FAILURE;
+}
+
+static int kc_txn_abort(void *vhandle) {
+    dbh_t *dbh = vhandle;
+    if (!dbh->writable || kcdbendtran(dbh->dbp, false))
+        return DST_OK;
+    print_error(__FILE__, __LINE__, "kcdbendtran(%p, false), err: %d, %s",
+                dbh->dbp,
+                kcdbecode(dbh->dbp), kcdbemsg(dbh->dbp));
+    return DST_FAILURE;
+}
+
+static int kc_txn_commit(void *vhandle) {
+    dbh_t *dbh = vhandle;
+    if (!dbh->writable || kcdbendtran(dbh->dbp, true))
+        return DST_OK;
+    print_error(__FILE__, __LINE__, "kc_txn_commit(%p, true), err: %d, %s",
+                dbh->dbp,
+                kcdbecode(dbh->dbp), kcdbemsg(dbh->dbp));
+    return DST_FAILURE;
+}
+
+static dsm_t dsm_kc = {
+    /* public -- used in datastore.c */
+    &kc_txn_begin,
+    &kc_txn_abort,
+    &kc_txn_commit,
+    /* private -- used in datastore_db_*.c */
+    NULL,	/* dsm_env_init          */
+    NULL,	/* dsm_cleanup           */
+    NULL,	/* dsm_cleanup_lite      */
+    NULL,	/* dsm_get_env_dbe       */
+    NULL,	/* dsm_database_name     */
+    NULL,	/* dsm_recover_open      */
+    NULL,	/* dsm_auto_commit_flags */
+    NULL,	/* dsm_get_rmw_flag      */
+    NULL,	/* dsm_lock              */
+    NULL,	/* dsm_common_close      */
+    NULL,	/* dsm_sync              */
+    NULL,	/* dsm_log_flush         */
+    NULL,	/* dsm_pagesize          */
+    NULL,	/* dsm_purgelogs         */
+    NULL,	/* dsm_checkpoint        */
+    NULL,	/* dsm_recover           */
+    NULL,	/* dsm_remove            */
+    NULL,	/* dsm_verify            */
+    NULL,	/* dsm_list_logfiles     */
+    NULL	/* dsm_leafpages         */
+};
+
+dsm_t *dsm = &dsm_kc;
+
+const char *db_version_str(void)
+{
+    static char v[80];
+    if (v[0] == '\0')
+        snprintf(v, sizeof(v) - 1, "Kyoto Cabinet %s (TreeDB)", KCVERSION);
+    return v;
+}
+
+
+static dbh_t *dbh_init(bfpath *bfp)
+{
+    dbh_t *handle;
+
+    handle = xmalloc(sizeof(dbh_t));
+    memset(handle, 0, sizeof(dbh_t));
+
+    handle->name = xstrdup(bfp->filepath);
+    handle->created = false;
+    handle->writable = false;
+    handle->dbp = kcdbnew();
+
+    return handle;
+}
+
+
+static void dbh_free(dbh_t *handle)
+{
+    if (handle != NULL) {
+      xfree(handle->name);
+      kcdbdel(handle->dbp);
+      xfree(handle);
+    }
+}
+
+
+bool db_is_swapped(void *vhandle)
+{
+    UNUSED(vhandle);
+
+    return false;
+}
+
+
+bool db_created(void *vhandle)
+{
+    dbh_t *handle = vhandle;
+
+    return handle->created;
+}
+
+
+void *db_open(void *env, bfpath *bfp, dbmode_t open_mode)
+{
+    dbh_t *handle;
+    uint32_t mode;
+    bool ret;
+
+    UNUSED(env);
+
+    handle = dbh_init(bfp);
+
+    handle->writable = open_mode & DS_WRITE;
+    mode = handle->writable ? KCOWRITER : KCOREADER;
+    ret = kcdbopen(handle->dbp, handle->name, mode);
+    if (!ret && handle->writable) {
+        ret = kcdbopen(handle->dbp, handle->name, mode | KCOCREATE);
+        handle->created = ret;
+    }
+
+    if (!ret)
+        goto open_err;
+
+    if (DEBUG_DATABASE(1))
+        fprintf(dbgout, "kcdbopen(%s, %u)\n", handle->name, mode);
+
+    return handle;
+
+open_err:
+    print_error(__FILE__, __LINE__, "kcdbopen(%s, %u), err: %d, %s",
+                handle->name, mode,
+                kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+    dbh_free(handle);
+
+    return NULL;
+}
+
+
+int db_delete(void *vhandle, const dbv_t *token)
+{
+    dbh_t *handle = vhandle;
+    bool ret;
+
+    ret = kcdbremove(handle->dbp, token->data, token->leng);
+    if (!ret) {
+        print_error(__FILE__, __LINE__, "kcdbremove(\"%.*s\"), err: %d, %s",
+                    CLAMP_INT_MAX(token->leng), (char *)token->data,
+                    kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+        exit(EX_ERROR);
+    }
+
+    return 0;
+}
+
+
+int db_get_dbvalue(void *vhandle, const dbv_t *token, dbv_t *val)
+{
+    dbh_t *handle = vhandle;
+    char *data;
+    size_t dsiz;
+
+    data = kcdbget(handle->dbp, token->data, token->leng, &dsiz);
+    if (data == NULL)
+        return DS_NOTFOUND;
+
+    val->leng = min(val->leng, dsiz);
+    memcpy(val->data, data, val->leng);
+    kcfree(data);
+
+    return 0;
+}
+
+int db_set_dbvalue(void *vhandle, const dbv_t *token, const dbv_t *val)
+{
+    dbh_t *handle = vhandle;
+    bool ret;
+
+    ret = kcdbset(handle->dbp, token->data, token->leng, val->data, val->leng);
+    if (!ret) {
+        print_error(__FILE__, __LINE__,
+                    "kcdbset: (%.*s, %.*s), err: %d, %s",
+                    CLAMP_INT_MAX(token->leng), (char *)token->data,
+                    CLAMP_INT_MAX(val->leng), (char *)val->data,
+                    kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+        exit(EX_ERROR);
+    }
+
+    return 0;
+}
+
+
+void db_close(void *vhandle)
+{
+    dbh_t *handle = vhandle;
+
+    if (handle == NULL)
+        return;
+
+    if (DEBUG_DATABASE(1))
+        fprintf(dbgout, "kcdbclose: %s\n", handle->name);
+
+    if (!kcdbclose(handle->dbp))
+        print_error(__FILE__, __LINE__, "kcdbclose: %s, err: %d, %s",
+                    handle->name,
+                    kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+
+    dbh_free(handle);
+}
+
+
+void db_flush(void *vhandle)
+{
+    dbh_t *handle = vhandle;
+
+    if (!kcdbsync(handle->dbp, false, NULL, NULL))
+        print_error(__FILE__, __LINE__, "kcdbsync(), err: %d, %s",
+                    kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+}
+
+ex_t db_foreach(void *vhandle, db_foreach_t hook, void *userdata)
+{
+    dbh_t *handle = vhandle;
+    KCCUR *cursor;
+    dbv_t dbv_key, dbv_data;
+    size_t ksiz, dsiz;
+    int ret;
+    ex_t retval = EX_OK;
+    char *key;
+    const char *data;
+
+    cursor = kcdbcursor(handle->dbp);
+    if (!kccurjump(cursor)) {
+        print_error(__FILE__, __LINE__, "kccurjump(), err: %d, %s",
+                    kcdbecode(handle->dbp), kcdbemsg(handle->dbp));
+        retval = EX_ERROR;
+        goto done;
+    }
+
+    while ((key = kccurget(cursor, &ksiz, &data, &dsiz, true)) != NULL) {
+        /* Copy to dbv_key and dbv_data */
+        dbv_key.data = xstrdup(key);
+        dbv_key.leng = ksiz;
+        dbv_data.data = xstrdup(data);
+        dbv_data.leng = dsiz;
+
+        /* Call function */
+        ret = hook(&dbv_key, &dbv_data, userdata);
+
+        xfree(dbv_key.data);
+        xfree(dbv_data.data);
+        kcfree(key);
+
+        if (ret != 0)
+            break;
+    }
+
+done:
+    kccurdel(cursor);
+
+    return retval;
+}
+
+const char *db_str_err(int e)
+{
+    UNUSED(e);
+    return "unknown error";
+}
diff --git a/src/tests/t.frame b/src/tests/t.frame
index 355f6f2..7eaa221 100755
--- a/src/tests/t.frame
+++ b/src/tests/t.frame
@@ -48,6 +48,7 @@ case $DB_NAME in
 	esac ;;
     *QDBM*)	     DB_TXN=false ;;
     *Tokyo*)	     DB_TXN=true  ;;
+    *Kyoto*)	     DB_TXN=true  ;;
     *SQLite*)	     DB_TXN=true  ;;
     *TrivialDB*)     DB_TXN=false ;;
     *)		    echo >&2 "Unknown data base type in bogofilter -V: $DB_NAME"