From 87c7fa3cfdadca4ee883daf84373302a42ad5fdc Mon Sep 17 00:00:00 2001 From: Joseph Fernandes Date: Wed, 18 Feb 2015 19:45:23 +0530 Subject: Adding Libgfdb to GlusterFS ************************************************************************* Libgfdb | ************************************************************************* Libgfdb provides abstract mechanism to record extra/rich metadata required for data maintenance, such as data tiering/classification. It provides consumer with API for recording and querying, keeping the consumer abstracted from the data store used beneath for storing data. It works in a plug-and-play model, where data stores can be plugged-in. Presently we have plugin for Sqlite3. In the future will provide recording and querying performance optimizer. In the current implementation the schema of metadata is fixed. Schema: ~~~~~~ GF_FILE_TB Table: ~~~~~~~~~~~~~~~~~ This table has one entry per file inode. It holds the metadata required to make decisions in data maintenance. GF_ID (Primary key) : File GFID (Universal Unique IDentifier in the namespace) W_SEC, W_MSEC : Write wind time in sec & micro-sec UW_SEC, UW_MSEC : Write un-wind time in sec & micro-sec W_READ_SEC, W_READ_MSEC : Read wind time in sec & micro-sec UW_READ_SEC, UW_READ_MSEC : Read un-wind time in sec & micro-sec WRITE_FREQ_CNTR INTEGER : Write Frequency Counter READ_FREQ_CNTR INTEGER : Read Frequency Counter GF_FLINK_TABLE: ~~~~~~~~~~~~~~ This table has all the hardlinks to a file inode. GF_ID : File GFID (Composite Primary Key)``| GF_PID : Parent Directory GFID (Composite Primary Key) |-> Primary Key FNAME : File Base Name (Composite Primary Key)__| FPATH : File Full Path (Its redundant for now, this will go) W_DEL_FLAG : This Flag is used for crash consistancy, when a link is unlinked. i.e Set to 1 during unlink wind and during unwind this record is deleted LINK_UPDATE : This Flag is used when a link is changed i.e rename. Set to 1 when rename wind and set to 0 in rename unwind Libgfdb API: ~~~~~~~~~~~ Refer libglusterfs/src/gfdb/gfdb_data_store.h Change-Id: I2e9fbab3878ce630a7f41221ef61017dc43db11f BUG: 1194753 Signed-off-by: Joseph Fernandes Signed-off-by: Dan Lambright Signed-off-by: Joseph Fernandes Reviewed-on: http://review.gluster.org/9683 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- Makefile.am | 4 +- configure.ac | 38 +- glusterfs.spec.in | 2 + libgfdb.pc.in | 11 + libglusterfs/Makefile.am | 2 +- libglusterfs/src/gfdb/Makefile.am | 42 + libglusterfs/src/gfdb/gfdb_data_store.c | 649 +++++++++++++ libglusterfs/src/gfdb/gfdb_data_store.h | 219 +++++ libglusterfs/src/gfdb/gfdb_data_store_types.h | 733 +++++++++++++++ libglusterfs/src/gfdb/gfdb_mem-types.h | 22 + libglusterfs/src/gfdb/gfdb_sqlite3.c | 1101 ++++++++++++++++++++++ libglusterfs/src/gfdb/gfdb_sqlite3.h | 288 ++++++ libglusterfs/src/gfdb/gfdb_sqlite3_helper.c | 1128 +++++++++++++++++++++++ libglusterfs/src/gfdb/gfdb_sqlite3_helper.h | 64 ++ libglusterfs/src/mem-types.h | 12 + xlators/mgmt/glusterd/src/glusterd-volume-set.c | 1 - 16 files changed, 4305 insertions(+), 11 deletions(-) create mode 100644 libgfdb.pc.in create mode 100644 libglusterfs/src/gfdb/Makefile.am create mode 100644 libglusterfs/src/gfdb/gfdb_data_store.c create mode 100644 libglusterfs/src/gfdb/gfdb_data_store.h create mode 100644 libglusterfs/src/gfdb/gfdb_data_store_types.h create mode 100644 libglusterfs/src/gfdb/gfdb_mem-types.h create mode 100644 libglusterfs/src/gfdb/gfdb_sqlite3.c create mode 100644 libglusterfs/src/gfdb/gfdb_sqlite3.h create mode 100644 libglusterfs/src/gfdb/gfdb_sqlite3_helper.c create mode 100644 libglusterfs/src/gfdb/gfdb_sqlite3_helper.h diff --git a/Makefile.am b/Makefile.am index 60a8d36131d..3b71fa8a4ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ EXTRA_DIST = autogen.sh \ COPYING-GPLV2 COPYING-LGPLV3 \ INSTALL README.md AUTHORS THANKS NEWS \ - glusterfs.spec glusterfs-api.pc.in libgfchangelog.pc.in \ + glusterfs.spec glusterfs-api.pc.in libgfchangelog.pc.in libgfdb.pc.in \ run-tests.sh \ build-aux/pkg-version \ build-aux/xdrgen \ @@ -14,7 +14,7 @@ SUBDIRS = $(ARGP_STANDALONE_DIR) libglusterfs rpc api xlators glusterfsd \ @UMOUNTD_SUBDIR@ tools pkgconfigdir = @pkgconfigdir@ -pkgconfig_DATA = glusterfs-api.pc libgfchangelog.pc +pkgconfig_DATA = glusterfs-api.pc libgfchangelog.pc libgfdb.pc CLEANFILES = diff --git a/configure.ac b/configure.ac index c3f505bcc00..419e0a741e3 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,7 @@ AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile libglusterfs/Makefile libglusterfs/src/Makefile + libglusterfs/src/gfdb/Makefile geo-replication/src/peer_gsec_create geo-replication/src/peer_mountbroker extras/peer_add_secret_pub @@ -216,6 +217,7 @@ AC_CONFIG_FILES([Makefile contrib/uuid/uuid_types.h glusterfs-api.pc libgfchangelog.pc + libgfdb.pc api/Makefile api/src/Makefile api/examples/Makefile @@ -495,7 +497,7 @@ AM_CONDITIONAL([ENABLE_BD_XLATOR], [test x$BUILD_BD_XLATOR = xyes]) AC_CHECK_HEADERS([openssl/cmac.h], [have_cmac_h=yes], [have_cmac_h=no]) AC_ARG_ENABLE([crypt-xlator], - AC_HELP_STRING([--enable-crypt-xlator], [Build crypt encryption xlator])) + AC_HELP_STRING([--enable-crypt-xlator], [Build crypt encryption xlator])) if test "x$enable_crypt_xlator" = "xyes" -a "x$have_cmac_h" = "xno"; then AC_MSG_ERROR([Encryption xlator requires OpenSSL with cmac.h]) @@ -538,7 +540,7 @@ AC_ARG_ENABLE([qemu-block], if test "x$enable_qemu_block" != "xno"; then PKG_CHECK_MODULES([GLIB], [glib-2.0], [HAVE_GLIB_2="yes"], - [HAVE_GLIB_2="no"]) + [HAVE_GLIB_2="no"]) fi if test "x$enable_qemu_block" = "xyes" -a "x$HAVE_GLIB_2" = "xno"; then @@ -550,7 +552,7 @@ BUILD_QEMU_BLOCK=no if test "x${enable_qemu_block}" != "xno" -a "x${HAVE_GLIB_2}" = "xyes"; then BUILD_QEMU_BLOCK=yes AC_DEFINE(HAVE_QEMU_BLOCK, 1, [define if libglib-2.0 library found and QEMU - Block translator enabled]) + Block translator enabled]) fi @@ -675,6 +677,25 @@ AC_SUBST(ZLIB_CFLAGS) AC_SUBST(ZLIB_LIBS) # end CDC xlator secion +# Data tiering requires sqlite +AC_ARG_ENABLE([tiering], + AC_HELP_STRING([--disable-tiering], + [Disable data classification/tiering]), + [BUILD_GFDB="${enableval}"], [BUILD_GFDB="yes"]) + +if test "x${BUILD_GFDB}" = "xyes"; then + PKG_CHECK_MODULES([SQLITE], [sqlite3], + AC_DEFINE(USE_GFDB, 1), + AC_MSG_ERROR([pass --disable-tiering to build without sqlite])) +else + AC_DEFINE(USE_GFDB, 0, [no sqlite, gfdb is disabled]) +fi + +AC_SUBST(SQLITE_CFLAGS) +AC_SUBST(SQLITE_LIBS) +AM_CONDITIONAL(BUILD_GFDB, test "x${BUILD_GFDB}" = "xyes") +AM_CONDITIONAL(USE_GFDB, test "x${BUILD_GFDB}" = "xyes") + # check for systemtap/dtrace BUILD_SYSTEMTAP=no AC_MSG_CHECKING([whether to include systemtap tracing support]) @@ -718,12 +739,12 @@ if test "x$enable_xml_output" != "xno"; then if test "x${no_xml}" = "x"; then AC_DEFINE([HAVE_LIB_XML], [1], [Define to 1 if using libxml2.]) else - if test "x$enable_georeplication" != "xno"; then + if test "x$enable_georeplication" != "xno"; then AC_MSG_ERROR([libxml2 devel libraries not found]) - else - AC_MSG_WARN([libxml2 devel libraries not found disabling XML support]) + else + AC_MSG_WARN([libxml2 devel libraries not found disabling XML support]) BUILD_XML_OUTPUT="no" - fi + fi fi else @@ -1222,6 +1243,8 @@ GFAPI_VERSION="4."${PACKAGE_VERSION} LIBGFCHANGELOG_VERSION="0.0.1" AC_SUBST(GFAPI_VERSION) AC_SUBST(LIBGFCHANGELOG_VERSION) +LIBGFDB_VERSION="0.0.1" +AC_SUBST(LIBGFDB_VERSION) dnl libtool versioning LIBGFXDR_LT_VERSION="0:1:0" @@ -1265,4 +1288,5 @@ echo "QEMU Block formats : $BUILD_QEMU_BLOCK" echo "Encryption xlator : $BUILD_CRYPT_XLATOR" echo "Unit Tests : $BUILD_UNITTEST" echo "POSIX ACLs : $USE_POSIX_ACLS" +echo "Data Classification : $BUILD_GFDB" echo diff --git a/glusterfs.spec.in b/glusterfs.spec.in index 0df22cd3c4c..8325b44c409 100644 --- a/glusterfs.spec.in +++ b/glusterfs.spec.in @@ -207,6 +207,7 @@ BuildRequires: userspace-rcu-devel >= 0.7 %if ( 0%{?_with_cmocka:0} ) BuildRequires: libcmocka-devel >= 1.0.0 %endif +BuildRequires: sqlite-devel %if ( 0%{!?_without_systemtap:1} ) BuildRequires: systemtap-sdt-devel %endif @@ -913,6 +914,7 @@ fi %files api-devel %{_libdir}/pkgconfig/glusterfs-api.pc %{_libdir}/pkgconfig/libgfchangelog.pc +%{_libdir}/pkgconfig/libgfdb.pc %{_libdir}/libgfapi.so %{_includedir}/glusterfs/api/* diff --git a/libgfdb.pc.in b/libgfdb.pc.in new file mode 100644 index 00000000000..01b0381eff5 --- /dev/null +++ b/libgfdb.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + + +Name: libgfdb +Description: GlusterFS Database Library +Version: @LIBGFDB_VERSION@ +Libs: -L${libdir} -lgfchangedb -lglusterfs -lsqlite3 +Cflags: -I${includedir}/glusterfs/gfdb diff --git a/libglusterfs/Makefile.am b/libglusterfs/Makefile.am index d471a3f9243..8e5a4a0ccbf 100644 --- a/libglusterfs/Makefile.am +++ b/libglusterfs/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = src +SUBDIRS = src src/gfdb CLEANFILES = diff --git a/libglusterfs/src/gfdb/Makefile.am b/libglusterfs/src/gfdb/Makefile.am new file mode 100644 index 00000000000..8c48463aed3 --- /dev/null +++ b/libglusterfs/src/gfdb/Makefile.am @@ -0,0 +1,42 @@ +libgfdb_la_CFLAGS = -Wall $(GF_CFLAGS) $(GF_DARWIN_LIBGLUSTERFS_CFLAGS) \ + -DDATADIR=\"$(localstatedir)\" + +libgfdb_la_CPPFLAGS = $(GF_CPPFLAGS) -D__USE_FILE_OFFSET64 -fpic \ + -I$(top_srcdir)/libglusterfs/src \ + -DDATADIR=\"$(localstatedir)\" + +libgfdb_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -lsqlite3 + +libgfdb_la_LDFLAGS = $(GF_LDFLAGS) -version-info $(LIBGLUSTERFS_LT_VERSION) + +libgfdbdir = $(includedir)/glusterfs/gfdb + +if BUILD_GFDB + lib_LTLIBRARIES = libgfdb.la +endif + +CONTRIB_BUILDDIR = $(top_builddir)/contrib + +libgfdb_la_SOURCES = gfdb_data_store.c gfdb_sqlite3_helper.c\ + gfdb_sqlite3.c \ + $(CONTRIBDIR)/uuid/clear.c \ + $(CONTRIBDIR)/uuid/copy.c $(CONTRIBDIR)/uuid/gen_uuid.c \ + $(CONTRIBDIR)/uuid/pack.c $(CONTRIBDIR)/uuid/parse.c \ + $(CONTRIBDIR)/uuid/unparse.c $(CONTRIBDIR)/uuid/uuid_time.c \ + $(CONTRIBDIR)/uuid/compare.c $(CONTRIBDIR)/uuid/isnull.c \ + $(CONTRIBDIR)/uuid/unpack.c + +noinst_HEADERS = gfdb_data_store.h gfdb_data_store_types.h gfdb_sqlite3_helper.h\ + gfdb_sqlite3.h gfdb_mem-types.h \ + $(CONTRIBDIR)/uuid/uuidd.h \ + $(CONTRIBDIR)/uuid/uuid.h $(CONTRIBDIR)/uuid/uuid.h \ + $(CONTRIB_BUILDDIR)/uuid/uuid_types.h + +libgfdb_HEADERS = gfdb_data_store.h gfdb_data_store_types.h \ + gfdb_sqlite3.h gfdb_mem-types.h gfdb_sqlite3_helper.c + +CLEANFILES = +CONFIG_CLEAN_FILES = $(CONTRIB_BUILDDIR)/uuid/uuid_types.h + +$(top_builddir)/libglusterfs/src/libglusterfs.la: + $(MAKE) -C $(top_builddir)/libglusterfs/src/ all diff --git a/libglusterfs/src/gfdb/gfdb_data_store.c b/libglusterfs/src/gfdb/gfdb_data_store.c new file mode 100644 index 00000000000..b250ece91e4 --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_data_store.c @@ -0,0 +1,649 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "gfdb_data_store.h" +#include "list.h" + +/****************************************************************************** + * + * Database Connection utils/internals + * + * ****************************************************************************/ + +/* GFDB Connection Node: + * ~~~~~~~~~~~~~~~~~~~~ + * Represents the connection to the database while using libgfdb + * The connection node is not thread safe as far as fini_db is concerned. + * You can use a single connection node + * to do multithreaded db operations like insert/delete/find of records. + * But you need to wait for all the operating threads to complete i.e + * pthread_join() and then do fini_db() to kill the connection node. + * gfdb_conn_node_t is an opaque structure. + * */ +struct gfdb_conn_node_t { + gfdb_connection_t gfdb_connection; + struct list_head conn_list; +}; + + +/* + * db_conn_list is the circular linked list which + * will have all the database connections for the process + * + * */ +static gfdb_conn_node_t *db_conn_list; + +/* + * db_conn_mutex is the mutex for db_conn_list + * + * */ +static pthread_mutex_t db_conn_mutex = PTHREAD_MUTEX_INITIALIZER; + + +/*Checks the sanity of the connection node*/ +#define CHECK_CONN_NODE(_conn_node)\ +do {\ + GF_ASSERT (_conn_node);\ + GF_ASSERT (_conn_node->gfdb_connection.gf_db_connection);\ +} while (0) + + +/*Check if the conn node is first in the list*/ +#define IS_FIRST_NODE(db_conn_list, _conn_node)\ + ((_conn_node == db_conn_list) ? _gf_true : _gf_false) + + +/*Check if the conn node is the only node in the list*/ +#define IS_THE_ONLY_NODE(_conn_node)\ +((_conn_node->conn_list.next == _conn_node->conn_list.prev)\ + ? _gf_true : _gf_false) + + + +/*Internal Function: Adds connection node to the end of + * the db connection list.*/ +static int +add_connection_node (gfdb_conn_node_t *_conn_node) { + int ret = -1; + + GF_ASSERT (_conn_node); + + /*Lock the list*/ + ret = pthread_mutex_lock (&db_conn_mutex); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed lock db connection list %s", strerror(ret)); + ret = -1; + goto out; + } + + if (db_conn_list == NULL) { + db_conn_list = _conn_node; + } else { + list_add_tail (&_conn_node->conn_list, + &db_conn_list->conn_list); + } + + /*unlock the list*/ + ret = pthread_mutex_unlock (&db_conn_mutex); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed unlock db connection list %s", strerror(ret)); + ret = -1; + /*TODO What if the unlock fails. + * Will it lead to deadlock? + * Most of the gluster code + * no check for unlock or destory of mutex!*/ + } + ret = 0; +out: + return ret; +} + + +/*Internal Function: + * Delete connection node from the list*/ +static inline int +delete_conn_node (gfdb_conn_node_t *_conn_node) +{ + int ret = -1; + + GF_ASSERT (_conn_node); + + /*Lock of the list*/ + ret = pthread_mutex_lock (&db_conn_mutex); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed lock on db connection list %s", strerror(ret)); + goto out; + } + + /*Remove the connection object from list*/ + if (IS_THE_ONLY_NODE(_conn_node)) { + db_conn_list = NULL; + GF_FREE (_conn_node); + } else { + if (IS_FIRST_NODE(db_conn_list, _conn_node)) { + db_conn_list = list_entry (db_conn_list->conn_list.next, + gfdb_conn_node_t, + conn_list); + } + list_del(&_conn_node->conn_list); + GF_FREE (_conn_node); + } + + /*Release the list lock*/ + ret = pthread_mutex_unlock (&db_conn_mutex); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_WARNING, + "Failed unlock on db connection" + " list %s", strerror(ret)); + /*TODO What if the unlock fails. + * Will it lead to deadlock? + * Most of the gluster code + * no check for unlock or destory of mutex!*/ + ret = -1; + goto out; + } + ret = 0; +out: + return ret; +} + + +/*Internal function: Used initialize/map db operation of + * specified type of db plugin*/ +static int +init_db_operations (gfdb_db_type_t gfdb_db_type, + gfdb_db_operations_t *gfdb_db_operations) { + + int ret = -1; + + GF_ASSERT (gfdb_db_operations); + + /*Clear the gfdb_db_operations*/ + gfdb_db_operations = memset(gfdb_db_operations, 0, + sizeof(*gfdb_db_operations)); + switch (gfdb_db_type) { + case GFDB_SQLITE3: + gf_sqlite3_fill_db_operations (gfdb_db_operations); + ret = 0; + break; + case GFDB_HYPERDEX: + case GFDB_HASH_FILE_STORE: + case GFDB_ROCKS_DB: + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, "Plugin not supported"); + break; + case GFDB_INVALID_DB: + case GFDB_DB_END: + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, "Invalid DB Type"); + break; + } + return ret; +} + + +/****************************************************************************** + * + * LIBGFDB API Functions + * + * ****************************************************************************/ + + +/*Libgfdb API Function: Used to initialize a db connection + * (Constructor function for db connection object) + * Arguments: + * args : Dictionary containing database specific parameters + * eg: For sqlite3, pagesize, cachesize, db name, db path + etc + * gfdb_db_type : Type of data base used i.e sqlite or hyperdex etc + * Returns : if successful return the GFDB Connection node to the caller or + * NULL in case of failure*/ +gfdb_conn_node_t * +init_db (dict_t *args, gfdb_db_type_t gfdb_db_type) +{ + int ret = -1; + gfdb_conn_node_t *_conn_node = NULL; + gfdb_db_operations_t *db_operations_t = NULL; + + /*Create data base connection object*/ + _conn_node = GF_CALLOC (1, sizeof(gfdb_conn_node_t), + gf_mt_db_conn_node_t); + if (!_conn_node) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed mem alloc for gfdb_conn_node_t!"); + goto alloc_failed; + } + + /*Init the list component of db conneciton object*/ + INIT_LIST_HEAD (&_conn_node->conn_list); + + + /*Add created connection node to the list*/ + ret = add_connection_node (_conn_node); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed to add connection node to list"); + goto _conn_failed; + } + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + + /*init the db ops object of db connection object*/ + ret = init_db_operations(gfdb_db_type, db_operations_t); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed initializing database operation failed."); + ret = -1; + goto init_db_failed; + } + + /*Calling the init_db_op of the respected db type*/ + GF_ASSERT (db_operations_t->init_db_op); + ret = db_operations_t->init_db_op (args, &_conn_node->gfdb_connection. + gf_db_connection); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed initializing database"); + ret = -1; + goto init_db_failed; + } + _conn_node->gfdb_connection.gfdb_db_type = gfdb_db_type; + ret = 0; + + return _conn_node; + + /*****Error Handling********/ + /* If init_db_operations or init_db of plugin failed delete + * conn node from the list. + * connection node will be free by delete_conn_node*/ +init_db_failed: + ret = delete_conn_node (_conn_node); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed deleting connection node from list"); + } + return NULL; + /*if adding to the list failed free connection node*/ +_conn_failed: + GF_FREE (_conn_node); + /*if allocation failed*/ +alloc_failed: + return NULL; + /*****Error Handling********/ +} + + + + + +/*Libgfdb API Function: Used to terminate/de-initialize db connection + * (Destructor function for db connection object) + * Arguments: + * _conn_node : GFDB Connection node + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +fini_db (gfdb_conn_node_t *_conn_node) +{ + int ret = -1; + gfdb_db_operations_t *db_operations_t = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + + GF_ASSERT (db_operations_t->fini_db_op); + + ret = db_operations_t->fini_db_op(&_conn_node->gfdb_connection. + gf_db_connection); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed close the db connection"); + goto out; + } + + ret = delete_conn_node (_conn_node); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Failed deleting connection node from list"); + } + + ret = 0; +out: + return ret; +} + + + + + + +/*Libgfdb API Function: Used to insert/update records in the database + * NOTE: In current gfdb_sqlite plugin we use that + * same function to delete the record. Set the + * gfdb_fop_path to GFDB_FOP_UNDEL to delete the + * link of inode from GF_FLINK_TB and + * GFDB_FOP_UNDEL_ALL to delete all the records from + * GF_FLINK_TB and GF_FILE_TB. + * TODO: Should seperate this function into the + * delete_record function + * Refer CTR Xlator features/changetimerecorder for usage + * Arguments: + * _conn_node : GFDB Connection node + * gfdb_db_record : Record to be inserted/updated + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +insert_record (gfdb_conn_node_t *_conn_node, + gfdb_db_record_t *gfdb_db_record) +{ + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->insert_record_op) { + + ret = db_operations_t->insert_record_op (gf_db_connection, + gfdb_db_record); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Insert/Update operation failed!"); + } + } + + return ret; +} + + + + +/*Libgfdb API Function: Used to delete record from the database + * NOTE: In the current gfdb_sqlite3 plugin + * implementation this function is dummy. + * Use the insert_record function. + * Refer CTR Xlator features/changetimerecorder for usage + * Arguments: + * _conn_node : GFDB Connection node + * gfdb_db_record : Record to be deleted + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +delete_record (gfdb_conn_node_t *_conn_node, + gfdb_db_record_t *gfdb_db_record) +{ + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->delete_record_op) { + + ret = db_operations_t->delete_record_op (gf_db_connection, + gfdb_db_record); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Delete operation failed!"); + } + + } + + return ret; +} + + + + + +/*Libgfdb API Function: Query all the records from the database + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +find_all(gfdb_conn_node_t *_conn_node, gf_query_callback_t query_callback, + void *_query_cbk_args) { + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->find_all_op) { + ret = db_operations_t->find_all_op (gf_db_connection, + query_callback, + _query_cbk_args); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Find all operation failed!"); + } + + } + + return ret; +} + + + +/*Libgfdb API Function: Query records/files that have not changed/accessed + * from a time in past to current time + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are not + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +find_unchanged_for_time(gfdb_conn_node_t *_conn_node, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *for_time) { + + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->find_unchanged_for_time_op) { + + ret = db_operations_t->find_unchanged_for_time_op + (gf_db_connection, + query_callback, + _query_cbk_args, + for_time); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Find unchanged operation failed!"); + } + + } + + return ret; +} + +/*Libgfdb API Function: Query records/files that have changed/accessed from a + * time in past to current time + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +find_recently_changed_files(gfdb_conn_node_t *_conn_node, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *from_time) { + + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->find_recently_changed_files_op) { + + ret = db_operations_t->find_recently_changed_files_op ( + gf_db_connection, + query_callback, + _query_cbk_args, + from_time); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Find changed operation failed!"); + } + + } + + return ret; + +} + +/*Libgfdb API Function: Query records/files that have not changed/accessed + * from a time in past to current time, with + * a desired frequency + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are not + * changed/accessed + * write_freq_thresold : Desired Write Frequency lower limit + * read_freq_thresold : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +find_unchanged_for_time_freq(gfdb_conn_node_t *_conn_node, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *for_time, + int write_freq_thresold, + int read_freq_thresold, + gf_boolean_t _clear_counters) { + + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->find_unchanged_for_time_freq_op) { + + ret = db_operations_t->find_unchanged_for_time_freq_op( + gf_db_connection, + query_callback, + _query_cbk_args, + for_time, + write_freq_thresold, + read_freq_thresold, + _clear_counters); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Find unchanged with freq operation failed!"); + } + + } + + return ret; +} + +/*Libgfdb API Function: Query records/files that have changed/accessed from a + * time in past to current time, with + * a desired frequency + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are + * changed/accessed + * write_freq_thresold : Desired Write Frequency lower limit + * read_freq_thresold : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +find_recently_changed_files_freq(gfdb_conn_node_t *_conn_node, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *from_time, + int write_freq_thresold, + int read_freq_thresold, + gf_boolean_t _clear_counters) { + + int ret = 0; + gfdb_db_operations_t *db_operations_t = NULL; + void *gf_db_connection = NULL; + + CHECK_CONN_NODE(_conn_node); + + db_operations_t = &_conn_node->gfdb_connection.gfdb_db_operations; + gf_db_connection = _conn_node->gfdb_connection.gf_db_connection; + + if (db_operations_t->find_recently_changed_files_freq_op) { + + ret = db_operations_t->find_recently_changed_files_freq_op( + gf_db_connection, + query_callback, + _query_cbk_args, + from_time, + write_freq_thresold, + read_freq_thresold, + _clear_counters); + if (ret) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Find changed with freq operation failed!"); + } + + } + + return ret; + +} diff --git a/libglusterfs/src/gfdb/gfdb_data_store.h b/libglusterfs/src/gfdb/gfdb_data_store.h new file mode 100644 index 00000000000..1212c2b3fe1 --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_data_store.h @@ -0,0 +1,219 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef __GFDB_DATA_STORE_H +#define __GFDB_DATA_STORE_H + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "common-utils.h" +#include +#include + +#include "gfdb_data_store_types.h" +#include "gfdb_sqlite3.h" + + +/* GFDB Connection Node: + * ~~~~~~~~~~~~~~~~~~~~ + * Represents the connection to the database while using libgfdb + * The connection node is not thread safe as far as fini_db is concerned. + * You can use a single connection node + * to do multithreaded db operations like insert/delete/find of records. + * But you need to wait for all the operating threads to complete i.e + * pthread_join() and then do fini_db() to kill the connection node. + * gfdb_conn_node_t is an opaque structure. + * */ +typedef struct gfdb_conn_node_t gfdb_conn_node_t; + + + + +/*Libgfdb API Function: Used to initialize db connection + * Arguments: + * args : Dictionary containing database specific parameters + * eg: For sqlite3, pagesize, cachesize, db name, db path + etc + * gfdb_db_type : Type of data base used i.e sqlite or hyperdex etc + * Returns : if successful return the GFDB Connection Node to the caller or + * NULL value in case of failure*/ +gfdb_conn_node_t * +init_db(dict_t *arg, gfdb_db_type_t db_type); + + + + + +/*Libgfdb API Function: Used to terminate/de-initialize db connection + * (Destructor function for db connection object) + * Arguments: + * _conn_node : DB Connection Index of the DB Connection + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +fini_db(gfdb_conn_node_t *); + + + + +/*Libgfdb API Function: Used to insert/updated records in the database + * NOTE: In current gfdb_sqlite plugin we use that + * same function to delete the record. Set the + * gfdb_fop_path to GFDB_FOP_UNDEL to delete the + * link of inode from GF_FLINK_TB and + * GFDB_FOP_UNDEL_ALL to delete all the records from + * GF_FLINK_TB and GF_FILE_TB. + * TODO: Should seperate this function into the + * delete_record function + * Refer CTR Xlator features/changetimerecorder for usage + * Arguments: + * _conn_node : GFDB Connection node + * gfdb_db_record : Record to be inserted/updated + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +insert_record(gfdb_conn_node_t *, gfdb_db_record_t *gfdb_db_record); + + + + +/*Libgfdb API Function: Used to delete record from the database + * NOTE: In the current gfdb_sqlite3 plugin + * implementation this function is dummy. + * Use the insert_record function. + * Refer CTR Xlator features/changetimerecorder for usage + * Arguments: + * _conn_node : GFDB Connection node + * gfdb_db_record : Record to be deleted + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int +delete_record(gfdb_conn_node_t *, gfdb_db_record_t *gfdb_db_record); + + + + + +/*Libgfdb API Function: Query all the records from the database + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int find_all(gfdb_conn_node_t *, gf_query_callback_t query_callback, + void *_query_cbk_args); + + + + + +/*Libgfdb API Function: Query records/files that have not changed/accessed + * from a time in past to current time + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are not + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int find_unchanged_for_time(gfdb_conn_node_t *, + gf_query_callback_t query_callback, + void *_query_cbk_args, gfdb_time_t *for_time); + + + + +/*Libgfdb API Function: Query records/files that have changed/accessed from a + * time in past to current time + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int find_recently_changed_files(gfdb_conn_node_t *_conn, + gf_query_callback_t query_callback, void *_query_cbk_args, + gfdb_time_t *from_time); + + + + + +/*Libgfdb API Function: Query records/files that have not changed/accessed + * from a time in past to current time, with + * a desired frequency + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are not + * changed/accessed + * write_freq_thresold : Desired Write Frequency lower limit + * read_freq_thresold : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int find_unchanged_for_time_freq(gfdb_conn_node_t *_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *for_time, + int write_freq_thresold, + int read_freq_thresold, + gf_boolean_t _clear_counters); + + + + + +/*Libgfdb API Function: Query records/files that have changed/accessed from a + * time in past to current time, with + * a desired frequency + * Arguments: + * _conn_node : GFDB Connection node + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are + * changed/accessed + * write_freq_thresold : Desired Write Frequency lower limit + * read_freq_thresold : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +int find_recently_changed_files_freq(gfdb_conn_node_t *_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *from_time, + int write_freq_thresold, + int read_freq_thresold, + gf_boolean_t _clear_counters); + +#endif diff --git a/libglusterfs/src/gfdb/gfdb_data_store_types.h b/libglusterfs/src/gfdb/gfdb_data_store_types.h new file mode 100644 index 00000000000..e3a2c76435b --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_data_store_types.h @@ -0,0 +1,733 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef __GFDB_DATA_STORE_TYPE_H +#define __GFDB_DATA_STORE_TYPE_H + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "common-utils.h" +#include "gfdb_mem-types.h" +#include "dict.h" + +typedef enum gf_db_operation { + GFDB_INVALID_DB_OP = -1, + /* Query DB OPS : All the Query DB_OP should be added */ + /* in between START and END */ + GFDB_QUERY_DB_OP_START, /* Start of Query DB_OP */ + GFDB_QUERY_DB_OP, + GF_FTABLE_EXISTS_DB_OP, + GFDB_QUERY_DB_OP_END, /* End of Query DB_OP */ + /* Non-Query DB OPS */ + GFDB_DB_CREATE_DB_OP, + GFDB_GFID_EXIST_DB_OP, + GFDB_W_INSERT_DB_OP, + GFDB_WU_INSERT_DB_OP, + GFDB_W_UPDATE_DB_OP, + GFDB_WU_UPDATE_DB_OP, + GFDB_W_DELETE_DB_OP, + GFDB_UW_DELETE_DB_OP, + GFDB_WFC_UPDATE_DB_OP, + GFDB_RFC_UPDATE_DB_OP +} gf_db_operation_t; + + +#define GF_COL_MAX_NUM 2 +#define GF_COL_ALL " * " + +/* Column/fields names used in the DB. + * If any new field is added should be updated here*/ +#define GF_COL_GF_ID "GF_ID" +#define GF_COL_GF_PID "GF_PID" +#define GF_COL_FILE_NAME "FNAME" +#define GF_COL_FPATH "FPATH" +#define GF_COL_WSEC "W_SEC" +#define GF_COL_WMSEC "W_MSEC" +#define GF_COL_UWSEC "UW_SEC" +#define GF_COL_UWMSEC "UW_MSEC" +#define GF_COL_WSEC_READ "W_READ_SEC" +#define GF_COL_WMSEC_READ "W_READ_MSEC" +#define GF_COL_UWSEC_READ "UW_READ_SEC" +#define GF_COL_UWMSEC_READ "UW_READ_MSEC" +#define GF_COL_WDEL_FLAG "W_DEL_FLAG" +#define GF_COL_WRITE_FREQ_CNTR "WRITE_FREQ_CNTR" +#define GF_COL_READ_FREQ_CNTR "READ_FREQ_CNTR" +#define GF_COL_LINK_UPDATE "LINK_UPDATE" + + + + +/***********************Time related********************************/ +/*1 sec = 1000000 microsec*/ +#define GFDB_MICROSEC 1000000 + +/*All the gfdb times are represented using this structure*/ +typedef struct timeval gfdb_time_t; + +/*Convert time into seconds*/ +static inline long int +gfdb_time_2_usec(gfdb_time_t *gfdb_time) +{ + GF_ASSERT(gfdb_time); + return gfdb_time->tv_sec * GFDB_MICROSEC + gfdb_time->tv_usec; +} + + + + + +/****************************************************************************** + * + * Insert/Update Record related data structures/functions + * + * ****************************************************************************/ + + + + +/*Indicated a generic synchronous write to the db + * This may or may not be implemented*/ +typedef enum gfdb_sync_type { + GFDB_INVALID_SYNC = -1, + GFDB_DB_ASYNC, + GFDB_DB_SYNC +} gfdb_sync_type_t; + +/*Strings related to the abvove sync type*/ +#define GFDB_STR_DB_ASYNC "async" +#define GFDB_STR_DB_SYNC "sync" + +/*To convert sync type from string to gfdb_sync_type_t*/ +static inline int +gf_string2gfdbdbsync (char *sync_option) +{ + int ret = -1; + + if (!sync_option) + goto out; + if (strcmp(sync_option, GFDB_STR_DB_ASYNC) == 0) { + ret = GFDB_DB_ASYNC; + } else if (strcmp(sync_option, GFDB_STR_DB_SYNC) == 0) { + ret = GFDB_DB_SYNC; + } +out: + return ret; +} + + + + + + +/*Indicated different types of db*/ +typedef enum gfdb_db_type { + GFDB_INVALID_DB = -1, + GFDB_HASH_FILE_STORE, + GFDB_ROCKS_DB, + GFDB_SQLITE3, + GFDB_HYPERDEX, + GFDB_DB_END /*Add DB type Entries above this only*/ +} gfdb_db_type_t; + +/*String related to the db types*/ +#define GFDB_DATA_STORE "gfdbdatastore" +#define GFDB_STR_HASH_FILE_STORE "hashfile" +#define GFDB_STR_ROCKS_DB "rocksdb" +#define GFDB_STR_SQLITE3 "sqlite3" +#define GFDB_STR_HYPERDEX "hyperdex" + +/*Convert db type in string to gfdb_db_type_t*/ +static inline int +gf_string2gfdbdbtype (char *db_option) +{ + int ret = -1; + + if (!db_option) + goto out; + if (strcmp(db_option, GFDB_STR_HASH_FILE_STORE) == 0) { + ret = GFDB_HASH_FILE_STORE; + } else if (strcmp(db_option, GFDB_STR_ROCKS_DB) == 0) { + ret = GFDB_ROCKS_DB; + } else if (strcmp(db_option, GFDB_STR_SQLITE3) == 0) { + ret = GFDB_SQLITE3; + } else if (strcmp(db_option, GFDB_STR_HYPERDEX) == 0) { + ret = GFDB_HYPERDEX; + } +out: + return ret; +} + + + + + + + +/*Tells the path of the fop*/ +typedef enum gfdb_fop_path { + GFDB_FOP_INVALID = -1, + /*Filler value for zero*/ + GFDB_FOP_PATH_ZERO = 0, + /*have wind path below this*/ + GFDB_FOP_WIND = 1, + GFDB_FOP_WDEL = 2, + /*have unwind path below this*/ + GFDB_FOP_UNWIND = 4, + /*Delete unwind path*/ + GFDB_FOP_UNDEL = 8, + GFDB_FOP_UNDEL_ALL = 16 +} gfdb_fop_path_t; +/*Strings related to the above fop path*/ +#define GFDB_STR_FOP_INVALID "INVALID" +#define GFDB_STR_FOP_WIND "ENTRY" +#define GFDB_STR_FOP_UNWIND "EXIT" +#define GFDB_STR_FOP_WDEL "WDEL" +#define GFDB_STR_FOP_UNDEL "UNDEL" + +static inline gf_boolean_t +iswindpath(gfdb_fop_path_t gfdb_fop_path) +{ + return ((gfdb_fop_path == GFDB_FOP_WIND) || + (gfdb_fop_path == GFDB_FOP_WDEL)) ? + _gf_true : _gf_false; +} + +static inline gf_boolean_t +isunwindpath(gfdb_fop_path_t gfdb_fop_path) +{ + return (gfdb_fop_path >= GFDB_FOP_UNWIND) ? _gf_true : _gf_false; +} + + + + + + + +/*Tell what type of fop it was + * Like whether a dentry fop or a inode fop + * Read fop or a write fop etc*/ +typedef enum gfdb_fop_type { + GFDB_FOP_INVALID_OP = -1, + /*Filler value for zero*/ + GFDB_FOP_TYPE_ZERO = 0, + GFDB_FOP_DENTRY_OP = 1, + GFDB_FOP_DENTRY_CREATE_OP = 2, + GFDB_FOP_INODE_OP = 4, + GFDB_FOP_WRITE_OP = 8, + GFDB_FOP_READ_OP = 16 +} gfdb_fop_type_t; + +#define GFDB_FOP_INODE_WRITE\ + (GFDB_FOP_INODE_OP | GFDB_FOP_WRITE_OP) + +#define GFDB_FOP_DENTRY_WRITE\ + (GFDB_FOP_DENTRY_OP | GFDB_FOP_WRITE_OP) + +#define GFDB_FOP_CREATE_WRITE\ + (GFDB_FOP_DENTRY_CREATE_OP | GFDB_FOP_WRITE_OP) + +#define GFDB_FOP_INODE_READ\ + (GFDB_FOP_INODE_OP | GFDB_FOP_READ_OP) + +static inline gf_boolean_t +isreadfop(gfdb_fop_type_t fop_type) +{ + return (fop_type & GFDB_FOP_READ_OP) ? _gf_true : _gf_false; +} + +static inline gf_boolean_t +isdentryfop(gfdb_fop_type_t fop_type) +{ + return ((fop_type & GFDB_FOP_DENTRY_OP) || + (fop_type & GFDB_FOP_DENTRY_CREATE_OP)) ? _gf_true : _gf_false; +} + +static inline gf_boolean_t +isdentrycreatefop(gfdb_fop_type_t fop_type) +{ + return (fop_type & GFDB_FOP_DENTRY_CREATE_OP) ? + _gf_true : _gf_false; +} + + + + + + + +/*The structure that is used to send insert/update the databases + * using insert_db api*/ +typedef struct gfdb_db_record { + uuid_t gfid; + uuid_t pargfid; + uuid_t old_pargfid; + char file_name[PATH_MAX]; + char file_path[PATH_MAX]; + char old_file_name[PATH_MAX]; + char old_path[PATH_MAX]; + gfdb_fop_type_t gfdb_fop_type; + gfdb_fop_path_t gfdb_fop_path; + /*Time of change or access*/ + gfdb_time_t gfdb_wind_change_time; + gfdb_time_t gfdb_unwind_change_time; + /* For crash consistancy while inserting/updating hard links */ + gf_boolean_t islinkupdate; + /* For dentry fops we can choose to ignore recording of unwind time */ + /* For inode fops "record_exit" volume option does the trick, */ + /* but for dentry fops we update the LINK_UPDATE, so an extra */ + /* flag is provided to ignore the recording of the unwind time. */ + gf_boolean_t do_record_uwind_time; + gf_boolean_t do_record_counters; +} gfdb_db_record_t; + + + +/******************************************************************************* + * + * Query related data structure and functions + * + * ****************************************************************************/ + + + +/*Structure used for querying purpose*/ +typedef struct gfdb_query_record { + /*Inode info*/ + uuid_t gfid; + /*All the hard link of the inode + * All the hard links will be queried as + * "GF_PID,FNAME,FPATH,W_DEL_FLAG,LINK_UPDATE" + * and multiple hardlinks will be seperated by "::"*/ + /*Do only shallow copy. The gf_query_callback_t */ + /* function should do the deep copy.*/ + char *_link_info_str; + ssize_t link_info_size; +} gfdb_query_record_t; + +/*Function to create the query_record*/ +static inline gfdb_query_record_t * +gfdb_query_record_init() +{ + int ret = -1; + gfdb_query_record_t *gfdb_query_record = NULL; + + gfdb_query_record = GF_CALLOC (1, sizeof(gfdb_query_record_t), + gf_mt_gfdb_query_record_t); + if (!gfdb_query_record) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Error allocating memory to gfdb_query_record "); + goto out; + } + ret = 0; +out: + if (ret == -1) { + GF_FREE (gfdb_query_record); + } + return gfdb_query_record; +} + +/*Function to destroy query record*/ +static inline void +gfdb_query_record_fini(gfdb_query_record_t + **gfdb_query_record) { + GF_FREE (*gfdb_query_record); +} + + + + + + + + +/*Structure to hold the link information*/ +typedef struct gfdb_link_info { + uuid_t pargfid; + char file_name[PATH_MAX]; + char file_path[PATH_MAX]; + gf_boolean_t is_link_updated; + gf_boolean_t is_del_flag_set; +} gfdb_link_info_t; + +/*Create a single link info structure*/ +static inline gfdb_link_info_t * +gfdb_link_info_init () +{ + gfdb_link_info_t *gfdb_link_info = NULL; + + gfdb_link_info = GF_CALLOC (1, sizeof(gfdb_link_info_t), + gf_mt_gfdb_link_info_t); + if (!gfdb_link_info) { + gf_log (GFDB_DATA_STORE, GF_LOG_ERROR, + "Error allocating memory to gfdb_link_info "); + } + + return gfdb_link_info; +} + +/*Destroy a link info structure*/ +static inline void +gfdb_link_info_fini(gfdb_link_info_t **gfdb_link_info) +{ + if (gfdb_link_info) + GF_FREE (*gfdb_link_info); +} + + +/*Length of each hard link string */ +#define DEFAULT_LINK_INFO_STR_LEN 1024 + +/* Parse a single link string into link_info structure + * Input format of str_link + * "GF_PID,FNAME,FPATH,W_DEL_FLAG,LINK_UPDATE" + * + * */ +static inline int +str_to_link_info (char *str_link, + gfdb_link_info_t *link_info) +{ + int ret = -1; + const char *delimiter = ","; + char *token_str = NULL; + char *saveptr = NULL; + char gfid[200] = ""; + + GF_ASSERT (str_link); + GF_ASSERT (link_info); + + /*Parent GFID*/ + token_str = strtok_r(str_link, delimiter, &saveptr); + if (token_str != NULL) { + strcpy (gfid, token_str); + ret = uuid_parse (gfid, link_info->pargfid); + if (ret == -1) + goto out; + } + + /*Filename*/ + token_str = strtok_r(NULL, delimiter, &saveptr); + if (token_str != NULL) { + strcpy (link_info->file_name, token_str); + } + + /*Filepath*/ + token_str = strtok_r(NULL, delimiter, &saveptr); + if (token_str != NULL) { + strcpy (link_info->file_path, token_str); + } + + /*is_link_updated*/ + token_str = strtok_r(NULL, delimiter, &saveptr); + if (token_str != NULL) { + link_info->is_link_updated = atoi(token_str); + if (link_info->is_link_updated != 0 && + link_info->is_link_updated != 1) { + goto out; + } + } + + /*is_del_flag_set*/ + token_str = strtok_r(NULL, delimiter, &saveptr); + if (token_str != NULL) { + link_info->is_del_flag_set = atoi (token_str); + if (link_info->is_del_flag_set != 0 && + link_info->is_del_flag_set != 1) { + goto out; + } + } + ret = 0; +out: + return ret; +} + + +/******************************************************************************* + * + * Signatures for the plugin functions + * i.e Any plugin should implementment + * these functions to integrate with + * libgfdb. + * + * ****************************************************************************/ + +/*Call back function for querying the database*/ +typedef int +(*gf_query_callback_t)(gfdb_query_record_t *, void *); + +/* Used to initialize db connection + * Arguments: + * args : Dictionary containing database specific parameters + * db_conn : pointer to plugin specific data base connection + * that will be created. If the call is successful + * db_conn will contain the plugin specific connection + * If call is unsuccessful will have NULL. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_init_db_t)(dict_t *args, void **db_conn); + + + + +/* Used to terminate/de-initialize db connection + * (Destructor function for db connection object) + * Arguments: + * db_conn : plugin specific data base connection + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_fini_db_t)(void **db_conn); + + + + +/*Used to insert/updated records in the database + * Arguments: + * db_conn : plugin specific data base connection + * gfdb_db_record : Record to be inserted/updated + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_insert_record_t)(void *db_conn, + gfdb_db_record_t *db_record); + + + + +/*Used to delete record from the database + * Arguments: + * db_conn : plugin specific data base connection + * gfdb_db_record : Record to be deleted + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_delete_record_t)(void *db_conn, + gfdb_db_record_t *db_record); + + + + +/* Query all the records from the database + * Arguments: + * db_conn : plugin specific data base connection + * query_callback : Call back function that will be called + * for every record found + * _query_cbk_args : Custom argument passed for the call back + * function query_callback + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_find_all_t)(void *db_conn, + gf_query_callback_t query_callback, + void *_cbk_args); + + + + +/* Query records/files that have not changed/accessed + * from a time in past to current time + * Arguments: + * db_conn : plugin specific data base connection + * query_callback : Call back function that will be called + * for every record found + * _cbk_args : Custom argument passed for the call back + * function query_callback + * for_time : Time from where the file/s are not + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_find_unchanged_for_time_t)(void *db_conn, + gf_query_callback_t query_callback, + void *_cbk_args, + gfdb_time_t *_time); + + + +/* Query records/files that have changed/accessed from a + * time in past to current time + * Arguments: + * db_conn : plugin specific data base connection + * query_callback : Call back function that will be called + * for every record found + * _cbk_args : Custom argument passed for the call back + * function query_callback + * _time : Time from where the file/s are + * changed/accessed + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_find_recently_changed_files_t)(void *db_conn, + gf_query_callback_t query_callback, + void *_cbk_args, gfdb_time_t *_time); + +/* Query records/files that have not changed/accessed + * from a time in past to current time, with + * a desired frequency + * + * Arguments: + * db_conn : plugin specific data base connection + * query_callback : Call back function that will be called + * for every record found + * _cbk_args : Custom argument passed for the call back + * function query_callback + * _time : Time from where the file/s are not + * changed/accessed + * _write_freq : Desired Write Frequency lower limit + * _read_freq : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_find_unchanged_for_time_freq_t) + (void *db_conn, + gf_query_callback_t query_callback, + void *_cbk_args, gfdb_time_t *_time, + int _write_freq, int _read_freq, + gf_boolean_t _clear_counters); + + + + +/* Query records/files that have changed/accessed from a + * time in past to current time, with a desired frequency + * Arguments: + * db_conn : plugin specific data base connection + * query_callback : Call back function that will be called + * for every record found + * _cbk_args : Custom argument passed for the call back + * function query_callback + * _time : Time from where the file/s are + * changed/accessed + * _write_freq : Desired Write Frequency lower limit + * _read_freq : Desired Read Frequency lower limit + * _clear_counters : If true, Clears all the frequency counters of + * all files. + * Returns : if successful return 0 or + * -ve value in case of failure*/ +typedef int +(*gfdb_find_recently_changed_files_freq_t)(void *db_conn, + gf_query_callback_t query_callback, + void *_cbk_args, gfdb_time_t *_time, + int _write_freq, int _read_freq, + gf_boolean_t _clear_counters); + + + + +/*Data structure holding all the above plugin function pointers*/ +typedef struct gfdb_db_operations { + gfdb_init_db_t init_db_op; + gfdb_fini_db_t fini_db_op; + gfdb_insert_record_t insert_record_op; + gfdb_delete_record_t delete_record_op; + gfdb_find_all_t find_all_op; + gfdb_find_unchanged_for_time_t find_unchanged_for_time_op; + gfdb_find_recently_changed_files_t find_recently_changed_files_op; + gfdb_find_unchanged_for_time_freq_t + find_unchanged_for_time_freq_op; + gfdb_find_recently_changed_files_freq_t + find_recently_changed_files_freq_op; +} gfdb_db_operations_t; + + + +/******************************************************************************* + * + * Database connection object: This objected is maitained by libgfdb for each + * database connection created. + * gf_db_connection : DB connection specific to the plugin + * gfdb_db_operations : Contains all the libgfdb API implementation + * from the plugin. + * gfdb_db_type : Type of database + * + * ****************************************************************************/ + + +typedef struct gfdb_connection { + void *gf_db_connection; + gfdb_db_operations_t gfdb_db_operations; + gfdb_db_type_t gfdb_db_type; +} gfdb_connection_t; + + + + +/******************************************************************************* + * + * Macros for get and set db options + * + * ****************************************************************************/ + + +/*Set param_key : str_value into param_dict*/ +#define SET_DB_PARAM_TO_DICT(comp_name, params_dict, param_key,\ + str_value, ret, error)\ + do {\ + data_t *data = NULL;\ + data = str_to_data (str_value);\ + if (!data)\ + goto error;\ + ret = dict_add (params_dict, param_key, data);\ + if (ret) {\ + gf_log (comp_name, GF_LOG_ERROR,\ + "Failed setting %s to params dictionary",\ + param_key);\ + goto error;\ + };\ + } while (0) + +/*get str_value of param_key from param_dict*/ +#define GET_DB_PARAM_FROM_DICT(comp_name, params_dict, param_key, str_value,\ + error)\ + do {\ + data_t *data = NULL;\ + data = dict_get (params_dict, param_key);\ + if (!data) {\ + gf_log (comp_name, GF_LOG_ERROR,\ + "Failed retriving %s from params", param_key);\ + goto error;\ + } else {\ + str_value = data->data;\ + };\ + } while (0) + + +/*get str_value of param_key from param_dict. if param_key is not present + * set _default_v to str_value */ +#define GET_DB_PARAM_FROM_DICT_DEFAULT(comp_name, params_dict, param_key,\ + str_value, _default_v)\ + do {\ + data_t *data = NULL;\ + data = dict_get (params_dict, param_key);\ + if (!data) {\ + str_value = _default_v;\ + gf_log (comp_name, GF_LOG_WARNING,\ + "Failed retriving %s from params"\ + "Assigning default value: %s",\ + param_key, _default_v);\ + } else {\ + str_value = data->data;\ + };\ + } while (0) + + +#endif + + diff --git a/libglusterfs/src/gfdb/gfdb_mem-types.h b/libglusterfs/src/gfdb/gfdb_mem-types.h new file mode 100644 index 00000000000..2a84b47fcf5 --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_mem-types.h @@ -0,0 +1,22 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + + +#ifndef __GFDB_MEM_TYPES_H__ +#define __GFDB_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gfdb_mem_types_ { + gfdb_mtstart = gf_common_mt_end + 1, + gfdb_mt_end +}; +#endif + diff --git a/libglusterfs/src/gfdb/gfdb_sqlite3.c b/libglusterfs/src/gfdb/gfdb_sqlite3.c new file mode 100644 index 00000000000..818691d7cea --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_sqlite3.c @@ -0,0 +1,1101 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "gfdb_sqlite3.h" +#include "gfdb_sqlite3_helper.h" + +/****************************************************************************** + * + * Util functions + * + * ***************************************************************************/ +inline gf_sql_connection_t * +gf_sql_connection_init () +{ + gf_sql_connection_t *gf_sql_conn = NULL; + + gf_sql_conn = GF_CALLOC (1, sizeof(gf_sql_connection_t), + gf_mt_sql_connection_t); + if (gf_sql_conn == NULL) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Error allocating memory to gf_sql_connection_t "); + } + + return gf_sql_conn; +} + +inline void +gf_sql_connection_fini (gf_sql_connection_t **sql_connection) +{ + if (!sql_connection) + return; + GF_FREE (*sql_connection); + *sql_connection = NULL; +} + +inline const char * +gf_sql_jm2str (gf_sql_journal_mode_t jm) +{ + switch (jm) { + case gf_sql_jm_delete: + return GF_SQL_JM_DELETE; + case gf_sql_jm_truncate: + return GF_SQL_JM_TRUNCATE; + case gf_sql_jm_persist: + return GF_SQL_JM_PERSIST; + case gf_sql_jm_memory: + return GF_SQL_JM_MEMORY; + case gf_sql_jm_wal: + return GF_SQL_JM_WAL; + case gf_sql_jm_off: + return GF_SQL_JM_OFF; + case gf_sql_jm_invalid: + break; + } + return NULL; +} + +inline gf_sql_journal_mode_t +gf_sql_str2jm (const char *jm_str) +{ + if (!jm_str) { + return gf_sql_jm_invalid; + } else if (strcmp(jm_str, GF_SQL_JM_DELETE) == 0) { + return gf_sql_jm_delete; + } else if (strcmp(jm_str, GF_SQL_JM_TRUNCATE) == 0) { + return gf_sql_jm_truncate; + } else if (strcmp(jm_str, GF_SQL_JM_PERSIST) == 0) { + return gf_sql_jm_persist; + } else if (strcmp(jm_str, GF_SQL_JM_MEMORY) == 0) { + return gf_sql_jm_memory; + } else if (strcmp(jm_str, GF_SQL_JM_WAL) == 0) { + return gf_sql_jm_wal; + } else if (strcmp(jm_str, GF_SQL_JM_OFF) == 0) { + return gf_sql_jm_off; + } + return gf_sql_jm_invalid; +} + +inline const char * +gf_sql_av_t2str (gf_sql_auto_vacuum_t sql_av) +{ + switch (sql_av) { + case gf_sql_av_none: + return GF_SQL_AV_NONE; + case gf_sql_av_full: + return GF_SQL_AV_FULL; + case gf_sql_av_incr: + return GF_SQL_AV_INCR; + case gf_sql_av_invalid: + break; + } + return NULL; +} + +inline gf_sql_auto_vacuum_t +gf_sql_str2av_t (const char *av_str) +{ + if (!av_str) { + return gf_sql_sync_invalid; + } else if (strcmp(av_str, GF_SQL_AV_NONE) == 0) { + return gf_sql_av_none; + } else if (strcmp(av_str, GF_SQL_AV_FULL) == 0) { + return gf_sql_av_full; + } else if (strcmp(av_str, GF_SQL_AV_INCR) == 0) { + return gf_sql_av_incr; + } + return gf_sql_sync_invalid; +} + +inline const char * +gf_sync_t2str (gf_sql_sync_t sql_sync) +{ + switch (sql_sync) { + case gf_sql_sync_off: + return GF_SQL_SYNC_OFF; + case gf_sql_sync_normal: + return GF_SQL_SYNC_NORMAL; + case gf_sql_sync_full: + return GF_SQL_SYNC_FULL; + case gf_sql_sync_invalid: + break; + } + return NULL; +} + +inline gf_sql_sync_t +gf_sql_str2sync_t (const char *sync_str) +{ + if (!sync_str) { + return gf_sql_sync_invalid; + } else if (strcmp(sync_str, GF_SQL_SYNC_OFF) == 0) { + return gf_sql_sync_off; + } else if (strcmp(sync_str, GF_SQL_SYNC_NORMAL) == 0) { + return gf_sql_sync_normal; + } else if (strcmp(sync_str, GF_SQL_SYNC_FULL) == 0) { + return gf_sql_sync_full; + } + return gf_sql_sync_invalid; +} + + +/*TODO replace GF_CALLOC by mem_pool or iobuff if required for performace */ +static inline char * +sql_stmt_init () +{ + char *sql_stmt = NULL; + + sql_stmt = GF_CALLOC (GF_STMT_SIZE_MAX, sizeof(char), + gf_common_mt_char); + + if (!sql_stmt) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Error allocating memory to SQL Statement "); + goto out; + } +out: + return sql_stmt; +} + +/*TODO replace GF_FREE by mem_pool or iobuff if required for performace */ +static inline void +sql_stmt_fini (char **sql_stmt) +{ + GF_FREE (*sql_stmt); +} + +/****************************************************************************** + * DB Essential functions used by + * create/insert/delete/update/query functions + * > execute_sqlstmt () + * > gf_open_sqlite3_conn () + * > gf_close_sqlite3_conn () + * ***************************************************************************/ +static sqlite3 * +gf_open_sqlite3_conn(char *sqlite3_db_path, int flags) +{ + sqlite3 *sqlite3_db_conn = NULL; + int ret = -1; + + GF_ASSERT (sqlite3_db_path); + + /*Creates DB if not created*/ + ret = sqlite3_open_v2(sqlite3_db_path, &sqlite3_db_conn, flags, NULL); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "FATAL: Could open %s : %s", + sqlite3_db_path, sqlite3_errmsg(sqlite3_db_conn)); + } + return sqlite3_db_conn; +} + +static int +gf_close_sqlite3_conn(sqlite3 *sqlite3_db_conn) +{ + int ret = 0; + + GF_ASSERT (sqlite3_db_conn); + + if (sqlite3_db_conn) { + ret = sqlite3_close (sqlite3_db_conn); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "FATAL: sqlite3 close connection failed %s", + sqlite3_errmsg(sqlite3_db_conn)); + ret = -1; + goto out; + } + } + ret = 0; +out: + return ret; +} + +/****************************************************************************** +* +* Database init / fini / create table +* +* ***************************************************************************/ + + +/*Function to fill db operations*/ +void +gf_sqlite3_fill_db_operations(gfdb_db_operations_t *gfdb_db_ops) +{ + GF_ASSERT (gfdb_db_ops); + + gfdb_db_ops->init_db_op = gf_sqlite3_init; + gfdb_db_ops->fini_db_op = gf_sqlite3_fini; + + gfdb_db_ops->insert_record_op = gf_sqlite3_insert; + gfdb_db_ops->delete_record_op = gf_sqlite3_delete; + + gfdb_db_ops->find_all_op = gf_sqlite3_find_all; + gfdb_db_ops->find_unchanged_for_time_op = + gf_sqlite3_find_unchanged_for_time; + gfdb_db_ops->find_recently_changed_files_op = + gf_sqlite3_find_recently_changed_files; + gfdb_db_ops->find_unchanged_for_time_freq_op = + gf_sqlite3_find_unchanged_for_time_freq; + gfdb_db_ops->find_recently_changed_files_freq_op = + gf_sqlite3_find_recently_changed_files_freq; +} + + +static int +create_filetable (sqlite3 *sqlite3_db_conn) +{ + int ret = -1; + char *sql_stmt = NULL; + char *sql_strerror = NULL; + + GF_ASSERT(sqlite3_db_conn); + + sql_stmt = sql_stmt_init(); + if (!sql_stmt) { + ret = ENOMEM; + goto out; + } + + GF_CREATE_STMT(sql_stmt); + + ret = sqlite3_exec (sqlite3_db_conn, sql_stmt, NULL, NULL, + &sql_strerror); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing: %s : %s", + sql_stmt, sql_strerror); + sqlite3_free (sql_strerror); + ret = -1; + goto out; + } + + + ret = 0; +out: + sql_stmt_fini (&sql_stmt); + return ret; +} + + + + +static inline int +apply_sql_params_db(gf_sql_connection_t *sql_conn, dict_t *param_dict) +{ + int ret = -1; + char *temp_str = NULL; + char sqlite3_config_str[PATH_MAX] = ""; + + GF_ASSERT(sql_conn); + GF_ASSERT(param_dict); + + /*Extract sql page_size from param_dict, + * if not specified default value will be GF_SQL_DEFAULT_PAGE_SIZE*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_PAGE_SIZE, temp_str, + GF_SQL_DEFAULT_PAGE_SIZE); + sql_conn->page_size = atoi(temp_str); + /*Apply page_size on the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "page_size", "%ld", + sql_conn->page_size, ret, out); + + + + /*Extract sql cache size from param_dict, + * if not specified default value will be + * GF_SQL_DEFAULT_CACHE_SIZE pages*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_CACHE_SIZE, temp_str, + GF_SQL_DEFAULT_CACHE_SIZE); + sql_conn->cache_size = atoi(temp_str); + /*Apply cache size on the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "cache_size", "%ld", + sql_conn->cache_size, ret, out); + + + + + /*Extract sql journal mode from param_dict, + * if not specified default value will be + * GF_SQL_DEFAULT_JOURNAL_MODE i.e "wal"*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_JOURNAL_MODE, temp_str, + GF_SQL_DEFAULT_JOURNAL_MODE); + sql_conn->journal_mode = gf_sql_str2jm (temp_str); + /*Apply journal mode to the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "journal_mode", "%s", + temp_str, ret, out); + + + + /*Only when the journal mode is WAL, wal_autocheckpoint makes sense*/ + if (sql_conn->journal_mode == gf_sql_jm_wal) { + /*Extract sql wal auto check point from param_dict + * if not specified default value will be + * GF_SQL_DEFAULT_WAL_AUTOCHECKPOINT pages*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_WAL_AUTOCHECK, temp_str, + GF_SQL_DEFAULT_WAL_AUTOCHECKPOINT); + sql_conn->wal_autocheckpoint = atoi(temp_str); + /*Apply wal auto check point to the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "wal_autocheckpoint", + "%ld", sql_conn->wal_autocheckpoint, ret, out); + } + + + + /*Extract sql synchronous from param_dict + * if not specified default value will be GF_SQL_DEFAULT_SYNC*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_SYNC, temp_str, GF_SQL_DEFAULT_SYNC); + sql_conn->synchronous = gf_sql_str2sync_t (temp_str); + /*Apply synchronous to the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "synchronous", "%d", + sql_conn->synchronous, ret, out); + + + + /*Extract sql auto_vacuum from param_dict + * if not specified default value will be GF_SQL_DEFAULT_AUTO_VACUUM*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT(GFDB_STR_SQLITE3, param_dict, + GFDB_SQL_PARAM_AUTO_VACUUM, temp_str, + GF_SQL_DEFAULT_AUTO_VACUUM); + sql_conn->auto_vacuum = gf_sql_str2av_t (temp_str); + /*Apply auto_vacuum to the sqlite db*/ + GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, "auto_vacuum", "%d", + sql_conn->auto_vacuum, ret, out); + + ret = 0; +out: + return ret; +} + + + +int +gf_sqlite3_init (dict_t *args, void **db_conn) { + int ret = -1; + gf_sql_connection_t *sql_conn = NULL; + struct stat stbuf = {0,}; + gf_boolean_t is_dbfile_exist = _gf_false; + char *temp_str = NULL; + + GF_ASSERT (args); + GF_ASSERT (db_conn); + + if (*db_conn != NULL) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "DB Connection is not empty!"); + return 0; + } + + if (!sqlite3_threadsafe()) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "sqlite3 is not in multithreaded mode"); + goto out; + } + + sql_conn = gf_sql_connection_init (); + if (!sql_conn) { + goto out; + } + + /*Extract sql db path from args*/ + temp_str = NULL; + GET_DB_PARAM_FROM_DICT(GFDB_STR_SQLITE3, args, + GFDB_SQL_PARAM_DBPATH, temp_str, out); + strncpy(sql_conn->sqlite3_db_path, temp_str, PATH_MAX); + + is_dbfile_exist = (stat (sql_conn->sqlite3_db_path, &stbuf) == 0) ? + _gf_true : _gf_false; + + /*Creates DB if not created*/ + sql_conn->sqlite3_db_conn = gf_open_sqlite3_conn ( + sql_conn->sqlite3_db_path, + SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE); + if (!sql_conn->sqlite3_db_conn) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed creating db connection"); + goto out; + } + + /* If the file exist we skip the config part + * and create the schema if NOT Present*/ + if (is_dbfile_exist) + goto create_table; + + + /*Apply sqlite3 params to database*/ + ret = apply_sql_params_db(sql_conn, args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed applying sql params to %s", + sql_conn->sqlite3_db_path); + goto out; + } + +/*Create the schema if NOT present*/ +create_table: + + ret = create_filetable (sql_conn->sqlite3_db_conn); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Creating %s Table", GF_FILE_TABLE); + goto out; + } + ret = 0; + +out: + if (ret) { + gf_sqlite3_fini ((void **)&sql_conn); + } + + *db_conn = sql_conn; + + return ret; +} + + +int +gf_sqlite3_fini (void **db_conn) +{ + int ret = -1; + gf_sql_connection_t *sql_conn = NULL; + + GF_ASSERT (db_conn); + sql_conn = *db_conn; + + if (sql_conn) { + if (sql_conn->sqlite3_db_conn) { + ret = gf_close_sqlite3_conn(sql_conn->sqlite3_db_conn); + if (ret) { + /*Logging of error done in + * gf_close_sqlite3_conn()*/ + goto out; + } + sql_conn->sqlite3_db_conn = NULL; + } + gf_sql_connection_fini (&sql_conn); + } + *db_conn = sql_conn; + ret = 0; +out: + return ret; +} + +/****************************************************************************** + * + * INSERT/UPDATE/DELETE Operations + * + * + * ***************************************************************************/ + +int gf_sqlite3_insert(void *db_conn, gfdb_db_record_t *gfdb_db_record) +{ + int ret = -1; + gf_sql_connection_t *sql_conn = db_conn; + + CHECK_SQL_CONN(sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, gfdb_db_record, out); + + + /*This is for debugging bug. Will be removed with a bug fix*/ + if ((GFDB_FOP_WIND == gfdb_db_record->gfdb_fop_path) && + (strncmp(gfdb_db_record->file_path, "gfdb_fop_type); + goto out; + } + + switch (gfdb_db_record->gfdb_fop_path) { + case GFDB_FOP_WIND: + ret = gf_sql_insert_wind(sql_conn, gfdb_db_record); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed wind insert"); + goto out; + } + break; + case GFDB_FOP_UNWIND: + ret = gf_sql_insert_unwind (sql_conn, gfdb_db_record); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed unwind insert"); + goto out; + } + break; + + case GFDB_FOP_WDEL: + ret = gf_sql_update_delete_wind(sql_conn, gfdb_db_record); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed updating delete during wind"); + goto out; + } + break; + case GFDB_FOP_UNDEL: + case GFDB_FOP_UNDEL_ALL: + ret = gf_sql_delete_unwind(sql_conn, gfdb_db_record); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed deleting"); + goto out; + } + break; + case GFDB_FOP_INVALID: + default: + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Cannot record to DB: Invalid FOP"); + goto out; + } + + ret = 0; +out: + return ret; +} + +int +gf_sqlite3_delete(void *db_conn, gfdb_db_record_t *gfdb_db_record) +{ + int ret = -1; + gf_sql_connection_t *sql_conn = db_conn; + + CHECK_SQL_CONN(sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, gfdb_db_record, out); + + ret = 0; +out: + return ret; +} + +/****************************************************************************** + * + * SELECT QUERY FUNCTIONS + * + * + * ***************************************************************************/ + +/* + * Find All files recorded in the DB + * Input: + * query_callback : query callback fuction to handle + * result records from the query + * */ +int +gf_sqlite3_find_all (void *db_conn, gf_query_callback_t query_callback, + void *query_cbk_args) +{ + int ret = -1; + char *query_str = NULL; + gf_sql_connection_t *sql_conn = db_conn; + sqlite3_stmt *prep_stmt = NULL; + + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, query_callback, out); + + query_str = "select GF_FILE_TB.GF_ID," + " (select group_concat( GF_PID || ',' || FNAME || ','" + " || FPATH || ',' || W_DEL_FLAG ||',' || LINK_UPDATE , '::')" + " from GF_FLINK_TB where " + "GF_FILE_TB.GF_ID = GF_FLINK_TB.GF_ID) from GF_FILE_TB ;"; + + + ret = sqlite3_prepare(sql_conn->sqlite3_db_conn, query_str, -1, + &prep_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing statment %s : %s", query_str, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + ret = gf_sql_query_function(prep_stmt, query_callback, query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Query %s", query_str); + goto out; + } + + ret = 0; +out: + sqlite3_finalize(prep_stmt); + return ret; +} + + +/* + * Find recently changed files from the DB + * Input: + * query_callback : query callback fuction to handle + * result records from the query + * from_time : Time to define what is recent + * */ +int +gf_sqlite3_find_recently_changed_files(void *db_conn, + gf_query_callback_t query_callback, + void *query_cbk_args, + gfdb_time_t *from_time) +{ + int ret = -1; + char *query_str = NULL; + gf_sql_connection_t *sql_conn = db_conn; + sqlite3_stmt *prep_stmt = NULL; + long int from_time_usec = 0; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, query_callback, out); + + query_str = "select GF_FILE_TB.GF_ID," + " (select group_concat( GF_PID || ',' || FNAME || ','" + " || FPATH || ',' || W_DEL_FLAG ||',' || LINK_UPDATE , '::')" + " from GF_FLINK_TB where GF_FILE_TB.GF_ID = GF_FLINK_TB.GF_ID)" + " from GF_FILE_TB where " + /*First condition: For writes*/ + "((" GF_COL_TB_WSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_WMSEC ") >= ? )" + " OR " + /*Second condition: For reads*/ + "((" GF_COL_TB_RWSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_RWMSEC ") >= ?)"; + + from_time_usec = gfdb_time_2_usec(from_time); + + ret = sqlite3_prepare(sql_conn->sqlite3_db_conn, query_str, -1, + &prep_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing statment %s : %s", query_str, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 1, from_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding from_time_usec %ld : %s", + from_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind read wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 2, from_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding from_time_usec %ld : %s ", + from_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the query*/ + ret = gf_sql_query_function(prep_stmt, query_callback, query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Query %s", query_str); + goto out; + } + + ret = 0; +out: + sqlite3_finalize(prep_stmt); + return ret; +} + + +/* + * Find unchanged files from a specified time from the DB + * Input: + * query_callback : query callback fuction to handle + * result records from the query + * for_time : Time from where the file/s are not changed + * */ +int +gf_sqlite3_find_unchanged_for_time (void *db_conn, + gf_query_callback_t query_callback, + void *query_cbk_args, + gfdb_time_t *for_time) +{ + int ret = -1; + char *query_str = NULL; + gf_sql_connection_t *sql_conn = db_conn; + sqlite3_stmt *prep_stmt = NULL; + long int for_time_usec = 0; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, query_callback, out); + + query_str = "select GF_FILE_TB.GF_ID," + " (select group_concat( GF_PID || ',' || FNAME || ','" + " || FPATH || ',' || W_DEL_FLAG ||',' || LINK_UPDATE , '::')" + " from GF_FLINK_TB where GF_FILE_TB.GF_ID = GF_FLINK_TB.GF_ID)" + " from GF_FILE_TB where " + /*First condition: For writes*/ + "((" GF_COL_TB_WSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_WMSEC ") <= ? )" + " OR " + /*Second condition: For reads*/ + "((" GF_COL_TB_RWSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_RWMSEC ") <= ?)"; + + for_time_usec = gfdb_time_2_usec(for_time); + + ret = sqlite3_prepare(sql_conn->sqlite3_db_conn, query_str, -1, + &prep_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing statment %s : %s", query_str, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 1, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind read wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 2, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the query*/ + ret = gf_sql_query_function(prep_stmt, query_callback, query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Query %s", query_str); + goto out; + } + + ret = 0; +out: + sqlite3_finalize(prep_stmt); + return ret; +} + + + + + +/* + * Find recently changed files with a specific frequency from the DB + * Input: + * db_conn : db connection object + * query_callback : query callback fuction to handle + * result records from the query + * from_time : Time to define what is recent + * freq_write_cnt : Frequency thresold for write + * freq_read_cnt : Frequency thresold for read + * clear_counters : Clear counters (r/w) for all inodes in DB + * */ +int +gf_sqlite3_find_recently_changed_files_freq (void *db_conn, + gf_query_callback_t query_callback, + void *query_cbk_args, + gfdb_time_t *from_time, + int freq_write_cnt, + int freq_read_cnt, + gf_boolean_t clear_counters) +{ + int ret = -1; + char *query_str = NULL; + gf_sql_connection_t *sql_conn = db_conn; + sqlite3_stmt *prep_stmt = NULL; + long int from_time_usec = 0; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, query_callback, out); + + query_str = "select GF_FILE_TB.GF_ID," + " (select group_concat( GF_PID || ',' || FNAME || ','" + " || FPATH || ',' || W_DEL_FLAG ||',' || LINK_UPDATE , '::')" + " from GF_FLINK_TB where GF_FILE_TB.GF_ID = GF_FLINK_TB.GF_ID)" + " from GF_FILE_TB where " + /*First condition: For Writes*/ + "( ((" GF_COL_TB_WSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_WMSEC ") >= ? )" + " AND "" (" GF_COL_TB_WFC " > = ? ) )" + " OR " + /*Second condition: For Reads */ + "( ((" GF_COL_TB_RWSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_RWMSEC ") <= ?)" + " AND "" (" GF_COL_TB_RFC " > = ? ) )"; + + from_time_usec = gfdb_time_2_usec(from_time); + + ret = sqlite3_prepare(sql_conn->sqlite3_db_conn, query_str, -1, + &prep_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing statment %s : %s", query_str, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 1, from_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding from_time_usec %ld : %s", + from_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write frequency thresold*/ + ret = sqlite3_bind_int(prep_stmt, 2, freq_write_cnt); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding freq_write_cnt %d : %s", freq_write_cnt, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + /*Bind read wind time*/ + ret = sqlite3_bind_int64(prep_stmt, 3, from_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding from_time_usec %ld : %s", + from_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind read frequency thresold*/ + ret = sqlite3_bind_int(prep_stmt, 4, freq_read_cnt); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding freq_read_cnt %d : %s", freq_read_cnt, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the query*/ + ret = gf_sql_query_function(prep_stmt, query_callback, query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Query %s", query_str); + goto out; + } + + + + /*Clear counters*/ + if (clear_counters) { + ret = gf_sql_clear_counters(sql_conn); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed clearing counters!"); + goto out; + } + } + ret = 0; +out: + sqlite3_finalize (prep_stmt); + return ret; +} + + + + +/* + * Find unchanged files from a specified time, w.r.t to frequency, from the DB + * Input: + * query_callback : query callback fuction to handle + * result records from the query + * for_time : Time from where the file/s are not changed + * freq_write_cnt : Frequency thresold for write + * freq_read_cnt : Frequency thresold for read + * clear_counters : Clear counters (r/w) for all inodes in DB + * */ +int +gf_sqlite3_find_unchanged_for_time_freq (void *db_conn, + gf_query_callback_t query_callback, + void *query_cbk_args, + gfdb_time_t *for_time, + int freq_write_cnt, + int freq_read_cnt, + gf_boolean_t clear_counters) +{ + int ret = -1; + char *query_str = NULL; + gf_sql_connection_t *sql_conn = db_conn; + sqlite3_stmt *prep_stmt = NULL; + long int for_time_usec = 0; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, query_callback, out); + + query_str = "select GF_FILE_TB.GF_ID," + " (select group_concat( GF_PID || ',' || FNAME || ','" + " || FPATH || ',' || W_DEL_FLAG ||',' || LINK_UPDATE , '::')" + " from GF_FLINK_TB where GF_FILE_TB.GF_ID = GF_FLINK_TB.GF_ID)" + " from GF_FILE_TB where " + /*First condition: For Writes + * Files that have write wind time smaller than for_time + * OR + * File that have write wind time greater than for_time, + * but write_frequency less than freq_write_cnt*/ + "( ((" GF_COL_TB_WSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_WMSEC ") < ? )" + " OR " + "( (" GF_COL_TB_WFC " < ? ) AND" + "((" GF_COL_TB_WSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_WMSEC ") >= ? ) ) )" + " OR " + /*Second condition: For Reads + * Files that have read wind time smaller than for_time + * OR + * File that have read wind time greater than for_time, + * but write_frequency less than freq_write_cnt*/ + "( ((" GF_COL_TB_RWSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_RWMSEC ") < ? )" + " OR " + "( (" GF_COL_TB_RFC " < ? ) AND" + "((" GF_COL_TB_RWSEC " * " TOSTRING(GFDB_MICROSEC) " + " + GF_COL_TB_RWMSEC ") >= ? ) ) )"; + + + for_time_usec = gfdb_time_2_usec(for_time); + + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, query_str, -1, + &prep_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing delete statment %s : %s", query_str, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write wind time*/ + ret = sqlite3_bind_int64 (prep_stmt, 1, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", + for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write frequency thresold*/ + ret = sqlite3_bind_int (prep_stmt, 2, freq_write_cnt); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding freq_write_cnt %d : %s", + freq_write_cnt, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind write wind time*/ + ret = sqlite3_bind_int64 (prep_stmt, 3, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", + for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + + /*Bind read wind time*/ + ret = sqlite3_bind_int64 (prep_stmt, 4, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", + for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind read frequency thresold*/ + ret = sqlite3_bind_int (prep_stmt, 5, freq_read_cnt); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding freq_read_cnt %d : %s", + freq_read_cnt, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind read wind time*/ + ret = sqlite3_bind_int64 (prep_stmt, 6, for_time_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding for_time_usec %ld : %s", + for_time_usec, + sqlite3_errmsg(sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the query*/ + ret = gf_sql_query_function (prep_stmt, query_callback, query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed Query %s", query_str); + goto out; + } + + + /*Clear counters*/ + if (clear_counters) { + ret = gf_sql_clear_counters (sql_conn); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed clearing counters!"); + goto out; + } + } + + ret = 0; +out: + sqlite3_finalize(prep_stmt); + return ret; +} diff --git a/libglusterfs/src/gfdb/gfdb_sqlite3.h b/libglusterfs/src/gfdb/gfdb_sqlite3.h new file mode 100644 index 00000000000..b0c4b2b5fdd --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_sqlite3.h @@ -0,0 +1,288 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef __GFDB_SQLITE3_H +#define __GFDB_SQLITE3_H + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +/*Sqlite3 header file*/ +#include + +#include "logging.h" +#include "gfdb_data_store_types.h" +#include "gfdb_mem-types.h" + +#define GF_STMT_SIZE_MAX 2048 + +#define GF_DB_NAME "gfdb.db" +#define GF_FILE_TABLE "GF_FILE_TB" +#define GF_FILE_LINK_TABLE "GF_FLINK_TB" +#define GF_MASTER_TABLE "sqlite_master" + +/*Since we have multiple tables to be created we put it in a transaction*/ +#define GF_CREATE_STMT(out_str)\ +do {\ + sprintf (out_str , "BEGIN; CREATE TABLE IF NOT EXISTS "\ + GF_FILE_TABLE\ + "(GF_ID TEXT PRIMARY KEY NOT NULL, "\ + "W_SEC INTEGER NOT NULL DEFAULT 0, "\ + "W_MSEC INTEGER NOT NULL DEFAULT 0, "\ + "UW_SEC INTEGER NOT NULL DEFAULT 0, "\ + "UW_MSEC INTEGER NOT NULL DEFAULT 0, "\ + "W_READ_SEC INTEGER NOT NULL DEFAULT 0, "\ + "W_READ_MSEC INTEGER NOT NULL DEFAULT 0, "\ + "UW_READ_SEC INTEGER NOT NULL DEFAULT 0, "\ + "UW_READ_MSEC INTEGER NOT NULL DEFAULT 0, "\ + "WRITE_FREQ_CNTR INTEGER NOT NULL DEFAULT 1, "\ + "READ_FREQ_CNTR INTEGER NOT NULL DEFAULT 1); "\ + "CREATE TABLE IF NOT EXISTS "\ + GF_FILE_LINK_TABLE\ + "(GF_ID TEXT NOT NULL, "\ + "GF_PID TEXT NOT NULL, "\ + "FNAME TEXT NOT NULL, "\ + "FPATH TEXT NOT NULL, "\ + "W_DEL_FLAG INTEGER NOT NULL DEFAULT 0, "\ + "LINK_UPDATE INTEGER NOT NULL DEFAULT 0, "\ + "PRIMARY KEY ( GF_ID, GF_PID, FNAME) "\ + ");"\ + "COMMIT;"\ + );;\ +} while (0) + + +#define GF_COL_TB_WSEC GF_FILE_TABLE "." GF_COL_WSEC +#define GF_COL_TB_WMSEC GF_FILE_TABLE "." GF_COL_WMSEC +#define GF_COL_TB_UWSEC GF_FILE_TABLE "." GF_COL_UWSEC +#define GF_COL_TB_UWMSEC GF_FILE_TABLE "." GF_COL_UWMSEC +#define GF_COL_TB_RWSEC GF_FILE_TABLE "." GF_COL_WSEC_READ +#define GF_COL_TB_RWMSEC GF_FILE_TABLE "." GF_COL_WMSEC_READ +#define GF_COL_TB_RUWSEC GF_FILE_TABLE "." GF_COL_UWSEC_READ +#define GF_COL_TB_RUWMSEC GF_FILE_TABLE "." GF_COL_UWMSEC_READ +#define GF_COL_TB_WFC GF_FILE_TABLE "." GF_COL_WRITE_FREQ_CNTR +#define GF_COL_TB_RFC GF_FILE_TABLE "." GF_COL_READ_FREQ_CNTR + + +/******************************************************************************* +* SQLITE3 Connection details and PRAGMA +* ****************************************************************************/ + +#define GF_SQL_AV_NONE "none" +#define GF_SQL_AV_FULL "full" +#define GF_SQL_AV_INCR "incr" + + +#define GF_SQL_SYNC_OFF "off" +#define GF_SQL_SYNC_NORMAL "normal" +#define GF_SQL_SYNC_FULL "full" + +#define GF_SQL_JM_DELETE "delete" +#define GF_SQL_JM_TRUNCATE "truncate" +#define GF_SQL_JM_PERSIST "persist" +#define GF_SQL_JM_MEMORY "memory" +#define GF_SQL_JM_WAL "wal" +#define GF_SQL_JM_OFF "off" + + +typedef enum gf_sql_auto_vacuum { + gf_sql_av_none = 0, + gf_sql_av_full, + gf_sql_av_incr, + gf_sql_av_invalid +} gf_sql_auto_vacuum_t; + +typedef enum gf_sql_sync { + gf_sql_sync_off = 0, + gf_sql_sync_normal, + gf_sql_sync_full, + gf_sql_sync_invalid +} gf_sql_sync_t; + + +typedef enum gf_sql_journal_mode { + gf_sql_jm_wal = 0, + gf_sql_jm_delete, + gf_sql_jm_truncate, + gf_sql_jm_persist, + gf_sql_jm_memory, + gf_sql_jm_off, + gf_sql_jm_invalid +} gf_sql_journal_mode_t; + + +typedef struct gf_sql_connection { + char sqlite3_db_path[PATH_MAX]; + sqlite3 *sqlite3_db_conn; + ssize_t cache_size; + ssize_t page_size; + ssize_t wal_autocheckpoint; + gf_sql_journal_mode_t journal_mode; + gf_sql_sync_t synchronous; + gf_sql_auto_vacuum_t auto_vacuum; +} gf_sql_connection_t; + + + +#define CHECK_SQL_CONN(sql_conn, out)\ +do {\ + GF_VALIDATE_OR_GOTO(GFDB_STR_SQLITE3, sql_conn, out);\ + if (!sql_conn->sqlite3_db_conn) {\ + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR,\ + "sqlite3 connection not initialized");\ + goto out;\ + };\ +} while (0) + + +#define GF_SQLITE3_SET_PRAGMA(sqlite3_config_str, param_key, format, value,\ + ret, error)\ +do {\ + sprintf(sqlite3_config_str, "PRAGMA " param_key " = " format , value);\ + ret = sqlite3_exec (sql_conn->sqlite3_db_conn, sqlite3_config_str,\ + NULL, NULL, NULL);\ + if (ret != SQLITE_OK) {\ + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR,\ + "Failed executing: %s : %s",\ + sqlite3_config_str, sqlite3_errmsg\ + (sql_conn->sqlite3_db_conn));\ + ret = -1;\ + goto error;\ + };\ +} while (0) + +/************************SQLITE3 PARAMS KEYS***********************************/ +#define GFDB_SQL_PARAM_DBPATH "sql-db-path" +#define GFDB_SQL_PARAM_CACHE_SIZE "sql-db-cachesize" +#define GFDB_SQL_PARAM_PAGE_SIZE "sql-db-pagesize" +#define GFDB_SQL_PARAM_JOURNAL_MODE "sql-db-journalmode" +#define GFDB_SQL_PARAM_WAL_AUTOCHECK "sql-db-wal-autocheckpoint" +#define GFDB_SQL_PARAM_SYNC "sql-db-sync" +#define GFDB_SQL_PARAM_AUTO_VACUUM "sql-db-autovacuum" + +#define GF_SQL_DEFAULT_DBPATH "" +#define GF_SQL_DEFAULT_PAGE_SIZE "4096" +#define GF_SQL_DEFAULT_CACHE_SIZE "1000" +#define GF_SQL_DEFAULT_WAL_AUTOCHECKPOINT "1000" +#define GF_SQL_DEFAULT_JOURNAL_MODE GF_SQL_JM_WAL +#define GF_SQL_DEFAULT_SYNC GF_SQL_SYNC_NORMAL +#define GF_SQL_DEFAULT_AUTO_VACUUM GF_SQL_AV_NONE + + +/* Defines the indexs for sqlite params + * The order should be maintained*/ +typedef enum sqlite_param_index { + sql_dbpath_ix = 0, + sql_pagesize_ix, + sql_cachesize_ix, + sql_journalmode_ix, + sql_walautocheck_ix, + sql_dbsync_ix, + sql_autovacuum_ix, + /*This should be in the end*/ + sql_index_max +} sqlite_param_index_t; + +/* Array to hold the sqlite param keys + * The order should be maintained as sqlite_param_index_t*/ +static char *sqlite_params_keys[] = { + GFDB_SQL_PARAM_DBPATH, + GFDB_SQL_PARAM_PAGE_SIZE, + GFDB_SQL_PARAM_CACHE_SIZE, + GFDB_SQL_PARAM_JOURNAL_MODE, + GFDB_SQL_PARAM_WAL_AUTOCHECK, + GFDB_SQL_PARAM_SYNC, + GFDB_SQL_PARAM_AUTO_VACUUM +}; + + +/* Array of default values for sqlite params + * The order should be maintained as sqlite_param_index_t*/ +static char *sqlite_params_default_value[] = { + GF_SQL_DEFAULT_DBPATH, + GF_SQL_DEFAULT_PAGE_SIZE, + GF_SQL_DEFAULT_CACHE_SIZE, + GF_SQL_DEFAULT_JOURNAL_MODE, + GF_SQL_DEFAULT_WAL_AUTOCHECKPOINT, + GF_SQL_DEFAULT_SYNC, + GF_SQL_DEFAULT_AUTO_VACUUM +}; + +/*Extract sql params from page_size to auto_vacumm + * The dbpath is extracted in a different way*/ +static inline int +gfdb_set_sql_params(char *comp_name, dict_t *from_dict, dict_t *to_dict) +{ + sqlite_param_index_t sql_index = sql_pagesize_ix; + char *_val_str = NULL; + int ret = -1; + + GF_ASSERT (comp_name); + GF_ASSERT (from_dict); + GF_ASSERT (to_dict); + + /*Extact and Set of the sql params from page_size*/ + for (sql_index = sql_pagesize_ix; sql_index < sql_index_max; + sql_index++) { + _val_str = NULL; + GET_DB_PARAM_FROM_DICT_DEFAULT (comp_name, from_dict, + sqlite_params_keys[sql_index], _val_str, + sqlite_params_default_value[sql_index]); + SET_DB_PARAM_TO_DICT (comp_name, to_dict, + sqlite_params_keys[sql_index], _val_str, ret, out); + } +out: + return ret; +} + + + + +/*************************SQLITE3 GFDB PLUGINS*********************************/ + +/*Db init and fini modules*/ +int gf_sqlite3_fini (void **db_conn); +int gf_sqlite3_init (dict_t *args, void **db_conn); + +/*insert/update/delete modules*/ +int gf_sqlite3_insert (void *db_conn, gfdb_db_record_t *); +int gf_sqlite3_delete (void *db_conn, gfdb_db_record_t *); + +/*querying modules*/ +int gf_sqlite3_find_all (void *db_conn, gf_query_callback_t, + void *_query_cbk_args); +int gf_sqlite3_find_unchanged_for_time (void *db_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *for_time); +int gf_sqlite3_find_recently_changed_files (void *db_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *from_time); +int gf_sqlite3_find_unchanged_for_time_freq (void *db_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *for_time, + int write_freq_cnt, + int read_freq_cnt, + gf_boolean_t clear_counters); +int gf_sqlite3_find_recently_changed_files_freq (void *db_conn, + gf_query_callback_t query_callback, + void *_query_cbk_args, + gfdb_time_t *from_time, + int write_freq_cnt, + int read_freq_cnt, + gf_boolean_t clear_counters); + +void gf_sqlite3_fill_db_operations (gfdb_db_operations_t *gfdb_db_ops); + +#endif diff --git a/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c new file mode 100644 index 00000000000..50504181d26 --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c @@ -0,0 +1,1128 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "gfdb_sqlite3_helper.h" + +/***************************************************************************** + * + * Helper function to execute actual sql queries + * + * + * ****************************************************************************/ + +static inline int +gf_sql_delete_all (gf_sql_connection_t *sql_conn, + char *gfid) +{ + int ret = -1; + sqlite3_stmt *delete_file_stmt = NULL; + sqlite3_stmt *delete_link_stmt = NULL; + char *delete_link_str = "DELETE FROM " + GF_FILE_LINK_TABLE + " WHERE GF_ID = ? ;"; + char *delete_file_str = "DELETE FROM " + GF_FILE_TABLE + " WHERE GF_ID = ? ;"; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + + /* + * Delete all links associated with this GFID + * + * */ + /*Prepare statement for delete all links*/ + ret = sqlite3_prepare(sql_conn->sqlite3_db_conn, delete_link_str, -1, + &delete_link_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing delete statment %s : %s", + delete_link_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (delete_link_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + /*Execute the prepare statement*/ + if (sqlite3_step (delete_link_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + delete_link_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + /* + * Delete entry from file table associated with this GFID + * + * */ + /*Prepare statement for delete all links*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, delete_file_str, -1, + &delete_file_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing delete statment %s : %s", + delete_file_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (delete_file_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step (delete_file_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + delete_file_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + +out: + /*Free prepared statement*/ + sqlite3_finalize (delete_file_stmt); + sqlite3_finalize (delete_link_stmt); + return ret; +} + +static inline int +gf_sql_delete_link (gf_sql_connection_t *sql_conn, + char *gfid, + char *pargfid, + char *basename) +{ + int ret = -1; + sqlite3_stmt *delete_stmt = NULL; + char *delete_str = "DELETE FROM " + GF_FILE_LINK_TABLE + " WHERE GF_ID = ? AND GF_PID = ?" + " AND FNAME = ?;"; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, pargfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basename, out); + + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, delete_str, -1, + &delete_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing delete statment %s : %s", delete_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (delete_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind pargfid*/ + ret = sqlite3_bind_text (delete_stmt, 2, pargfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent gfid %s : %s", pargfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind basename*/ + ret = sqlite3_bind_text (delete_stmt, 3, basename, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basename %s : %s", basename, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step(delete_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + delete_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (delete_stmt); + return ret; +} + + + +static inline int +gf_sql_update_link_flags (gf_sql_connection_t *sql_conn, + char *gfid, + char *pargfid, + char *basename, + int update_flag, + gf_boolean_t is_update_or_delete) +{ + int ret = -1; + sqlite3_stmt *update_stmt = NULL; + char *update_column = NULL; + char update_str[1024] = ""; + + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, pargfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basename, out); + + update_column = (is_update_or_delete) ? "LINK_UPDATE" : "W_DEL_FLAG"; + + sprintf (update_str, "UPDATE " + GF_FILE_LINK_TABLE + " SET %s = ?" + " WHERE GF_ID = ? AND GF_PID = ? AND FNAME = ?;", + update_column); + + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, update_str, -1, + &update_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing update statment %s : %s", update_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + /*Bind link_update*/ + ret = sqlite3_bind_int (update_stmt, 1, update_flag); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding update_flag %d : %s", update_flag, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (update_stmt, 2, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind pargfid*/ + ret = sqlite3_bind_text (update_stmt, 3, pargfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent gfid %s : %s", pargfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind basename*/ + ret = sqlite3_bind_text (update_stmt, 4, basename, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basename %s : %s", basename, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + /*Execute the prepare statement*/ + if (sqlite3_step(update_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + update_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (update_stmt); + return ret; +} + + +static inline int +gf_sql_insert_link (gf_sql_connection_t *sql_conn, + char *gfid, + char *pargfid, + char *basename, + char *basepath) +{ + int ret = -1; + sqlite3_stmt *insert_stmt = NULL; + char *insert_str = "INSERT INTO " + GF_FILE_LINK_TABLE + " (GF_ID, GF_PID, FNAME, FPATH," + " W_DEL_FLAG, LINK_UPDATE) " + " VALUES (?, ?, ?, ?, 0, 1);"; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, pargfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basename, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basepath, out); + + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, insert_str, -1, + &insert_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing insert statment %s : %s", insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (insert_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind pargfid*/ + ret = sqlite3_bind_text (insert_stmt, 2, pargfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent gfid %s : %s", pargfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind basename*/ + ret = sqlite3_bind_text (insert_stmt, 3, basename, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basename %s : %s", basename, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind basepath*/ + ret = sqlite3_bind_text (insert_stmt, 4, basepath, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basepath %s : %s", basepath, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step (insert_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (insert_stmt); + return ret; +} + + +static inline int +gf_sql_update_link (gf_sql_connection_t *sql_conn, + char *gfid, + char *pargfid, + char *basename, + char *basepath, + char *old_pargfid, + char *old_basename) +{ + int ret = -1; + sqlite3_stmt *insert_stmt = NULL; + char *insert_str = "INSERT INTO " + GF_FILE_LINK_TABLE + " (GF_ID, GF_PID, FNAME, FPATH," + " W_DEL_FLAG, LINK_UPDATE) " + " VALUES (? , ?, ?, ?, 0, 1);"; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, pargfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basename, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, basepath, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, old_pargfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, old_basename, out); + + /* + * + * Delete the old link + * + * */ + ret = gf_sql_delete_link (sql_conn, gfid, old_pargfid, + old_basename); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed deleting old link"); + goto out; + } + + /* + * + * insert new link + * + * */ + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, insert_str, -1, + &insert_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing insert statment %s : %s", insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (insert_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind new pargfid*/ + ret = sqlite3_bind_text (insert_stmt, 2, pargfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent gfid %s : %s", pargfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind new basename*/ + ret = sqlite3_bind_text (insert_stmt, 3, basename, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basename %s : %s", basename, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind new basepath*/ + ret = sqlite3_bind_text (insert_stmt, 4, basepath, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding basename %s : %s", basepath, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step (insert_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (insert_stmt); + return ret; +} + +static inline int +gf_sql_insert_write_wind_time (gf_sql_connection_t *sql_conn, + char *gfid, + gfdb_time_t *wind_time) +{ + int ret = -1; + sqlite3_stmt *insert_stmt = NULL; + char *insert_str = "INSERT INTO " + GF_FILE_TABLE + "(GF_ID, W_SEC, W_MSEC, UW_SEC, UW_MSEC)" + " VALUES (?, ?, ?, 0, 0);"; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, wind_time, out); + + + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, insert_str, -1, + &insert_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing insert statment %s : %s", insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (insert_stmt, 1, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind wind secs*/ + ret = sqlite3_bind_int (insert_stmt, 2, wind_time->tv_sec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent wind secs %ld : %s", + wind_time->tv_sec, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind wind msecs*/ + ret = sqlite3_bind_int (insert_stmt, 3, wind_time->tv_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent wind msecs %ld : %s", + wind_time->tv_usec, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step (insert_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + insert_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (insert_stmt); + return ret; +} + + + +/*Update write/read times for both wind and unwind*/ +static inline int +gf_update_time (gf_sql_connection_t *sql_conn, + char *gfid, + gfdb_time_t *update_time, + gf_boolean_t record_counter, + gf_boolean_t is_wind, + gf_boolean_t is_read) +{ + int ret = -1; + sqlite3_stmt *update_stmt = NULL; + char update_str[1024] = ""; + char *freq_cntr_str = NULL; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfid, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, update_time, out); + + /* + * Constructing the prepare statment string. + * + * */ + /*For write time*/ + if (!is_read) { + if (is_wind) { + /*if record counter is on*/ + freq_cntr_str = (record_counter) ? + ", WRITE_FREQ_CNTR = WRITE_FREQ_CNTR + 1" : ""; + + /*Prefectly safe as we will not go array of bound*/ + sprintf (update_str, "UPDATE " + GF_FILE_TABLE + " SET W_SEC = ?, W_MSEC = ? " + " %s"/*place for read freq counters*/ + " WHERE GF_ID = ? ;", freq_cntr_str); + } else { + /*Prefectly safe as we will not go array of bound*/ + sprintf (update_str, "UPDATE " + GF_FILE_TABLE + " SET UW_SEC = ?, UW_MSEC = ? ;"); + } + } + /*For Read Time update*/ + else { + if (is_wind) { + /*if record counter is on*/ + freq_cntr_str = (record_counter) ? + ", READ_FREQ_CNTR = READ_FREQ_CNTR + 1" : ""; + + /*Prefectly safe as we will not go array of bound*/ + sprintf (update_str, "UPDATE " + GF_FILE_TABLE + " SET W_READ_SEC = ?, W_READ_MSEC = ? " + " %s"/*place for read freq counters*/ + " WHERE GF_ID = ? ;", freq_cntr_str); + } else { + /*Prefectly safe as we will not go array of bound*/ + sprintf (update_str, "UPDATE " + GF_FILE_TABLE + " SET UW_READ_SEC = ?, UW_READ_MSEC = ? ;"); + } + } + + /*Prepare statement*/ + ret = sqlite3_prepare (sql_conn->sqlite3_db_conn, update_str, -1, + &update_stmt, 0); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed preparing insert statment %s : %s", update_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind time secs*/ + ret = sqlite3_bind_int (update_stmt, 1, update_time->tv_sec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent wind secs %ld : %s", + update_time->tv_sec, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind time msecs*/ + ret = sqlite3_bind_int (update_stmt, 2, update_time->tv_usec); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding parent wind msecs %ld : %s", + update_time->tv_usec, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Bind gfid*/ + ret = sqlite3_bind_text (update_stmt, 3, gfid, -1, NULL); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed binding gfid %s : %s", gfid, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + /*Execute the prepare statement*/ + if (sqlite3_step (update_stmt) != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing the prepared stmt %s : %s", + update_str, + sqlite3_errmsg (sql_conn->sqlite3_db_conn)); + ret = -1; + goto out; + } + + ret = 0; +out: + /*Free prepared statement*/ + sqlite3_finalize (update_stmt); + return ret; +} + +/****************************************************************************** + * + * Helper functions for gf_sqlite3_insert() + * + * + * ****************************************************************************/ + +int +gf_sql_insert_wind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record) +{ + int ret = -1; + gfdb_time_t *modtime = NULL; + char *pargfid_str = NULL; + char *gfid_str = NULL; + char *old_pargfid_str = NULL; + gf_boolean_t its_wind = _gf_true;/*remains true for this function*/ + + + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfdb_db_record, out); + + + gfid_str = gf_strdup (uuid_utoa (gfdb_db_record->gfid)); + if (!gfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + + modtime = &gfdb_db_record->gfdb_wind_change_time; + + /* handle all dentry based operations */ + if (isdentryfop (gfdb_db_record->gfdb_fop_type)) { + /*Parent GFID is always set*/ + pargfid_str = gf_strdup (uuid_utoa (gfdb_db_record->pargfid)); + if (!pargfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + + /* handle create, mknod */ + if (isdentrycreatefop (gfdb_db_record->gfdb_fop_type)) { + /*insert link*/ + ret = gf_sql_insert_link(sql_conn, + gfid_str, pargfid_str, + gfdb_db_record->file_name, + gfdb_db_record->file_path); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed inserting link in DB"); + goto out; + } + gfdb_db_record->islinkupdate = _gf_true; + + /* + * Only for create/mknod insert wind time + * for the first time + * */ + ret = gf_sql_insert_write_wind_time (sql_conn, gfid_str, + modtime); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed inserting wind time in DB"); + goto out; + } + goto out; + } + /*handle rename, link */ + else { + /*rename*/ + if (strlen (gfdb_db_record->old_file_name) != 0) { + old_pargfid_str = gf_strdup (uuid_utoa ( + gfdb_db_record->old_pargfid)); + if (!old_pargfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + gf_sql_update_link (sql_conn, gfid_str, + pargfid_str, + gfdb_db_record->file_name, + gfdb_db_record->file_path, + old_pargfid_str, + gfdb_db_record->old_file_name); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed updating link"); + goto out; + } + gfdb_db_record->islinkupdate = _gf_true; + } + /*link*/ + else { + ret = gf_sql_insert_link (sql_conn, + gfid_str, pargfid_str, + gfdb_db_record->file_name, + gfdb_db_record->file_path); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed inserting link in DB"); + goto out; + } + gfdb_db_record->islinkupdate = _gf_true; + } + } + } + + /*All fops update times read or write*/ + ret = gf_update_time (sql_conn, gfid_str, modtime, + gfdb_db_record->do_record_counters, + its_wind, + isreadfop (gfdb_db_record->gfdb_fop_type)); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed update wind time in DB"); + goto out; + } + + ret = 0; +out: + GF_FREE (gfid_str); + GF_FREE (pargfid_str); + GF_FREE (old_pargfid_str); + return ret; +} + + + + +int +gf_sql_insert_unwind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record) +{ + + int ret = -1; + gfdb_time_t *modtime = NULL; + gf_boolean_t its_wind = _gf_true;/*remains true for this function*/ + char *gfid_str = NULL; + char *pargfid_str = NULL; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfdb_db_record, out); + + gfid_str = gf_strdup (uuid_utoa(gfdb_db_record->gfid)); + if (!gfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + + /*Only update if recording unwind is set*/ + if (gfdb_db_record->do_record_uwind_time) { + modtime = &gfdb_db_record->gfdb_unwind_change_time; + ret = gf_update_time (sql_conn, gfid_str, modtime, + gfdb_db_record->do_record_counters, + (!its_wind), + isreadfop (gfdb_db_record->gfdb_fop_type)); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed update unwind time in DB"); + goto out; + } + } + + /*For link creation and changes we use link updated*/ + if (gfdb_db_record->islinkupdate && + isdentryfop(gfdb_db_record->gfdb_fop_type)) { + + pargfid_str = gf_strdup(uuid_utoa(gfdb_db_record->pargfid)); + if (!pargfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating pargfid_str string failed."); + goto out; + } + + ret = gf_sql_update_link_flags (sql_conn, gfid_str, pargfid_str, + gfdb_db_record->file_name, 0, _gf_true); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed updating link flags in unwind"); + goto out; + } + } + + ret = 0; +out: + GF_FREE (gfid_str); + GF_FREE (pargfid_str); + return ret; +} + + +int +gf_sql_update_delete_wind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record) +{ + int ret = -1; + gfdb_time_t *modtime = NULL; + char *gfid_str = NULL; + char *pargfid_str = NULL; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfdb_db_record, out); + + gfid_str = gf_strdup (uuid_utoa(gfdb_db_record->gfid)); + if (!gfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + + pargfid_str = gf_strdup (uuid_utoa(gfdb_db_record->pargfid)); + if (!pargfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating pargfid_str string failed."); + goto out; + } + + /*Update the wind write times*/ + modtime = &gfdb_db_record->gfdb_unwind_change_time; + ret = gf_update_time (sql_conn, gfid_str, modtime, + gfdb_db_record->do_record_counters, + _gf_true, + isreadfop (gfdb_db_record->gfdb_fop_type)); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed update wind time in DB"); + goto out; + } + + ret = gf_sql_update_link_flags (sql_conn, gfid_str, pargfid_str, + gfdb_db_record->file_name, 1, + _gf_false); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed updating link flags in wind"); + goto out; + } + + ret = 0; +out: + GF_FREE (gfid_str); + GF_FREE (pargfid_str); + return ret; +} + +int +gf_sql_delete_unwind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record) +{ + int ret = -1; + char *gfid_str = NULL; + char *pargfid_str = NULL; + gfdb_time_t *modtime = NULL; + + CHECK_SQL_CONN (sql_conn, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, gfdb_db_record, out); + + gfid_str = gf_strdup (uuid_utoa(gfdb_db_record->gfid)); + if (!gfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating gfid string failed."); + goto out; + } + + /*Nuke all the entries for this GFID from DB*/ + if (gfdb_db_record->gfdb_fop_path == GFDB_FOP_UNDEL_ALL) { + gf_sql_delete_all(sql_conn, gfid_str); + } + /*Remove link entries only*/ + else if (gfdb_db_record->gfdb_fop_path == GFDB_FOP_UNDEL) { + + pargfid_str = gf_strdup(uuid_utoa(gfdb_db_record->pargfid)); + if (!pargfid_str) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Creating pargfid_str string failed."); + goto out; + } + + modtime = &gfdb_db_record->gfdb_unwind_change_time; + + ret = gf_sql_delete_link(sql_conn, gfid_str, pargfid_str, + gfdb_db_record->file_name); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed deleting link"); + goto out; + } + + if (gfdb_db_record->do_record_uwind_time) { + ret = gf_update_time (sql_conn, gfid_str, modtime, + gfdb_db_record->do_record_counters, + _gf_false, + isreadfop(gfdb_db_record->gfdb_fop_type)); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed update unwind time in DB"); + goto out; + } + } + } + ret = 0; +out: + GF_FREE (gfid_str); + GF_FREE (pargfid_str); + return ret; +} + +/****************************************************************************** + * + * Find/Query helper functions + * + * ****************************************************************************/ +int +gf_sql_query_function (sqlite3_stmt *prep_stmt, + gf_query_callback_t query_callback, + void *_query_cbk_args) +{ + int ret = -1; + gfdb_query_record_t *gfdb_query_record = NULL; + char *text_column = NULL; + sqlite3 *db_conn = NULL; + + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, prep_stmt, out); + GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, query_callback, out); + + db_conn = sqlite3_db_handle(prep_stmt); + + gfdb_query_record = gfdb_query_record_init (); + if (!gfdb_query_record) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed to create gfdb_query_record"); + goto out; + } + + /*Loop to access queried rows*/ + while ((ret = sqlite3_step (prep_stmt)) == SQLITE_ROW) { + + /*Clear the query record*/ + memset (gfdb_query_record, 0, sizeof(*gfdb_query_record)); + + if (sqlite3_column_count(prep_stmt) > 0) { + + /*Retriving GFID - column index is 0*/ + text_column = (char *)sqlite3_column_text + (prep_stmt, 0); + if (!text_column) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed retriving GF_ID"); + goto out; + } + ret = uuid_parse (text_column, gfdb_query_record->gfid); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed parsing GF_ID"); + goto out; + } + + /*Retrive Link Buffer - column index 1*/ + text_column = (char *)sqlite3_column_text + (prep_stmt, 1); + /* Get link string. Do shallow copy here + * query_callback function should do a + * deep copy and then do operations on this field*/ + gfdb_query_record->_link_info_str = text_column; + gfdb_query_record->link_info_size = strlen + (text_column); + + /* Call the call back function provided*/ + ret = query_callback (gfdb_query_record, + _query_cbk_args); + if (ret) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Query Call back failed!"); + goto out; + } + + } + + } + + if (ret != SQLITE_DONE) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed retriving records from db : %s", + sqlite3_errmsg (db_conn)); + ret = -1; + goto out; + } + + ret = 0; +out: + gfdb_query_record_fini (&gfdb_query_record); + return ret; +} + + + +int +gf_sql_clear_counters (gf_sql_connection_t *sql_conn) +{ + int ret = -1; + char *sql_strerror = NULL; + char *query_str = NULL; + + CHECK_SQL_CONN (sql_conn, out); + + query_str = "BEGIN;UPDATE " + GF_FILE_TABLE + " SET " GF_COL_READ_FREQ_CNTR " = 0 , " + GF_COL_WRITE_FREQ_CNTR " = 0 ;COMMIT;"; + + ret = sqlite3_exec (sql_conn->sqlite3_db_conn, query_str, NULL, NULL, + &sql_strerror); + if (ret != SQLITE_OK) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Failed executing: %s : %s", + query_str, sql_strerror); + sqlite3_free (sql_strerror); + ret = -1; + goto out; + } + + ret = 0; +out: + return ret; +} diff --git a/libglusterfs/src/gfdb/gfdb_sqlite3_helper.h b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.h new file mode 100644 index 00000000000..8b62be1d4d0 --- /dev/null +++ b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.h @@ -0,0 +1,64 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef __GFDB_SQLITE3_HELPER_H +#define __GFDB_SQLITE3_HELPER_H + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "gfdb_sqlite3.h" + +/****************************************************************************** + * + * Helper functions for gf_sqlite3_insert() + * + * ****************************************************************************/ + + +int +gf_sql_insert_wind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record); + +int +gf_sql_insert_unwind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record); + + +int +gf_sql_update_delete_wind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record); + +int +gf_sql_delete_unwind (gf_sql_connection_t *sql_conn, + gfdb_db_record_t *gfdb_db_record); + + + + + +/****************************************************************************** + * + * Find/Query helper functions + * + * ****************************************************************************/ + + +int +gf_sql_query_function (sqlite3_stmt *prep_stmt, + gf_query_callback_t query_callback, + void *_query_cbk_args); + +int +gf_sql_clear_counters (gf_sql_connection_t *sql_conn); + +#endif diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h index 93aea8502e3..9ff78dd19a4 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -129,6 +129,18 @@ enum gf_common_mem_types_ { gf_common_mt_wr = 113, gf_common_mt_rdma_arena_mr = 114, gf_common_mt_parser_t = 115, + /*related to gfdb library*/ + gfdb_mt_time_t, + gf_mt_sql_cbk_args_t, + gf_mt_gfdb_query_record_t, + gf_mt_gfdb_link_info_t, + gf_mt_gfdb_db_operations_t, + gf_mt_sql_connection_t, + gf_mt_sql_conn_node_t, + gf_mt_db_conn_node_t, + gf_mt_db_connection_t, + gfdb_mt_db_record_t, + /*related to gfdb library*/ gf_common_mt_end }; #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index 467d8cb8518..385e9075ce7 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -1662,7 +1662,6 @@ struct volopt_map_entry glusterd_volopt_map[] = { .voltype = "mgmt/glusterd", .op_version = GD_OP_VERSION_3_6_0, }, - /*Trash translator options */ { .key = "features.trash", .voltype = "features/trash", -- cgit