rockside 是 ToplingDB 的核心 submodule
rockside 就是 ToplingDB 的 SidePlugin 插件体系的实现。
ToplingDB fork 自 RocksDB,核心是两个 github 仓库:
ToplingDB fork 自 RocksDB,仅对 RocksDB 进行最少的必要的修改 rockside SidePlugin 插件体系,是 ToplingDB 的 submodule
ToplingDB 对 RocksDB 做了很多改进:
1.修复了 RocksDB 的很多 Bug,其中有几十个修复已经 Pull Request 到了上游 RocksDB
2.SidePlugin 插件体系 可以通过 json/yaml 设定 DB 的各种配置参数,用户代码只需要关注自己的业务逻辑,不需要操心任何配置相关的事情
3.SidePlugin 内置了对 RocksDB 自身所有组件的支持(例如各种 TableFactory, Cache, RateLimiter, WriteBufferManager 等等)
4.通过 SidePlugin 框架,内嵌了一个 Http Web Server,可以展示 DB 的各种内部状态(例如展示当前生效的配置参数,展示 LSM 树形态等等),还可以将 DB 的各种内部指标导出到 Prometheus+grafana 实现监控
5.通过内嵌的 Http Web Server,不用重启进程,在线修改 DB 的各种配置参数
6.分布式 Compact 将 Compact 转移到专有的计算集群,并且这也是通过 json/yaml 配置来实现的,用户代码不需要为此进行任何修改!
7.分布式 Compact 完美支持带状态的 CompactionFilter, MergeOperator, EventHandler 等等,当然,这需要用户自己实现状态的序列化/反序列化
8.Topling 性能组件:更快的 MemTable,更快的SST,内存压缩的SST,这些也是通过 json/yaml 来配置的,不需要修改用户代码
ToplingDB 使用入门
本文原始链接:101 · topling/rockside Wiki
从 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); 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; }
复制
1. Open
-----------------------------------
SidePluginRepo
是 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
复制
2. 启动内嵌的 Http Web Server
理论上,内嵌的 Http Web Server 可以在 Open 中自动启动,但是,我们仍然决定让用户来显式启动:
repo.StartHttpServer();
复制
主要有三个原因:
- 用户可以显式打开同一个 json/yaml 中定义的多个 DB,但内嵌的 Http 只有一个
- 以 RocksDB 的接口风格,错误处理使用返回值
Status
,难以使用同一个Status
来区分,DB Open 与 Http 的错误信息 - 即使 json/yaml 中定义了 http,用户也可能并不想启用内嵌的 Http Web Server
3. Close
需要显式 Close,就一行代码:
repo.CloseAllDB();
复制
复杂一点的:db_bench 针对 ToplingDB 的修改
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) {
复制
ToplingDB GitHub 地址: https://github.com/topling/toplingdb
欢迎大家提 issue!
官网地址:https://topling.cn/
添加官方客服微信可进入技术交流群免费试用云原生数据库 Todis(外存版 Redis)