Skip to content

SidePlugin Java Binding

rockeet edited this page Mar 22, 2023 · 45 revisions

SidePlugin Java Binding 只需要极小的工作量

SidePlugin 的 Java Binding 只需要 Bind SidePluginRepo,并且只需要 bind 极少的方法(此处仅列出声明):

class SidePluginRepo extends RocksObject {
    public SidePluginRepo(); // constructor
    public void importAutoFile(String fname) throws RocksDBException;
    public RocksDB openDB(String js) throws RocksDBException;
    public RocksDB openDB(String js, List<ColumnFamilyHandle> out_cfhs);
    public RocksDB openDB() throws RocksDBException;
    public RocksDB openDB(List<ColumnFamilyHandle> out_cfhs) throws RocksDBException;
    public void startHttpServer() throws RocksDBException;
    public void closeHttpServer();
    public void closeAllDB(); // conform to C++ native name CloseAllDB
    public void close(); // synonym to closeAllDB
    public void put(String name, String spec, Options opt); // rarely used
    public void put(String name, String spec, DBOptions dbo);  // rarely used
    public void put(String name, String spec, ColumnFamilyOptions cfo); // rarely used
}

这么小的工作量,我已经多年没碰过 java,jni 更是从来没用过,实现这个 Binding,现学现卖,从头至尾,也只花了不到一天的时间。所以,良好的架构设计,可以极大地减小工作量,如果按照 SidePlugin 的架构,rocksdbjava 中的代码(java 代码与 c++ 各约 4 万行)至少可以缩减 90%。

参考 C++ 版的 101,Java 版的写法没啥大的不同;再参考实际的例子 SideGetBenchmarks,相信大家很容易使用 java 调用 ToplingDB。

其中的 put 方法是为了兼容已有代码:如果现存代码对各种 Option 进行了一些设置,并且这些设置无法通过配置文件进行配置(例如自定义了 java 版的 CompactionFilter),就先把 option put 到 SidePluginRepo,然后再调用 importAutoFile —— importAutoFile 会补充 put option 中的缺失选项,并覆盖同名选项!

运行 SideGetBenchmarks

步骤 1:编译并安装 rocksdb

git clone https://github.com/topling/toplingdb.git --depth 1
cd toplingdb
git submodule update --init --recursive
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts # silent git
make -j`nproc` DEBUG_LEVEL=0 shared_lib
sudo make install-shared PREFIX=/opt

步骤 2: 编译 rocksdbjava

make rocksdbjava -j`nproc` DEBUG_LEVEL=0

步骤 3: 将 rocksdbjava 加入 maven 仓库

你现在应该位于 toplingdb 仓库的根目录

cd java/target
cp rocksdbjni-7.10.0-linux64.jar rocksdbjni-7.10.0-SNAPSHOT-linux64.jar
mvn install:install-file -Dfile=rocksdbjni-7.10.0-SNAPSHOT-linux64.jar -DgroupId=org.rocksdb -DartifactId=rocksdbjni -Dversion=7.10.0-SNAPSHOT -Dpackaging=jar

步骤 4: 编译 SideGetBenchmarks

假定你现在位于 toplingdb 仓库的根目录

cd java/jmh
mvn clean package

步骤 5: 运行 SideGetBenchmarks

假定你现在已经位于 toplingdb/java/jmh

mkdir -p /dev/shm/db_bench_enterprise
cp ../../sideplugin/rockside/src/topling/web/{style.css,index.html} /dev/shm/db_bench_enterprise
export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH # for libterark-*
export LD_PRELOAD=libterark-zbs-g++-12.1-r.so:libterark-fsa-g++-12.1-r.so:libjemalloc.so
java -jar target/rocksdbjni-jmh-1.0-SNAPSHOT-benchmarks.jar \
     -p keyCount=1000 -p keySize=128 -p valueSize=32768 \
     -p sideConf=../../sideplugin/rockside/sample-conf/db_bench_enterprise.yaml SideGetBenchmarks

运行起来之后,可以访问 http://127.0.0.1:2011 观测 db 状态。

说明 1:社区版用户请将 db_bench_enterprise.yaml 替换为 db_bench_community.yaml,这两个文件都在 toplingdb/sideplugin/rockside/sample-conf 中, sideplugin/rockside 是 ToplingDB 的 submodule。

说明 2:设置 LD_PRELOAD 是因为 toplingdb 和 jemalloc 动态库使用了 init exec 类型的 TLS(线程局部存储),这种 TLS 访问速度最快,但使用了这种 TLS 的动态库必须预先加载,或者由可执行文件显式链接。而 java 加载 jni 是由 jvm 动态加载的,如果不用 LD_PRELOAD,会导致动态库中的这种 TLS 初始化失败。

限制

目前使用 Java 实现组件无法用 Java 代码注册到 SidePlugin 的插件库中,一般情况下这并不是什么严重问题,唯一的问题在于:无法使用分布式 Compact。

例如在 Java 中实现了自定义的 CompactionFilter/MergeOperator ,因为无法注册到 SidePlugin 的插件库中,所以无法为 dcompact_worker 预加载相应的动态库以运行分布式 Compact。除非(1)实现专门的动态库,通过 jni 回调 Java 代码把相应的组件注册到 SidePlugin 中,并且把 java 编译成本地代码的动态库。或者(2)使用 C++ 实现相同功能的插件并注册到 SidePlugin 中,例如数据都是 protobuf 格式,用 C++ 实现相应插件并不困难,而且性能还更高。