bool kdb_bucket::start(int bucket_number) { bool ret = true; const char* data_dir = TBSYS_CONFIG.getString(TAIRKDB_SECTION, KDB_DATA_DIR, KDB_DEFAULT_DATA_DIR); if (data_dir == NULL) { log_error("kdb data dir not config, item: %s.%s", TAIRKDB_SECTION, KDB_DATA_DIR); ret = false; } if (ret) { snprintf(filename, PATH_MAX_LENGTH, "%s/tair_kdb_%06d.dat", data_dir, bucket_number); uint64_t map_size = TBSYS_CONFIG.getInt(TAIRKDB_SECTION, KDB_MAP_SIZE, KDB_MAP_SIZE_DEFAULT); uint64_t bucket_size = TBSYS_CONFIG.getInt(TAIRKDB_SECTION, KDB_BUCKET_SIZE, KDB_BUCKET_SIZE_DEFAULT); uint64_t record_align = TBSYS_CONFIG.getInt(TAIRKDB_SECTION, KDB_RECORD_ALIGN, KDB_RECORD_ALIGN_DEFAULT); ret = db.tune_map(map_size); if (!ret ) { print_db_error("set mmap size failed"); } if (ret) { ret = db.tune_alignment(record_align); if (!ret) { print_db_error("set record alignment failed"); } } if (ret) { ret = db.tune_options(kyotocabinet::HashDB::TLINEAR); if (!ret) { print_db_error("set option failed"); } } if (ret) { ret = db.tune_buckets(bucket_size); if (!ret) { print_db_error("set bucket size failed"); } } if (ret) { uint32_t mode = kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE |kyotocabinet::HashDB::ONOREPAIR; ret = db.open(filename, mode); if (!ret) { print_db_error("open kdb failed"); } } } if (ret) { stat_mgr.start(bucket_number, data_dir); log_info("kdb [%d] opened", bucket_number); } return ret; }
/** * Returns the file_id for the specified file. * @param database is the structure that contains everything that is * related to the database (it's connexion for instance). * @param meta is the file's metadata that we want to insert into the * cache. * @returns a file_row_t structure filed with values returned by the * database. */ static file_row_t *get_file_id(db_t *database, meta_data_t *meta) { file_row_t *row = NULL; char *error_message = NULL; gchar *sql_command = NULL; int db_result = 0; row = new_file_row_t(); sql_command = g_strdup_printf("SELECT file_id from files WHERE inode=%" G_GUINT64_FORMAT " AND name='%s' AND type=%d AND uid=%d AND gid=%d AND ctime=%" G_GUINT64_FORMAT " AND mtime=%" G_GUINT64_FORMAT " AND mode=%d AND size=%" G_GUINT64_FORMAT ";", meta->inode, meta->name, meta->file_type, meta->uid, meta->gid, meta->ctime, meta->mtime, meta->mode, meta->size); db_result = sqlite3_exec(database->db, sql_command, get_file_callback, row, &error_message); free_variable(sql_command); if (db_result == SQLITE_OK) { return row; } else { print_db_error(database->db, _("(%d) Error while searching into the table 'files': %s\n"), db_result, error_message); return NULL; /* to avoid a compilation warning as we exited with failure in print_db_error */ } }
/** * Returns a database connexion or NULL. * @param database_name is the filename of the file that contains the * database * @result returns a db_t * filled with the database connexion or NULL * in case of an error. */ db_t *open_database(gchar *database_name) { db_t *database = NULL; sqlite3 *db = NULL; int result = 0; database = (db_t *) g_malloc0(sizeof(db_t)); result = sqlite3_open(database_name, &db); if (result != SQLITE_OK) { print_db_error(db, _("(%d) Error while trying to open %s database: %s\n"), result, database_name, sqlite3_errmsg(db)); free_variable(database); sqlite3_close(db); return NULL; } else { database->db = db; sqlite3_extended_result_codes(db, 1); verify_if_tables_exists(database); return database; } }
/** * Prints out an error message if an sqlite function just made one. * @param db is the concerned sqlite database * @param result is the result of the sqlite function * @param infos is a gchar * containing some context to help understanding * the error. * @note sqlite3_errstr needs at least sqlite 3.7.15 */ static void print_on_db_error(sqlite3 *db, int result, const gchar *infos) { const char *message = NULL; int errcode = 0; if (result == SQLITE_ERROR) { errcode = sqlite3_extended_errcode(db); message = sqlite3_errstr(errcode); print_db_error(db, _("sqlite error (%d - %d) on %s: %s\n"), result, errcode, infos, message); } }
/** * Prints out an error message if an sqlite function just made one. * @param db is the concerned sqlite database * @param result is the result of the sqlite function * @param infos is a gchar * containing some context to help understanding * the error. * @note sqlite3_errstr needs at least sqlite 3.7.15 */ static void print_on_db_error(sqlite3 *db, int result, const gchar *infos) { const char *message = NULL; int errcode = 0; if (result == SQLITE_ERROR && db != NULL) { /** @note sqlite3_errstr needs at least sqlite 3.7.15 */ errcode = sqlite3_extended_errcode(db); message = sqlite3_errstr(errcode); print_db_error(_("sqlite error (%d - %d) on %s: %s\n"), result, errcode, infos, message); } }
int kdb_bucket::remove(common::data_entry& key, bool version_care) { int rc = TAIR_RETURN_SUCCESS; int stat_data_size = 0; int li = util::string_util::mur_mur_hash(key.get_data(), key.get_size()) % LOCKER_SIZE; if(!locks->lock(li, true)) { log_error("acquire lock failed"); return TAIR_RETURN_FAILED; } if (rc == TAIR_RETURN_SUCCESS) { size_t val_size = 0; char* old_value = db.get(key.get_data(), key.get_size(), &val_size); if (old_value == NULL) { rc = TAIR_RETURN_DATA_NOT_EXIST; } else { kdb_item item; item.full_value = old_value; item.full_value_size = val_size; stat_data_size = val_size + key.get_size(); item.decode(); if (version_care && key.data_meta.version != 0 && key.data_meta.version != item.meta.version) { rc = TAIR_RETURN_VERSION_ERROR; } delete [] old_value; } } if (rc == TAIR_RETURN_SUCCESS) { int dc = db.remove(key.get_data(), key.get_size()); if (dc < 0) { print_db_error("remove item failed"); rc = TAIR_RETURN_FAILED; } if (rc == TAIR_RETURN_SUCCESS) { stat_mgr.stat_sub(key.area, stat_data_size, stat_data_size); } } locks->unlock(li); return rc; }
/** * Executes the SQL command onto the database without any callback * @param database : the db_t * structure that contains the database connexion * @param sql_cmd : a gchar * SQL command to be executed onto the database * @param format_message : a gchar * format message to be used in case of an error */ static void exec_sql_cmd(db_t *database, gchar *sql_cmd, gchar *format_message) { char *error_message = NULL; const char *message = NULL; int result = 0; result = sqlite3_exec(database->db, sql_cmd, NULL, 0, &error_message); if (result != SQLITE_OK) { result = sqlite3_extended_errcode(database->db); /* sqlite3_errstr needs at least sqlite 3.7.15 */ message = sqlite3_errstr(result); print_db_error(database->db, format_message, result, message); } }
bool kdb_bucket::begin_scan() { if (cursor != NULL) { delete cursor; } cursor = db.cursor(); // open the cursor bool ret = cursor->jump(); // jump to the first record if (ret == false) { const kyotocabinet::BasicDB::Error& err = db.error(); if (err == kyotocabinet::BasicDB::Error::NOREC) { ret = true; } else { print_db_error("begin scan error"); } } return ret; }
/** * Returns a database connexion or NULL. * @param dirname is the name of the directory where the database is * located. * @param filename is the filename of the file that contains the * database * @result returns a db_t * filled with the database connexion or NULL * in case of an error. */ db_t *open_database(gchar *dirname, gchar *filename) { gchar *database_name = NULL; db_t *database = NULL; sqlite3 *db = NULL; int result = 0; if (dirname != NULL && filename != NULL) { create_directory(dirname); database_name = g_build_filename(dirname, filename, NULL); result = sqlite3_open(database_name, &db); if (result != SQLITE_OK) { print_db_error(_("(%d) Error while trying to open %s database: %s\n"), result, database_name, sqlite3_errmsg(db)); sqlite3_close(db); free_variable(database_name); return NULL; } else { database = (db_t *) g_malloc0(sizeof(db_t)); g_assert_nonnull(database); database->version_filename = g_strdup_printf("%s.version", database_name); database->db = db; sqlite3_extended_result_codes(db, 1); verify_if_tables_exists(database); database->stmts = new_stmts(db); database->version = get_database_version(database->version_filename, KN_CLIENT_DATABASE); migrate_schema_if_needed(database); free_variable(database_name); return database; } } else { return NULL; } }
/** * Executes the SQL command onto the database without any callback * @param database : the db_t * structure that contains the database connexion * @param sql_cmd : a gchar * SQL command to be executed onto the database * @param format_message : a gchar * format message to be used in case of an error */ static int exec_sql_cmd(db_t *database, gchar *sql_cmd, gchar *format_message) { char *error_message = NULL; const char *message = NULL; int result = 0; int errcode = 0; if (database != NULL && database->db != NULL) { result = sqlite3_exec(database->db, sql_cmd, NULL, 0, &error_message); if (result != SQLITE_OK) { /** @note sqlite3_errstr needs at least sqlite 3.7.15 */ errcode = sqlite3_extended_errcode(database->db); message = sqlite3_errstr(result); print_db_error(format_message, result, errcode, message); } } return result; }
/** * Migrates or does changes on sql schema where needed * @param database is the structure that contains everything that is * related to the database (it's connexion for instance). */ static void migrate_schema_if_needed(db_t *database) { if (database != NULL && database->version == 1) { /* First version is OK and there is nothing to do with that */ } else if (database != NULL && database->version >= 1 && database->version < DATABASE_SCHEMA_VERSION) { fprintf(stdout, _("Warning database version is not correct: %ld but expected: %d\n"), database->version, DATABASE_SCHEMA_VERSION); fprintf(stdout, _("Now trying to migrate from %ld to %d\n"), database->version, DATABASE_SCHEMA_VERSION); /* Here should go the code to migrate from on version to another one * in an incremental way. */ exit(EXIT_FAILURE); } else if (database != NULL) { print_db_error(_("Error database version is not correct: %ld but expected between 2 and %d\n"), database->version, DATABASE_SCHEMA_VERSION); exit(EXIT_FAILURE); } }
void kdb_bucket::stop() { if (!db.close()) { print_db_error("close kdb failed"); } }
int kdb_bucket::put(common::data_entry& key, common::data_entry& value, bool version_care, uint32_t expire_time) { kdb_item item; int cdate = 0; int mdate = 0; int edate = 0; int stat_data_size = 0; if(key.data_meta.cdate == 0 || version_care) { cdate = time(NULL); mdate = cdate; if(expire_time > 0) edate = expire_time > static_cast<uint32_t>(mdate) ? expire_time : mdate + expire_time; } else { cdate = key.data_meta.cdate; mdate = key.data_meta.mdate; edate = key.data_meta.edate; } int rc = TAIR_RETURN_SUCCESS; int li = util::string_util::mur_mur_hash(key.get_data(), key.get_size()) % LOCKER_SIZE; if(!locks->lock(li, true)) { log_error("acquire lock failed"); return TAIR_RETURN_FAILED; } size_t val_size = 0; char* old_value = db.get(key.get_data(), key.get_size(), &val_size); if (old_value != NULL) { // key already exist item.full_value = old_value; item.full_value_size = val_size; item.decode(); cdate = item.meta.cdate; // set back the create time if (item.is_expired()) { item.meta.version = 0; } else if (version_care) { // item is not expired & care version, check version if (key.data_meta.version != 0 && key.data_meta.version != item.meta.version) { rc = TAIR_RETURN_VERSION_ERROR; } } item.full_value = NULL; item.full_value_size = 0; if (rc == TAIR_RETURN_SUCCESS) { stat_data_size -= val_size + key.get_size(); } } if (old_value != NULL) { // free the memory ASAP delete [] old_value; } if (rc == TAIR_RETURN_SUCCESS) { item.meta.flag = value.data_meta.flag; item.meta.cdate = cdate; item.meta.mdate = mdate; item.meta.edate = edate; if (version_care) { item.meta.version++; } else { item.meta.version = key.data_meta.version; } item.value = value.get_data(); item.value_size = value.get_size(); item.encode(); stat_data_size += item.full_value_size + key.get_size(); int dc = db.set(key.get_data(), key.get_size(), item.full_value, item.full_value_size); item.free_full_value(); // free encoded value //update key's meta info key.data_meta.flag = item.meta.flag; key.data_meta.cdate = item.meta.cdate; key.data_meta.edate = item.meta.edate; key.data_meta.mdate = item.meta.mdate; key.data_meta.version = item.meta.version; key.data_meta.keysize = key.get_size(); key.data_meta.valsize = item.value_size; if (dc < 0) { print_db_error("update item failed"); rc = TAIR_RETURN_FAILED; } if (rc == TAIR_RETURN_SUCCESS) { stat_mgr.stat_add(key.area, stat_data_size, stat_data_size); } } locks->unlock(li); return rc; }