-
Notifications
You must be signed in to change notification settings - Fork 6
101
示例代码(省略了错误处理,完整版在这里)
从 RocksDB 迁移到 ToplingDB,只需要修改 Open/Close 相关的代码,其它代码不用任何改动。
#include <topling/side_plugin_repo.h>
#include <rocksdb/db.h>
int main(int argc, char* argv[]) {
using namespace rocksdb;
SidePluginRepo repo;
repo.ImportAutoFile(argv[1]); // argv[1] is json/yaml conf file
DB* db = nullptr;
repo.OpenDB(&db); // open the db defined by sub object "open" in json conf
repo.StartHttpServer();
if (strcasecmp(argv[2], "set") == 0) {
db->Put(WriteOptions(), argv[3], argv[4]);
}
else if (strcasecmp(argv[2], "get") == 0) {
std::string val;
db->Get(ReadOptions(), argv[3], &val);
fprintf(stdout, "%s\n", val.c_str());
}
fprintf(stderr, "now visit the web(defined in json/yaml conf file)\n");
fprintf(stderr, "press enter to exit\n");
getchar(); // wait for enter
repo.CloseAllDB();
return 0;
}
假定 ToplingDB 已安装到 /opt,以下列出编译和连接选项
为了兼容性,ToplingDB 的 namespace 和 library 名称仍然是 rocksdb
release 版编译 |
-I/opt/include -std=c++17 -O2 -DNDEBUG , -O2 可换为 -O3 .. |
---|---|
release 版连接 | -L/opt/lib -lrocksdb -lterark-zbs-r -lterark-fsa-r -lterark-core-r |
debug 版编译 | -I/opt/include -std=c++17 -O0 |
debug 版连接 | -L/opt/lib -lrocksdb_debug -lterark-zbs-d -lterark-fsa-d -lterark-core-d |
afr* 版编译 | -I/opt/include -std=c++17 -O1 |
afr* 版连接 | -L/opt/lib -lrocksdb_debug_1 -lterark-zbs-a -lterark-fsa-a -lterark-core-a |
注*: afr 指 Assert For Release,是带有基本优化和断言的版本,相应的 ToplingDB 编译安装时 DEBUG_LEVEL=1
特别注意:应首选动态链接到 ToplingDB,必须静态连接 ToplingDB 时,需要在前后增加 -Wl,--whole-archive
和 --no-whole-archive
,因为 ToplingDB 的插件机制为了隔离用户代码对插件代码的直接依赖,通过 C++ 的全局对象构造来注册插件,注册插件的这些代码静态链接时会被链接器认为从未使用,从而给自动删除掉了,所以需要通过 -Wl,--whole-archive
来强制链接器不要删除这些代码,但同时也会导致链接器保留了真正无用的代码。此外,静态链接还需要链接依赖库的依赖。
g++ <objects> -o a.out -L/opt/lib \
-Wl,--whole-archive \
-lrocksdb -lterark-zbs-r -lterark-fsa-r -lterark-core-r \
-Wl,--no-whole-archive \
-lstdc++fs \
-lcurl -lssl -lcrypto \
-lz -lsnappy -lbz2 -llz4 -lgomp -luring -laio -lpthread -ldl -lrt
运行该程序可复用 db_bench 的 yaml 配置
SidePluginRepo
是 ToplingDB SidePlugin 的核心 class,所有组件都被包含在其中,要使用 SidePlugin,就要先定一个 SidePluginRepo
对象:
SidePluginRepo repo;
有了 SidePluginRepo
对象,接下来就是导入配置参数,最便捷的方式是调用 ImportAutoFile
,该函数根据文件后缀名自动识别 json 和 yaml 文件:
repo.ImportAutoFile(argv[1]); // argv[1] is json/yaml conf file
现在,我们可以打开 DB 了:
DB* db = nullptr;
repo.OpenDB(&db);
在 RocksDB 中,我们一般使用 DB::Open
,少数情况下使用其它 Open 函数,但是在 SidePlugin 中,我们统一用 OpenDB
,具体使用的是哪个 Open 函数,是在 json/yaml 中进行配置的:例如 Todis从结点。
在这个例子中我们使用的是默认的,只有一个 ColumnFamily 的 DB,但其实 OpenDB
是个重载的函数,也可以用来 Open 有多个 ColumnFamily 的 DB(后面修改的 db_bench 就是这样的例子):
DB_MultiCF* dbmcf = nullptr;
repo.OpenDB(&dbmcf); // overload function name
理论上,内嵌的 Http Web Server 可以在 OpenDB
中自动启动,但是,我们仍然决定让用户来显式启动:
repo.StartHttpServer();
主要有三个原因:
- 用户可以显式打开同一个 json/yaml 中定义的多个 DB,但内嵌的 Http 只有一个
- 以 RocksDB 的接口风格,错误处理使用返回值
Status
,难以使用同一个Status
来区分 DB Open 与 Http Start 的错误信息 - 即使 json/yaml 中定义了 http,用户也可能并不想启用内嵌的 Http Web Server
您仍然可以在配置中显式启动 http:如果在 http 对象中定义了 "auto_start_http": true
,就会在打开 DB 之后启动 http
需要显式 Close,就一行代码:
repo.CloseAllDB();
进一步参考:在 ToplingDB 中使用 CompactionFilter
db_bench_tool.cc
是一个 8000 多行的文件,我们让它支持 ToplingDB,只新增了 47 行代码,
无任何其它修改,就拥有了 ToplingDB 的全部能力!以下是 diff 内容:
diff --git a/tools/db_bench_tool.cc b/tools/db_bench_tool.cc
index fcd3c157a..3a1f632a5 100644
--- a/tools/db_bench_tool.cc
+++ b/tools/db_bench_tool.cc
@@ -97,6 +97,8 @@
#include <io.h> // open/close
#endif
+#include "sideplugin/rockside/src/topling/side_plugin_repo.h"
+
using GFLAGS_NAMESPACE::ParseCommandLineFlags;
using GFLAGS_NAMESPACE::RegisterFlagValidator;
using GFLAGS_NAMESPACE::SetUsageMessage;
@@ -1052,6 +1054,7 @@ DEFINE_int32(trace_replay_threads, 1,
DEFINE_bool(io_uring_enabled, true,
"If true, enable the use of IO uring if the platform supports it");
extern "C" bool RocksDbIOUringEnable() { return FLAGS_io_uring_enabled; }
+DEFINE_string(json, "", "json config file.");
#endif // ROCKSDB_LITE
DEFINE_bool(adaptive_readahead, false,
@@ -3087,6 +3090,7 @@ class Benchmark {
}
void DeleteDBs() {
+ repo_.CloseAllDB(false);
db_.DeleteDBs();
for (const DBWithColumnFamilies& dbwcf : multi_dbs_) {
delete dbwcf.db;
@@ -3104,6 +3108,11 @@ class Benchmark {
}
}
+ void exit(int code) {
+ this->~Benchmark();
+ ::exit(code);
+ }
+
Slice AllocateKey(std::unique_ptr<const char[]>* key_guard) {
char* data = new char[key_size_];
const char* const_data = data;
@@ -3236,6 +3245,7 @@ class Benchmark {
ErrorExit();
}
Open(&open_options_);
+ open_options_ = db_.db->GetOptions();
PrintHeader(open_options_);
std::stringstream benchmark_stream(FLAGS_benchmarks);
std::string name;
@@ -4516,9 +4526,45 @@ class Benchmark {
InitializeOptionsGeneral(opts);
}
+ SidePluginRepo repo_;
void OpenDb(Options options, const std::string& db_name,
DBWithColumnFamilies* db) {
uint64_t open_start = FLAGS_report_open_timing ? FLAGS_env->NowNanos() : 0;
+ if (!FLAGS_json.empty()) {
+ repo_.CloseAllDB(false);
+ repo_.CleanResetRepo();
+ DB_MultiCF* dbmcf = nullptr;
+ Status s = repo_.ImportAutoFile(FLAGS_json);
+ if (!s.ok()) {
+ fprintf(stderr, "ERROR: ImportAutoFile(%s): %s\n",
+ FLAGS_json.c_str(), s.ToString().c_str());
+ exit(1);
+ }
+ s = repo_.OpenDB(&dbmcf);
+ if (!s.ok()) {
+ fprintf(stderr, "ERROR: OpenDB(): Config File=%s: %s\n",
+ FLAGS_json.c_str(), s.ToString().c_str());
+ exit(1);
+ }
+ s = repo_.StartHttpServer();
+ if (!s.ok()) {
+ fprintf(stderr, "ERROR: StartHttpServer(): JsonFile=%s: %s\n",
+ FLAGS_json.c_str(), s.ToString().c_str());
+ exit(1);
+ }
+ db->cfh = dbmcf->cf_handles;
+ db->db = dbmcf->db;
+ if (auto tdb = dynamic_cast<OptimisticTransactionDB*>(dbmcf->db)) {
+ db->opt_txn_db = tdb;
+ db->db = tdb->GetBaseDB();
+ }
+ db->num_created = FLAGS_num_column_families;
+ db->num_hot = FLAGS_num_column_families;
+ DBOptions dbo = db->db->GetDBOptions();
+ dbstats = dbo.statistics;
+ FLAGS_db = db->db->GetName();
+ return;
+ }
Status s;
// Open with column families if necessary.
if (FLAGS_num_column_families > 1) {