diff --git a/db/c.cc b/db/c.cc index 76a949cd1..f3d0fed12 100644 --- a/db/c.cc +++ b/db/c.cc @@ -29,6 +29,7 @@ #include "rocksdb/statistics.h" #include "rocksdb/slice_transform.h" #include "rocksdb/table.h" +#include "rocksdb/utilities/backupable_db.h" using rocksdb::Cache; using rocksdb::ColumnFamilyDescriptor; @@ -69,12 +70,19 @@ using rocksdb::WritableFile; using rocksdb::WriteBatch; using rocksdb::WriteOptions; using rocksdb::LiveFileMetaData; +using rocksdb::BackupEngine; +using rocksdb::BackupableDBOptions; +using rocksdb::BackupInfo; +using rocksdb::RestoreOptions; using std::shared_ptr; extern "C" { struct rocksdb_t { DB* rep; }; +struct rocksdb_backup_engine_t { BackupEngine* rep; }; +struct rocksdb_backup_engine_info_t { std::vector rep; }; +struct rocksdb_restore_options_t { RestoreOptions rep; }; struct rocksdb_iterator_t { Iterator* rep; }; struct rocksdb_writebatch_t { WriteBatch rep; }; struct rocksdb_snapshot_t { const Snapshot* rep; }; @@ -527,6 +535,96 @@ rocksdb_t* rocksdb_open_for_read_only( return result; } +rocksdb_backup_engine_t* rocksdb_backup_engine_open( + const rocksdb_options_t* options, + const char* path, + char** errptr) { + BackupEngine* be; + if (SaveError(errptr, BackupEngine::Open(options->rep.env, BackupableDBOptions(path), &be))) { + return nullptr; + } + rocksdb_backup_engine_t* result = new rocksdb_backup_engine_t; + result->rep = be; + return result; +} + +void rocksdb_backup_engine_create_new_backup( + rocksdb_backup_engine_t *be, + rocksdb_t *db, + char** errptr) { + SaveError(errptr, be->rep->CreateNewBackup(db->rep)); +} + +rocksdb_restore_options_t* rocksdb_restore_options_create() { + return new rocksdb_restore_options_t; +} + +void rocksdb_restore_options_destroy(rocksdb_restore_options_t* opt) { + delete opt; +} + +void rocksdb_restore_options_set_keep_log_files( + rocksdb_restore_options_t* opt, int v) { + opt->rep.keep_log_files = v; +} + +void rocksdb_backup_engine_restore_db_from_latest_backup( + rocksdb_backup_engine_t *be, + const char* db_dir, + const char* wal_dir, + const rocksdb_restore_options_t *restore_options, + char** errptr) { + SaveError(errptr, be->rep->RestoreDBFromLatestBackup(std::string(db_dir), std::string(wal_dir), restore_options->rep)); +} + +const rocksdb_backup_engine_info_t* rocksdb_backup_engine_get_backup_info( + rocksdb_backup_engine_t* be) { + rocksdb_backup_engine_info_t* result = new rocksdb_backup_engine_info_t; + be->rep->GetBackupInfo(&result->rep); + return result; +} + +int rocksdb_backup_engine_info_count( + const rocksdb_backup_engine_info_t* info) { + return static_cast(info->rep.size()); +} + +const int64_t rocksdb_backup_engine_info_timestamp( + const rocksdb_backup_engine_info_t* info, + int index) { + return info->rep[index].timestamp; +} + +const uint32_t rocksdb_backup_engine_info_backup_id( + const rocksdb_backup_engine_info_t* info, + int index) { + return info->rep[index].backup_id; +} + +const uint64_t rocksdb_backup_engine_info_size( + const rocksdb_backup_engine_info_t* info, + int index) { + return info->rep[index].size; +} + +const uint32_t rocksdb_backup_engine_info_number_files( + const rocksdb_backup_engine_info_t* info, + int index) { + return info->rep[index].number_files; +} + +void rocksdb_backup_engine_info_destroy( + const rocksdb_backup_engine_info_t* info) { + delete info; +} + +void rocksdb_backup_engine_close( + rocksdb_backup_engine_t *be) { + delete be->rep; + delete be; +} + + void rocksdb_close(rocksdb_t* db) { delete db->rep; delete db; diff --git a/db/c_test.c b/db/c_test.c index ba239a43d..b8f0ea186 100644 --- a/db/c_test.c +++ b/db/c_test.c @@ -10,9 +10,11 @@ #include #include #include +#include const char* phase = ""; static char dbname[200]; +static char dbbackupname[200]; static void StartPhase(const char* name) { fprintf(stderr, "=== Test %s\n", name); @@ -346,6 +348,11 @@ int main(int argc, char** argv) { GetTempDir(), ((int) geteuid())); + snprintf(dbbackupname, sizeof(dbbackupname), + "%s/rocksdb_c_test-%d-backup", + GetTempDir(), + ((int) geteuid())); + StartPhase("create_objects"); cmp = rocksdb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); env = rocksdb_create_default_env(); @@ -396,6 +403,41 @@ int main(int argc, char** argv) { CheckNoError(err); CheckGet(db, roptions, "foo", "hello"); + StartPhase("backup_and_restore"); + { + rocksdb_destroy_db(options, dbbackupname, &err); + CheckNoError(err); + + rocksdb_backup_engine_t *be = rocksdb_backup_engine_open(options, dbbackupname, &err); + CheckNoError(err); + + rocksdb_backup_engine_create_new_backup(be, db, &err); + CheckNoError(err); + + rocksdb_delete(db, woptions, "foo", 3, &err); + CheckNoError(err); + + rocksdb_close(db); + + rocksdb_destroy_db(options, dbname, &err); + CheckNoError(err); + + rocksdb_restore_options_t *restore_options = rocksdb_restore_options_create(); + rocksdb_restore_options_set_keep_log_files(restore_options, 0); + rocksdb_backup_engine_restore_db_from_latest_backup(be, dbname, dbname, restore_options, &err); + CheckNoError(err); + rocksdb_restore_options_destroy(restore_options); + + rocksdb_options_set_error_if_exists(options, 0); + db = rocksdb_open(options, dbname, &err); + CheckNoError(err); + rocksdb_options_set_error_if_exists(options, 1); + + CheckGet(db, roptions, "foo", "hello"); + + rocksdb_backup_engine_close(be); + } + StartPhase("compactall"); rocksdb_compact_range(db, NULL, 0, NULL, 0); CheckGet(db, roptions, "foo", "hello"); diff --git a/examples/c_simple_example.c b/examples/c_simple_example.c index 1dd380721..c152b7da1 100644 --- a/examples/c_simple_example.c +++ b/examples/c_simple_example.c @@ -8,9 +8,11 @@ #include // sysconf() - get CPU count const char DBPath[] = "/tmp/rocksdb_simple_example"; +const char DBBackupPath[] = "/tmp/rocksdb_simple_example_backup"; int main(int argc, char **argv) { rocksdb_t *db; + rocksdb_backup_engine_t *be; rocksdb_options_t *options = rocksdb_options_create(); // Optimize RocksDB. This is the easiest way to // get RocksDB to perform well @@ -25,6 +27,10 @@ int main(int argc, char **argv) { db = rocksdb_open(options, DBPath, &err); assert(!err); + // open Backup Engine that we will use for backing up or database + be = rocksdb_backup_engine_open(options, DBBackupPath, &err); + assert(!err); + // Put key-value rocksdb_writeoptions_t *writeoptions = rocksdb_writeoptions_create(); const char key[] = "key"; @@ -41,10 +47,26 @@ int main(int argc, char **argv) { assert(strcmp(returned_value, "value") == 0); free(returned_value); + // create new backup in a directory specified by DBBackupPath + rocksdb_backup_engine_create_new_backup(be, db, &err); + assert(!err); + + rocksdb_close(db); + + // If something is wrong, you might want to restore data from last backup + rocksdb_restore_options_t *restore_options = rocksdb_restore_options_create(); + rocksdb_backup_engine_restore_db_from_latest_backup(be, DBPath, DBPath, restore_options, &err); + assert(!err); + rocksdb_restore_options_destroy(restore_options); + + db = rocksdb_open(options, DBPath, &err); + assert(!err); + // cleanup rocksdb_writeoptions_destroy(writeoptions); rocksdb_readoptions_destroy(readoptions); rocksdb_options_destroy(options); + rocksdb_backup_engine_close(be); rocksdb_close(db); return 0; diff --git a/include/rocksdb/c.h b/include/rocksdb/c.h index c686c90c7..ac5f612a0 100644 --- a/include/rocksdb/c.h +++ b/include/rocksdb/c.h @@ -55,6 +55,9 @@ extern "C" { /* Exported types */ typedef struct rocksdb_t rocksdb_t; +typedef struct rocksdb_backup_engine_t rocksdb_backup_engine_t; +typedef struct rocksdb_backup_engine_info_t rocksdb_backup_engine_info_t; +typedef struct rocksdb_restore_options_t rocksdb_restore_options_t; typedef struct rocksdb_cache_t rocksdb_cache_t; typedef struct rocksdb_compactionfilter_t rocksdb_compactionfilter_t; typedef struct rocksdb_compactionfiltercontext_t @@ -104,6 +107,56 @@ extern rocksdb_t* rocksdb_open_for_read_only( unsigned char error_if_log_file_exist, char** errptr); +extern rocksdb_backup_engine_t* rocksdb_backup_engine_open( + const rocksdb_options_t* options, + const char* path, + char** errptr); + +extern void rocksdb_backup_engine_create_new_backup( + rocksdb_backup_engine_t* be, + rocksdb_t* db, + char** errptr); + +extern rocksdb_restore_options_t* rocksdb_restore_options_create(); +extern void rocksdb_restore_options_destroy(rocksdb_restore_options_t* opt); +extern void rocksdb_restore_options_set_keep_log_files( + rocksdb_restore_options_t* opt, int v); + +extern void rocksdb_backup_engine_restore_db_from_latest_backup( + rocksdb_backup_engine_t *be, + const char* db_dir, + const char* wal_dir, + const rocksdb_restore_options_t *restore_options, + char** errptr); + +extern const rocksdb_backup_engine_info_t* rocksdb_backup_engine_get_backup_info( + rocksdb_backup_engine_t* be); + +extern int rocksdb_backup_engine_info_count( + const rocksdb_backup_engine_info_t* info); + +extern const int64_t rocksdb_backup_engine_info_timestamp( + const rocksdb_backup_engine_info_t* info, + int index); + +extern const uint32_t rocksdb_backup_engine_info_backup_id( + const rocksdb_backup_engine_info_t* info, + int index); + +extern const uint64_t rocksdb_backup_engine_info_size( + const rocksdb_backup_engine_info_t* info, + int index); + +extern const uint32_t rocksdb_backup_engine_info_number_files( + const rocksdb_backup_engine_info_t* info, + int index); + +extern void rocksdb_backup_engine_info_destroy( + const rocksdb_backup_engine_info_t *info); + +extern void rocksdb_backup_engine_close( + rocksdb_backup_engine_t* be); + extern rocksdb_t* rocksdb_open_column_families( const rocksdb_options_t* options, const char* name,