diff options
author | Joseph Fernandes <josferna@redhat.com> | 2015-02-18 19:45:23 +0530 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2015-03-18 10:36:42 -0700 |
commit | 87c7fa3cfdadca4ee883daf84373302a42ad5fdc (patch) | |
tree | e61b744ea3c2058a95a5057bb8c2fe7763eb101f /libglusterfs/src/gfdb/gfdb_sqlite3.c | |
parent | dbd62a8d2b50392fbed0a0781a4f241dadb8f506 (diff) |
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>
Diffstat (limited to 'libglusterfs/src/gfdb/gfdb_sqlite3.c')
-rw-r--r-- | libglusterfs/src/gfdb/gfdb_sqlite3.c | 1101 |
1 files changed, 1101 insertions, 0 deletions
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. <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_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, "<gfid", 5) == 0)) { + gf_log (GFDB_STR_SQLITE3, GF_LOG_ERROR, + "Skip path <gfid fop=%d", + gfdb_db_record->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; +} |