ITADN

RFC: Modernizing RocksDB’s Java API using Panama (FFM)

#14574Opendfa1 创建于 2026-04-05
java-api
D
dfa1commented
Hello I'm a long-time user of rocksdbjni (since version 6.x I believe) and I'm happily running it in production since 7 years. Lately I started to use JDK 25 in production and wanted to experiment the new possibilities, especially after reading this excellent article https://rocksdb.org/blog/2024/02/20/foreign-function-interface.html. This RFC proposes a direction for a next‑generation Java API for RocksDB based on the Foreign Function & Memory API (FFM/Panama). The goal is to reduce JNI surface area, improve safety, and make contributions easier — without rewriting the C++ core or breaking existing users. *Motivation* My main motivation is to reduce the lag between the RocksDB C++ and Java: historically every time a new API is defined, some time is needed before it appears. *Goals* - move logic to pure Java, remove JVM crashes in case of bad memory access - Use Panama MemorySegment for zero‑copy - Make contributions easier *Non‑Goals* - Rewriting RocksDB C++ - Breaking existing Java API immediately - Removing JNI before Panama is stable *Proposed Architecture* - Use `c.h` via `jextract` or AI (I've beenusing Claude Code so far and it is quite good) - Wrap it into a Java API that looks really 1:1 with the current rocksdbjni - Any Java class is holding the `MemorySegment` , the code can be generated in a very mechanical way + few tweaks around ownership of some related objects (to be clarified). Example ```java public final class FlushOptions implements AutoCloseable { static final MethodHandle MH_CREATE; private static final MethodHandle MH_DESTROY; private static final MethodHandle MH_SET_WAIT; private static final MethodHandle MH_GET_WAIT; static { MH_CREATE = RocksDB.lookup("rocksdb_flushoptions_create", FunctionDescriptor.of(ValueLayout.ADDRESS)); MH_DESTROY = RocksDB.lookup("rocksdb_flushoptions_destroy", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS)); // void rocksdb_flushoptions_set_wait(opts*, unsigned char) MH_SET_WAIT = RocksDB.lookup("rocksdb_flushoptions_set_wait", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_BYTE)); // unsigned char rocksdb_flushoptions_get_wait(opts*) MH_GET_WAIT = RocksDB.lookup("rocksdb_flushoptions_get_wait", FunctionDescriptor.of(ValueLayout.JAVA_BYTE, ValueLayout.ADDRESS)); } private final MemorySegment ptr; /** * Creates FlushOptions with {@code wait = true} (the default). */ public FlushOptions() { try { this.ptr = (MemorySegment) MH_CREATE.invokeExact(); } catch (Throwable t) { throw new RocksDBException("flushoptions create failed", t); } } /** * If {@code true} (default), {@code flush()} blocks until the memtable flush * completes. If {@code false}, the flush is submitted asynchronously. * * @return {@code this} for chaining */ public FlushOptions setWait(boolean wait) { try { MH_SET_WAIT.invokeExact(ptr, wait ? (byte) 1 : (byte) 0); return this; } catch (Throwable t) { throw new RocksDBException("flushoptions setWait failed", t); } } /** Returns whether flush waits for completion. */ public boolean isWait() { try { return ((byte) MH_GET_WAIT.invokeExact(ptr)) != 0; } catch (Throwable t) { throw new RocksDBException("flushoptions getWait failed", t); } } @Override public void close() { try { MH_DESTROY.invokeExact(ptr); } catch (Throwable t) { throw new RocksDBException("flushoptions destroy failed", t); } } } ``` *Call for Contributors* There is an experimental repository, created in few hours of work (mostly by Claude): https://github.com/dfa1/rocksdbffm Performance numbers are not bad but they need extra validation. Feedback from the RocksDB maintainers and the community would be extremely valuable at this stage /cc @adamretter @alanpaxton
3 条评论