RocksJava is structured in 3 layers:

  • The Java classes within the package which form the RocksJava API. Java users only directly interact with this layer.

  • JNI code written in C++ that provides the link between the Java API and RocksDB.

  • RocksDB itself written in C++ and compiled into a native library which is used by the JNI layer.

(We try hard to keep RocksJava API in sync with RocksDB's C++ API, but it often falls behind. We highly encourage community contributions … so please feel free to send us a Pull Request if you find yourself needing a certain API which is in C++ but not yet in Java.)

In this page you will learn the basics of RocksDB Java API.

You may either use the pre-built Maven artifacts that we publish, or build RocksJava yourself from its source code.

We also publish RocksJava artifacts to Maven Central, in case you just want to depend on the jar instead of building it on your own: https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.rocksdb%22.

We publish both an uber-like Jar (rocksdbjni-X.X.X.jar) which contains native libraries for all supported platforms alongside the Java class files, as well as smaller platform specific Jars (such as rocksdbjni-X.X.X-linux64.jar).

If you are using the Maven Central compiled artifacts on Microsoft Windows, they were compiled using Microsoft Visual Studio 2015, if you don't have "Microsoft Visual C++ 2015 Redistributable" installed, then you will need to install it from https://www.microsoft.com/en-us/download/details.aspx?id=48145, or otherwise build your own binaries from source code.

Compiling from Source

To build RocksJava, you first need to set your JAVA_HOME environment variable to point to the location where Java SDK is installed (must be Java 1.7+). You must also have the prerequisites for your platform to compile the native library of RocksDB, see . Once JAVA_HOME is properly set and you have the prerequisites installed, simply running make rocksdbjava will build the Java bindings for RocksDB:

  1. $ make -j8 rocksdbjava

This will generate rocksdbjni.jar and librocksdbjni.so (or librocksdbjni.jnilib on macOS) in the java/target directory under the rocksdb root directory. Specifically, rocksdbjni.jar contains the Java classes that defines the Java API for RocksDB, while librocksdbjni.so includes the C++ rocksdb library and the native implementation of the Java classes defined in rocksdbjni.jar.

To run the unit tests:

[Facebook internal only] On Facebook devservers:

  1. $ ROCKSDB_NO_FBCODE=1 make jtest

To clean:

Samples

We provided some samples here, if you want to jump directly into code.

Many of the Java Objects used in the RocksJava API will be backed by C++ objects for which the Java Objects have ownership. As C++ has no notion of automatic garbage collection for its heap in the way that Java does, we must explicitly free the memory used by the C++ objects when we are finished with them.

Any Java object in RocksJava that manages a C++ object will inherit from org.rocksdb.AbstractNativeReference which is designed to assist in managing and cleaning up any owned C++ objects when you are done with them. Two mechanisms are used for this:

  • AbstractNativeReference#close().

To ease the use of this, this method overrides java.lang.AutoCloseable#close(), which enables it to be used with ARM (Automatic Resource Management) like constructs such as Java SE 7's statement.

  • AbstractNativeReference#finalize().

This method is called by Java's Finalizer thread, when all strong references to the object have expired and just before the object is Garabage Collected. Ultimately it delegates to AbstractNativeReference#close(). The user should however not rely on this, and instead consider it more of a last-effort fail-safe.

It will certainly make sure that owned C++ objects will be cleaned up when the Java object is collected. It does not however help to manage the memory of RocksJava as a whole, as the memory allocated on the heap in C++ for the native C++ objects backing the Java objects is effectively invisible to the Java GC process and so the JVM cannot correctly calculate the memory pressure for the GC. Users should always explicitly call AbstractNativeReference#close() on their RocksJava objects when they are done with them.

Opening a Database

A rocksdb database has a name which corresponds to a file system directory. All of the contents of database are stored in this directory. The following example shows how to open a database, creating it if necessary:

  1. import org.rocksdb.RocksDB;
  2. import org.rocksdb.Options;
  3. ...
  4. // a static method that loads the RocksDB C++ library.
  5. RocksDB.loadLibrary();
  6.  
  7. // the Options class contains a set of configurable DB options
  8. // that determines the behaviour of the database.
  9. try (final Options options = new Options().setCreateIfMissing(true)) {
  10.  
  11. try (final RocksDB db = RocksDB.open(options, "path/to/db")) {
  12.  
  13. // do something
  14. }
  15. } catch (RocksDBException e) {
  16. // do some error handling
  17. ...
  18. }
  19. ...

The database provides put, remove, and get methods to modify/query the database. For example, the following code moves the value stored under key1 to key2.

Opening a Database with Column Families

A rocksdb database may have multiple column families. Column Families allow you to group similar key/values together and perform operations on them independently of other Column Families.

It is important to note that when working with Column Families in RocksJava, there is a very specific order of destruction that must be obeyed for the database to correctly free all resources and shutdown. The ordering is illustrated in this code example:

  1. import org.rocksdb.RocksDB;
  2. import org.rocksdb.Options;
  3. ...
  4. // a static method that loads the RocksDB C++ library.
  5. RocksDB.loadLibrary();
  6.  
  7. try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions().optimizeUniversalStyleCompaction()) {
  8.  
  9. // list of column family descriptors, first entry must always be default column family
  10. final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
  11. new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts),
  12. new ColumnFamilyDescriptor("my-first-columnfamily".getBytes(), cfOpts)
  13. );
  14.  
  15. // a list which will hold the handles for the column families once the db is opened
  16. new ArrayList<>();
  17.  
  18. try (final DBOptions options = new DBOptions()
  19. .setCreateIfMissing(true)
  20. .setCreateMissingColumnFamilies(true);
  21. final RocksDB db = RocksDB.open(options,
  22. "path/to/do", cfDescriptors,
  23. columnFamilyHandleList)) {
  24.  
  25. try {
  26.  
  27. // do something
  28.  
  29. } finally {
  30.  
  31. // NOTE frees the column family handles before freeing the db
  32. for (final ColumnFamilyHandle columnFamilyHandle :
  33. columnFamilyHandleList) {
  34. columnFamilyHandle.close();
  35. }
  36. } // frees the db and the db options
  37. }
  38. } // frees the column family options
  39. ...