/* Copyright (c) 2015 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #ifndef __GFDB_DATA_STORE_TYPE_H #define __GFDB_DATA_STORE_TYPE_H #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif #include #include #include #include "common-utils.h" #include "compat-uuid.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; /* Global flag to record or not record counters */ gf_boolean_t do_record_counters; /* Global flag to Record/Not Record wind or wind time. * This flag will overrule do_record_uwind_time*/ gf_boolean_t do_record_times; } 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 = gf_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