add sqlite3 backend 32/95832/6 accepted/tizen/3.0/common/20161122.063740 accepted/tizen/3.0/ivi/20161121.234444 accepted/tizen/3.0/mobile/20161121.234348 accepted/tizen/3.0/tv/20161121.234402 accepted/tizen/3.0/wearable/20161121.234422 submit/tizen_3.0/20161118.014051
authorJiwoong Im <jiwoong.im@samsung.com>
Fri, 4 Nov 2016 01:18:56 +0000 (10:18 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Fri, 18 Nov 2016 01:20:08 +0000 (17:20 -0800)
- Because gdbm doesn't have restore mechanism, replace backend to sqlite3

Change-Id: Ib0148e5c4932a5c563a081621497ac62bd3aedaa
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
backend/CMakeLists.txt
backend/sqlite.c [new file with mode: 0644]
packaging/buxton2.conf
packaging/buxton2.spec

index 380d87b..164686c 100644 (file)
@@ -9,3 +9,12 @@ SET_TARGET_PROPERTIES(${TARGET} PROPERTIES
 TARGET_LINK_LIBRARIES(${TARGET} ${PKGS_LDFLAGS} -lgdbm)
 INSTALL(TARGETS ${TARGET} DESTINATION ${MODULE_DIR} COMPONENT RuntimeLibraries)
 
+SET(TARGET sqlite)
+SET(SRC sqlite.c)
+ADD_LIBRARY(${TARGET} SHARED ${SRC})
+SET_TARGET_PROPERTIES(${TARGET} PROPERTIES
+               PREFIX ""
+               COMPILE_FLAGS "-fvisibility=hidden"
+)
+TARGET_LINK_LIBRARIES(${TARGET} ${PKGS_LDFLAGS} -lsqlite3)
+INSTALL(TARGETS ${TARGET} DESTINATION ${MODULE_DIR} COMPONENT RuntimeLibraries)
diff --git a/backend/sqlite.c b/backend/sqlite.c
new file mode 100644 (file)
index 0000000..95d2a3f
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+#include <glib.h>
+#include <sqlite3.h>
+
+#include "backend.h"
+#include "log.h"
+
+#define QUERY_MAX_LEN   8192
+#define QUERY_CREATE_TABLE_BUXTON "create table if not exists buxton " \
+       "(key text, " \
+       "data blob, " \
+       "PRIMARY KEY(key)) "
+
+static GHashTable *dbs;
+
+static void free_db(sqlite3 *db)
+{
+       if (!db)
+               return;
+
+       sqlite3_close(db);
+}
+
+static sqlite3 *open_sqlite3(const char *dbpath, bool readonly)
+{
+       sqlite3 *db;
+       char *nm;
+       int r;
+       bool db_exist = false;
+
+       assert(dbpath);
+
+       if (!dbs) {
+               errno = ENODEV;
+               return NULL;
+       }
+
+       db = g_hash_table_lookup(dbs, dbpath);
+       if (db)
+               return db;
+
+       nm = strdup(dbpath);
+       if (!nm) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       if (access(nm, F_OK) == 0)
+               db_exist = true;
+
+       r = sqlite3_open_v2(dbpath, &db,
+                       readonly ? SQLITE_OPEN_READONLY :
+                       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+       if (r) {
+               bxt_err("Open '%s' failed: %s", dbpath, sqlite3_errmsg(db));
+               errno = EIO;
+               free(nm);
+               return NULL;
+       }
+
+       if (!db_exist) {
+               r = sqlite3_exec(db, "PRAGMA journal_mode = WAL",
+                               NULL, NULL, NULL);
+               if (r) {
+                       bxt_err("change journal mode '%s' failed: %s",
+                                       dbpath, sqlite3_errmsg(db));
+                       errno = EIO;
+                       free(nm);
+                       return NULL;
+               }
+
+               r = sqlite3_exec(db, QUERY_CREATE_TABLE_BUXTON,
+                               NULL, NULL, NULL);
+               if (r != SQLITE_OK) {
+                       bxt_err("Create tables '%s' failed: %s",
+                                       dbpath, sqlite3_errmsg(db));
+                       errno = EIO;
+                       free(nm);
+                       return NULL;
+               }
+       }
+
+       g_hash_table_insert(dbs, nm, db);
+
+       bxt_dbg("Open '%s'", dbpath);
+
+       return db;
+}
+
+static int open_db(const char *dbpath, bool readonly)
+{
+       sqlite3 *db;
+
+       if (!dbpath || !*dbpath) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       db = open_sqlite3(dbpath, readonly);
+       if (!db)
+               return -1;
+
+       return 0;
+}
+
+static int close_db(const char *dbpath)
+{
+       sqlite3 *db;
+
+       if (!dbpath || !*dbpath) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (!dbs) {
+               errno = ENODEV;
+               return -1;
+       }
+
+       db = g_hash_table_lookup(dbs, dbpath);
+
+       if (!db)
+               return 0;
+
+       g_hash_table_remove(dbs, dbpath);
+
+       bxt_info("close '%s'", dbpath);
+
+       return 0;
+}
+
+static int remove_db(const char *dbpath)
+{
+       sqlite3 *db;
+       int r;
+
+       if (!dbpath || !*dbpath) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (!dbs) {
+               errno = ENODEV;
+               return -1;
+       }
+
+       db = g_hash_table_lookup(dbs, dbpath);
+       if (db)
+               g_hash_table_remove(dbs, dbpath);
+
+       r = unlink(dbpath);
+       if (r == -1) {
+               bxt_err("Remove '%s' failed: %d", dbpath, errno);
+               return -1;
+       }
+
+       bxt_dbg("Remove '%s'", dbpath);
+
+       return 0;
+}
+
+static int set_value(const char *dbpath, const char *key, const void *data,
+               int dlen)
+{
+       sqlite3 *db;
+       int r;
+       int ret = 0;
+       const char insert_query[] =
+           "insert or replace into buxton(key, data) values(?,?)";
+       sqlite3_stmt *stmt;
+
+       if (!dbpath || !*dbpath || !key || !*key || !data || dlen <= 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       db = open_sqlite3(dbpath, false);
+       if (!db)
+               return -1;
+
+       r = sqlite3_prepare_v2(db, insert_query, strlen(insert_query),
+                       &stmt, NULL);
+       if (r != SQLITE_OK) {
+               bxt_err("prepare error, ret = %d, extended = %d\n",
+                               r, sqlite3_extended_errcode(db));
+               return -1;
+       }
+
+       r = sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
+       if (r) {
+               bxt_err("Sqlite3 error [%d] : <%s> preparing <%s> querry\n", r,
+                               sqlite3_errmsg(db), insert_query);
+               ret = -1;
+               goto end;
+       }
+       r = sqlite3_bind_blob(stmt, 2, data, dlen, SQLITE_STATIC);
+       if (r) {
+               bxt_err("Sqlite3 error [%d] : <%s> preparing <%s> querry\n", r,
+                               sqlite3_errmsg(db), insert_query);
+               ret = -1;
+               goto end;
+       }
+
+       r = sqlite3_step(stmt);
+       if (r != SQLITE_DONE) {
+               bxt_err("Sqlite3 error [%d] : <%s> executing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+end:
+       r = sqlite3_finalize(stmt);
+       if (r != SQLITE_OK) {
+               bxt_err("Sqlite3 error [%d] : <%s> finalizing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+       bxt_dbg("Set '%s' Key '%s'", dbpath, key);
+
+       return ret;
+}
+
+static int get_value(const char *dbpath, const char *key, void **data,
+               int *dlen, bool readonly)
+{
+       int r;
+       int ret = 0;
+       sqlite3 *db;
+       sqlite3_stmt *stmt;
+       const char select_query[] = "select data from buxton where key = ?";
+
+       if (!dbpath || !*dbpath || !key || !*key || !data || !dlen) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       db = open_sqlite3(dbpath, readonly);
+       if (!db)
+               return -1;
+
+       r = sqlite3_prepare_v2(db, select_query, strlen(select_query),
+                       &stmt, NULL);
+       if (r != SQLITE_OK) {
+               bxt_err("prepare error, ret = %d, extended = %d\n",
+                               r, sqlite3_extended_errcode(db));
+               return -1;
+       }
+
+       r = sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
+       if (r) {
+               bxt_err("Sqlite3 error [%d] : <%s> preparing <%s> querry\n", r,
+                               sqlite3_errmsg(db), select_query);
+               ret = -1;
+               goto end;
+       }
+
+       r = sqlite3_step(stmt);
+       if (r != SQLITE_ROW) {
+               errno = ENOENT;
+               ret = -1;
+               goto end;
+       }
+
+       *dlen = sqlite3_column_bytes(stmt, 0);
+       if (*dlen > 0) {
+               *data = malloc(sizeof(void *) * (*dlen + 1));
+               if (*data == NULL) {
+                       errno = ENOMEM;
+                       ret = -1;
+                       goto end;
+               }
+               memcpy(*data, (void *)sqlite3_column_blob(stmt, 0), *dlen);
+       } else {
+               *data = NULL;
+       }
+
+end:
+       r = sqlite3_finalize(stmt);
+       if (r != SQLITE_OK) {
+               bxt_err("Sqlite3 error [%d] : <%s> finalizing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+       bxt_dbg("Get '%s' Key '%s'", dbpath, key);
+
+       return ret;
+}
+
+static int unset_value(const char *dbpath, const char *key)
+{
+       sqlite3 *db;
+       sqlite3_stmt *stmt;
+       int r;
+       int ret = 0;
+       const char delete_query[] = "delete from buxton where key = ?;";
+
+       if (!dbpath || !*dbpath || !key || !*key) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       db = open_sqlite3(dbpath, false);
+       if (!db)
+               return -1;
+
+       r = sqlite3_prepare_v2(db, delete_query, strlen(delete_query),
+                       &stmt, NULL);
+       if (r != SQLITE_OK) {
+               bxt_err("prepare error, ret = %d, extended = %d\n",
+                               r, sqlite3_extended_errcode(db));
+               return -1;
+       }
+
+       r = sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
+       if (r) {
+               bxt_err("Sqlite3 error [%d] : <%s> preparing <%s> querry\n", r,
+                               sqlite3_errmsg(db), delete_query);
+               ret = -1;
+               goto end;
+       }
+
+       r = sqlite3_step(stmt);
+       if (r != SQLITE_DONE) {
+               bxt_err("Sqlite3 error [%d] : <%s> executing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+end:
+       r = sqlite3_finalize(stmt);
+       if (r != SQLITE_OK) {
+               bxt_err("Sqlite3 error [%d] : <%s> finalizing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+       bxt_dbg("Unset '%s' Key '%s'", dbpath, key);
+
+       return ret;
+}
+
+static int list_keys(const char *dbpath, char ***keys, unsigned int *klen)
+{
+       sqlite3 *db;
+       GList *list;
+       GList *l;
+       int r;
+       int ret = 0;
+       int i;
+       unsigned int _klen;
+       char *_key;
+       char **_keys;
+       const char list_query[] = "select key from buxton";
+       sqlite3_stmt *stmt;
+
+       if (!dbpath || !*dbpath || !keys) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       db = open_sqlite3(dbpath, true);
+       if (!db)
+               return -1;
+
+       r = sqlite3_prepare_v2(db, list_query, strlen(list_query),
+                       &stmt, NULL);
+       if (r != SQLITE_OK) {
+               bxt_err("prepare error, ret = %d, extended = %d\n",
+                               r, sqlite3_extended_errcode(db));
+               return -1;
+       }
+
+       _klen = 0;
+       list = NULL;
+       while (sqlite3_step(stmt) == SQLITE_ROW) {
+               _key = (char *)sqlite3_column_text(stmt, 0);
+               list = g_list_append(list, strdup(_key));
+               _klen++;
+       }
+
+       /* +1 for NULL terminated */
+       _keys = malloc(sizeof(void *) * (_klen + 1));
+       if (!_keys) {
+               g_list_free_full(list, (GDestroyNotify)free);
+               errno = ENOMEM;
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0, l = list; l && i < _klen; l = g_list_next(l), i++)
+               _keys[i] = l->data;
+
+       _keys[i] = NULL;
+
+       g_list_free(list);
+
+       *keys = _keys;
+
+       if (klen)
+               *klen = _klen;
+
+end:
+       r = sqlite3_finalize(stmt);
+       if (r != SQLITE_OK) {
+               bxt_err("Sqlite3 error [%d] : <%s> finalizing statement\n", r,
+                               sqlite3_errmsg(db));
+               ret = -1;
+       }
+
+       bxt_dbg("List '%s'", dbpath);
+
+       return ret;
+}
+
+static void module_exit(void)
+{
+       g_hash_table_destroy(dbs);
+       dbs = NULL;
+}
+
+static int module_init(void)
+{
+       dbs = g_hash_table_new_full(g_str_hash, g_str_equal,
+                       (GDestroyNotify)free, (GDestroyNotify)free_db);
+       if (!dbs) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       return 0;
+}
+
+DEFINE_BUXTON_BACKEND = {
+       .name = "sqlite",
+
+       .module_init = module_init,
+       .module_exit = module_exit,
+
+       .open_db = open_db,
+       .close_db = close_db,
+       .remove_db = remove_db,
+       .set_value = set_value,
+       .get_value = get_value,
+       .unset_value = unset_value,
+       .list_keys = list_keys,
+};
+
index e726601..79e93c3 100644 (file)
@@ -4,24 +4,24 @@
 
 [system]
 Type=System
-Backend=gdbm
+Backend=sqlite
 Storage=persistent
 Description=System configuration layer
 
 [memory]
 Type=System
-Backend=gdbm
+Backend=sqlite
 Storage=volatile
 Description=Run-time settings
 
 [user]
 Type=User
-Backend=gdbm
+Backend=sqlite
 Storage=persistent
 Description=Per-user settings
 
 [user-memory]
 Type=User
-Backend=gdbm
+Backend=sqlite
 Storage=volatile
 Description=Per-user run-time settings
index 39c6a94..bffb0e2 100644 (file)
@@ -21,6 +21,7 @@ BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(libsystemd)
 BuildRequires:  pkgconfig(cynara-client-async)
 BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(sqlite3)
 Requires(post): /usr/bin/getent
 Requires(post): /usr/bin/chown
 Requires(post): /usr/sbin/useradd