aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2017-10-25 14:47:16 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2017-10-25 14:47:16 +0200
commit562d2639c2b675859011202a46c2ed6f61c4457c (patch)
tree1bd32ec00b91526cea073f8edd02a48387788aec
parent4a4fd954141d1fb4410bf90b00e6f6c8a6540579 (diff)
database: switch to use gdbm by default
Change-Id: I25b54a6b1f66f3acef3c1c7cb96e0daaa1019eae Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--ll-database-binding/conf.d/cmake/FindGDBM.cmake51
-rw-r--r--ll-database-binding/src/CMakeLists.txt9
-rw-r--r--ll-database-binding/src/ll-database-binding.c320
3 files changed, 288 insertions, 92 deletions
diff --git a/ll-database-binding/conf.d/cmake/FindGDBM.cmake b/ll-database-binding/conf.d/cmake/FindGDBM.cmake
new file mode 100644
index 0000000..abc9987
--- /dev/null
+++ b/ll-database-binding/conf.d/cmake/FindGDBM.cmake
@@ -0,0 +1,51 @@
+# -*- cmake -*-
+
+# - Find gdbm
+# Find the gdbm includes and library
+# This module defines
+# DB_INCLUDE_DIR, where to find db.h, etc.
+# DB_LIBRARIES, the libraries needed to use BerkeleyDB.
+# DB_FOUND, If false, do not try to use BerkeleyDB.
+# also defined, but not for general use are
+# DB_LIBRARY, where to find the BerkeleyDB library.
+
+FIND_PATH(DB_INCLUDE_DIR gdbm.h
+ /usr/local/include/gdbm
+ /usr/local/include
+ /usr/include/gdbm
+ /usr/include
+ )
+
+SET(DB_NAMES ${DB_NAMES} gdbm)
+FIND_LIBRARY(DB_LIBRARY
+ NAMES ${DB_NAMES}
+ PATHS /usr/lib /usr/local/lib
+ )
+
+IF (DB_LIBRARY AND DB_INCLUDE_DIR)
+ SET(DB_LIBRARIES ${DB_LIBRARY})
+ SET(DB_FOUND "YES")
+ELSE (DB_LIBRARY AND DB_INCLUDE_DIR)
+ SET(DB_FOUND "NO")
+ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR)
+
+
+IF (DB_FOUND)
+ IF (NOT DB_FIND_QUIETLY)
+ MESSAGE(STATUS "Found gdbm: ${DB_LIBRARIES}")
+ ENDIF (NOT DB_FIND_QUIETLY)
+ELSE (DB_FOUND)
+ IF (DB_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find gdbm library")
+ ENDIF (DB_FIND_REQUIRED)
+ENDIF (DB_FOUND)
+
+# Deprecated declarations.
+SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} )
+GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH)
+
+MARK_AS_ADVANCED(
+ DB_LIBRARY
+ DB_INCLUDE_DIR
+ )
+
diff --git a/ll-database-binding/src/CMakeLists.txt b/ll-database-binding/src/CMakeLists.txt
index 904b857..cea11a3 100644
--- a/ll-database-binding/src/CMakeLists.txt
+++ b/ll-database-binding/src/CMakeLists.txt
@@ -1,9 +1,14 @@
PROJECT_TARGET_ADD(ll-database-binding)
-find_package(BerkeleyDB REQUIRED)
+find_package(GDBM)
+if(DB_FOUND)
+ add_definitions(-DUSE_GDBM)
+else(DB_FOUND)
+ find_package(BerkeleyDB REQUIRED)
+endif(DB_FOUND)
include_directories(${DB_INCLUDE_DIR})
-add_library(ll-database-binding MODULE ll-database-binding.c utils.h)
+add_library(ll-database-binding MODULE ll-database-binding.c)
target_link_libraries(ll-database-binding ${DB_LIBRARY})
set_target_properties(ll-database-binding PROPERTIES
diff --git a/ll-database-binding/src/ll-database-binding.c b/ll-database-binding/src/ll-database-binding.c
index e878896..c9f49f1 100644
--- a/ll-database-binding/src/ll-database-binding.c
+++ b/ll-database-binding/src/ll-database-binding.c
@@ -26,13 +26,10 @@
#include <limits.h>
#include <json-c/json.h>
-#include <db.h>
#define AFB_BINDING_VERSION 2
#include <afb/afb-binding.h>
-#define DBFILE "ll-database-binding.db"
-
#if !defined(TO_STRING_FLAGS)
# if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
# define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4)
@@ -40,15 +37,219 @@
# define TO_STRING_FLAGS (JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE)
#endif
-// ----- Globals -----
+#if defined(USE_BERKELEY_DB)
+# undef USE_BERKELEY_DB
+#endif
+
+#if defined(USE_GDBM)
+# undef USE_GDBM
+# define USE_GDBM 1
+# define USE_BERKELEY_DB 0
+#else
+# define USE_GDBM 0
+# define USE_BERKELEY_DB 1
+#endif
+
+// ----- Berkeley database -----
+#if USE_BERKELEY_DB
+
+#include <db.h>
+
+#define DBFILE "ll-database-binding.db"
+#define DATA DBT
+#define DATA_SET(k,d,s) do{memset((k),0,sizeof*(k));(k)->data=(void*)d;(k)->size=(uint32_t)s;}while(0)
+#define DATA_PTR(k) ((void*)((k).data))
+#define DATA_STR(k) ((char*)((k).data))
+#define DATA_SZ(k) ((size_t)((k).size))
+
static DB *database;
-// ----- Binding's declarations -----
-static int ll_database_binding_init();
-static void verb_insert(struct afb_req req);
-static void verb_update(struct afb_req req);
-static void verb_delete(struct afb_req req);
-static void verb_read(struct afb_req req);
+static int xdb_open(const char *path)
+{
+ int ret;
+
+ ret = db_create(&database, NULL, 0);
+ if (ret != 0)
+ {
+ AFB_ERROR("Failed to create database: %s.", db_strerror(ret));
+ return -1;
+ }
+
+ ret = database->open(database, NULL, path, NULL, DB_BTREE, DB_CREATE, 0600);
+ if (ret != 0)
+ {
+ AFB_ERROR("Failed to open the '%s' database: %s.", path, db_strerror(ret));
+ database->close(database, 0);
+ return -1;
+ }
+ return 0;
+}
+
+static void xdb_put(struct afb_req req, DBT *key, DBT *data, int replace)
+{
+ int ret;
+
+ ret = database->put(database, NULL, key, data, replace ? 0 : DB_NOOVERWRITE);
+ if (ret == 0)
+ afb_req_success(req, NULL, NULL);
+ else
+ {
+ AFB_ERROR("can't %s key %s with %s", replace ? "replace" : "insert", DATA_STR(*key), DATA_STR(*data));
+ afb_req_fail_f(req, "failed", "%s", db_strerror(ret));
+ }
+}
+
+static void xdb_delete(struct afb_req req, DBT *key)
+{
+ int ret;
+
+ ret = database->del(database, NULL, key, 0);
+ if (ret == 0)
+ afb_req_success_f(req, NULL, NULL);
+ else
+ {
+ AFB_ERROR("can't delete key %s", DATA_STR(*key));
+ afb_req_fail_f(req, "failed", "%s", db_strerror(ret));
+ }
+
+ free(DATA_PTR(key));
+}
+
+static void verb_read(struct afb_req req)
+{
+ DATA key;
+ DATA data;
+ int ret;
+
+ char value[4096];
+
+ struct json_object* result;
+ struct json_object* val;
+
+
+ if (get_key(req, &key))
+ return;
+
+ AFB_INFO("read: key=%s", DATA_STR(key));
+
+ memset(&data, 0, sizeof data);
+ data.data = value;
+ data.ulen = 4096;
+ data.flags = DB_DBT_USERMEM;
+
+ ret = database->get(database, NULL, &key, &data, 0);
+ if (ret == 0)
+ {
+ result = json_object_new_object();
+ val = json_tokener_parse(DATA_STR(data));
+ json_object_object_add(result, "value", val ? val : json_object_new_string(DATA_STR(data)));
+
+ afb_req_success_f(req, result, "db success: read %s=%s.", DATA_STR(key), DATA_STR(data));
+ }
+ else
+ afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", DATA_STR(key), db_strerror(ret));
+
+ free(DATA_PTR(key));
+}
+
+#endif
+
+// ----- gdbm database -----
+#if USE_GDBM
+
+#include <errno.h>
+#include <gdbm.h>
+
+#define DBFILE "ll-database-binding.dbm"
+#define DATA datum
+#define DATA_SET(k,d,s) do{(k)->dptr=(char*)d;(k)->dsize=(int)s;}while(0)
+#define DATA_PTR(k) ((void*)((k).dptr))
+#define DATA_STR(k) ((char*)((k).dptr))
+#define DATA_SZ(k) ((size_t)((k).dsize))
+
+static GDBM_FILE database;
+
+static void onfatal(const char *text)
+{
+ AFB_ERROR("fatal gdbm message: %s", text);
+}
+
+static int xdb_open(const char *path)
+{
+ database = gdbm_open(path, 512, GDBM_WRCREAT|GDBM_SYNC, 0600, onfatal);
+ if (!database)
+ {
+ AFB_ERROR("Fail to open/create database: %s%s%s", gdbm_errlist[gdbm_errno],
+ gdbm_syserr[gdbm_errno] ? ", " : "",
+ gdbm_syserr[gdbm_errno] ? strerror(errno) : "");
+ return -1;
+
+ }
+ return 0;
+}
+
+static void xdb_put(struct afb_req req, datum *key, datum *data, int replace)
+{
+ int ret;
+
+ ret = gdbm_store(database, *key, *data, replace ? GDBM_REPLACE : GDBM_INSERT);
+ if (ret == 0)
+ afb_req_success(req, NULL, NULL);
+ else
+ {
+ AFB_ERROR("can't %s key %s with %s: %s%s%s",
+ replace ? "replace" : "insert",
+ DATA_STR(*key),
+ DATA_STR(*data),
+ gdbm_errlist[gdbm_errno],
+ gdbm_syserr[gdbm_errno] ? ", " : "",
+ gdbm_syserr[gdbm_errno] ? strerror(errno) : "");
+ afb_req_fail_f(req, "failed", "%s", ret > 0 ? "key already exists" : gdbm_errlist[gdbm_errno]);
+ }
+}
+
+static void xdb_delete(struct afb_req req, datum *key)
+{
+ int ret;
+
+ ret = gdbm_delete(database, *key);
+ if (ret == 0)
+ afb_req_success_f(req, NULL, NULL);
+ else
+ {
+ AFB_ERROR("can't delete key %s: %s%s%s",
+ DATA_STR(*key),
+ gdbm_errlist[gdbm_errno],
+ gdbm_syserr[gdbm_errno] ? ", " : "",
+ gdbm_syserr[gdbm_errno] ? strerror(errno) : "");
+ afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]);
+ }
+}
+
+static void xdb_get(struct afb_req req, datum *key)
+{
+ struct json_object* obj;
+ datum result;
+
+ result = gdbm_fetch(database, *key);
+ if (result.dptr)
+ {
+ obj = json_object_new_object();
+ json_object_object_add(obj, "value", json_tokener_parse(result.dptr));
+ afb_req_success(req, obj, NULL);
+ free(result.dptr);
+ }
+ else
+ {
+ AFB_ERROR("can't get key %s: %s%s%s",
+ DATA_STR(*key),
+ gdbm_errlist[gdbm_errno],
+ gdbm_syserr[gdbm_errno] ? ", " : "",
+ gdbm_syserr[gdbm_errno] ? strerror(errno) : "");
+ afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]);
+ }
+}
+#endif
// ----- Binding's implementations -----
@@ -100,29 +301,13 @@ static int ll_database_binding_init()
}
AFB_INFO("opening database %s", path);
-
- ret = db_create(&database, NULL, 0);
- if (ret != 0)
- {
- AFB_ERROR("Failed to create database: %s.", db_strerror(ret));
- return -1;
- }
-
- ret = database->open(database, NULL, path, NULL, DB_BTREE, DB_CREATE, 0664);
- if (ret != 0)
- {
- AFB_ERROR("Failed to open the '%s' database: %s.", path, db_strerror(ret));
- database->close(database, 0);
- return -1;
- }
-
- return 0;
+ return xdb_open(path);
}
/**
* Returns the database key for the 'req'
*/
-static int get_key(struct afb_req req, DBT *key)
+static int get_key(struct afb_req req, DATA *key)
{
char *appid, *data;
const char *jkey;
@@ -173,56 +358,42 @@ static int get_key(struct afb_req req, DBT *key)
memcpy(&data[lappid + 1], jkey, ljkey + 1);
/* return the key */
- memset(key, 0, sizeof *key);
- key->data = data;
- key->size = (uint32_t)size;
+ DATA_SET(key, data, size);
return 0;
}
static void put(struct afb_req req, int replace)
{
- int ret;
- DBT key;
- DBT data;
+ DATA key;
+ DATA data;
const char* value;
struct json_object* args;
struct json_object* item;
+ /* get the value */
args = afb_req_json(req);
-
if (!json_object_object_get_ex(args, "value", &item))
{
afb_req_fail(req, "no-value", NULL);
return;
}
-
value = json_object_to_json_string_ext(item, TO_STRING_FLAGS);
if (!value)
{
afb_req_fail(req, "out-of-memory", NULL);
return;
}
+ DATA_SET(&data, value, strlen(value) + 1); /* includes the tailing null */
+ /* get the key */
if (get_key(req, &key))
return;
- AFB_INFO("put: key=%s, value=%s", (char*)key.data, value);
-
- memset(&data, 0, sizeof data);
- data.data = (void*)value;
- data.size = (uint32_t)strlen(value) + 1; /* includes the tailing null */
-
- ret = database->put(database, NULL, &key, &data, replace ? 0 : DB_NOOVERWRITE);
- if (ret == 0)
- afb_req_success(req, NULL, NULL);
- else
- {
- AFB_ERROR("can't %s key %s with %s", replace ? "replace" : "insert", (char*)key.data, (char*)data.data);
- afb_req_fail_f(req, "failed", "%s", db_strerror(ret));
- }
- free(key.data);
+ AFB_INFO("put: key=%s, value=%s", DATA_STR(key), DATA_STR(data));
+ xdb_put(req, &key, &data, replace);
+ free(DATA_PTR(key));
}
static void verb_insert(struct afb_req req)
@@ -237,57 +408,26 @@ static void verb_update(struct afb_req req)
static void verb_delete(struct afb_req req)
{
- DBT key;
- int ret;
+ DATA key;
if (get_key(req, &key))
return;
- AFB_INFO("delete: key=%s", (char*)key.data);
-
- if ((ret = database->del(database, NULL, &key, 0)) == 0)
- afb_req_success_f(req, NULL, "db success: delete %s.", (char *)key.data);
- else
- afb_req_fail_f(req, "Failed to delete datas.", "db fail: delete %s - %s", (char*)key.data, db_strerror(ret));
-
- free(key.data);
+ AFB_INFO("delete: key=%s", DATA_STR(key));
+ xdb_delete(req, &key);
+ free(DATA_PTR(key));
}
static void verb_read(struct afb_req req)
{
- DBT key;
- DBT data;
- int ret;
-
- char value[4096];
-
- struct json_object* result;
- struct json_object* val;
-
+ DATA key;
if (get_key(req, &key))
return;
- AFB_INFO("read: key=%s", (char*)key.data);
-
- memset(&data, 0, sizeof data);
- data.data = value;
- data.ulen = 4096;
- data.flags = DB_DBT_USERMEM;
-
- ret = database->get(database, NULL, &key, &data, 0);
- if (ret == 0)
- {
- result = json_object_new_object();
- val = json_tokener_parse((char*)data.data);
- json_object_object_add(result, "value", val ? val : json_object_new_string((char*)data.data));
-
- afb_req_success_f(req, result, "db success: read %s=%s.", (char*)key.data, (char*)data.data);
- }
- else
- afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", (char*)key.data, db_strerror(ret));
-
- free(key.data);
+ AFB_INFO("read: key=%s", DATA_STR(key));
+ xdb_get(req, &key);
+ free(DATA_PTR(key));
}
// ----- Binding's configuration -----