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 <josferna@redhat.com>
Signed-off-by: Dan Lambright <dlambrig@redhat.com>
Signed-off-by: Joseph Fernandes <josferna@redhat.com>
Reviewed-on: http://review.gluster.org/9683
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Joseph Fernandes 2015-02-18 19:45:23 +05:30 committed by Vijay Bellur
parent dbd62a8d2b
commit 87c7fa3cfd
16 changed files with 4305 additions and 11 deletions

View File

@ -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 =

View File

@ -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

View File

@ -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/*

11
libgfdb.pc.in Normal file
View File

@ -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

View File

@ -1,3 +1,3 @@
SUBDIRS = src
SUBDIRS = src src/gfdb
CLEANFILES =

View File

@ -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

View File

@ -0,0 +1,649 @@
/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
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;
}

View File

@ -0,0 +1,219 @@
/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
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 <time.h>
#include <sys/time.h>
#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

View File

@ -0,0 +1,733 @@
/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
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 <time.h>
#include <sys/time.h>
#include <string.h>
#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

View File

@ -0,0 +1,22 @@
/*
Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com>
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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,288 @@
/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
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 <sqlite3.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
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

View File

@ -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

View File

@ -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",