columnFamilyHandles) throws RocksDBException {
+ // This allows to use the rocksjni default Options instead of
+ // the c++ one.
+ Options options = new Options();
+ return open(options, path, columnFamilyNames, columnFamilyHandles);
+ }
+
+ /**
+ * The factory constructor of RocksDB that opens a RocksDB instance given
+ * the path to the database using the specified options and db path.
+ *
+ *
+ * Options instance *should* not be disposed before all DBs using this options
+ * instance have been closed. If user doesn't call options dispose explicitly,
+ * then this options instance will be GC'd automatically.
+ *
* Options instance can be re-used to open multiple DBs if DB statistics is
* not used. If DB statistics are required, then its recommended to open DB
* with new Options instance as underlying native statistics instance does not
- * use any locks to prevent concurrent updates.
+ * use any locks to prevent concurrent updates.
+ *
+ * @param options {@link org.rocksdb.Options} instance.
+ * @param path the path to the rocksdb.
+ * @return a {@link RocksDB} instance on success, null if the specified
+ * {@link RocksDB} can not be opened.
+ *
+ * @throws org.rocksdb.RocksDBException
+ * @see Options#setCreateIfMissing(boolean)
*/
public static RocksDB open(Options options, String path)
throws RocksDBException {
@@ -133,6 +174,169 @@ public class RocksDB extends RocksObject {
return db;
}
+ /**
+ * The factory constructor of RocksDB that opens a RocksDB instance given
+ * the path to the database using the specified options and db path and a list
+ * of column family names.
+ *
+ * If opened in read write mode every existing column family name must be passed
+ * within the list to this method.
+ *
+ * If opened in read-only mode only a subset of existing column families must
+ * be passed to this method.
+ *
+ * Options instance *should* not be disposed before all DBs using this options
+ * instance have been closed. If user doesn't call options dispose explicitly,
+ * then this options instance will be GC'd automatically.
+ *
+ * Options instance can be re-used to open multiple DBs if DB statistics is
+ * not used. If DB statistics are required, then its recommended to open DB
+ * with new Options instance as underlying native statistics instance does not
+ * use any locks to prevent concurrent updates.
+ *
+ * ColumnFamily handles are disposed when the RocksDB instance is disposed.
+ *
+ * @param options {@link org.rocksdb.Options} instance.
+ * @param path the path to the rocksdb.
+ * @param columnFamilyNames list of column family names
+ * @param columnFamilyHandles will be filled with ColumnFamilyHandle instances
+ * on open.
+ * @return a {@link RocksDB} instance on success, null if the specified
+ * {@link RocksDB} can not be opened.
+ *
+ * @throws org.rocksdb.RocksDBException
+ * @see Options#setCreateIfMissing(boolean)
+ */
+ public static RocksDB open(Options options, String path, List columnFamilyNames,
+ List columnFamilyHandles)
+ throws RocksDBException {
+ RocksDB db = new RocksDB();
+ List cfReferences = db.open(options.nativeHandle_, path,
+ columnFamilyNames, columnFamilyNames.size());
+ for (int i=0; i columnFamilyNames,
+ List columnFamilyHandles) throws RocksDBException {
+ // This allows to use the rocksjni default Options instead of
+ // the c++ one.
+ Options options = new Options();
+ return openReadOnly(options, path, columnFamilyNames, columnFamilyHandles);
+ }
+
+ /**
+ * The factory constructor of RocksDB that opens a RocksDB instance in
+ * Read-Only mode given the path to the database using the specified
+ * options and db path.
+ *
+ * Options instance *should* not be disposed before all DBs using this options
+ * instance have been closed. If user doesn't call options dispose explicitly,
+ * then this options instance will be GC'd automatically.
+ *
+ * @param options {@link Options} instance.
+ * @param path the path to the RocksDB.
+ * @return a {@link RocksDB} instance on success, null if the specified
+ * {@link RocksDB} can not be opened.
+ * @throws RocksDBException
+ */
+ public static RocksDB openReadOnly(Options options, String path)
+ throws RocksDBException {
+ // when non-default Options is used, keeping an Options reference
+ // in RocksDB can prevent Java to GC during the life-time of
+ // the currently-created RocksDB.
+ RocksDB db = new RocksDB();
+ db.openROnly(options.nativeHandle_, path);
+
+ db.storeOptionsInstance(options);
+ return db;
+ }
+
+ /**
+ * The factory constructor of RocksDB that opens a RocksDB instance in
+ * Read-Only mode given the path to the database using the specified
+ * options and db path.
+ *
+ * This open method allows to open RocksDB using a subset of available
+ * column families
+ * Options instance *should* not be disposed before all DBs using this
+ * options instance have been closed. If user doesn't call options dispose
+ * explicitly,then this options instance will be GC'd automatically.
+ *
+ * @param options {@link Options} instance.
+ * @param path the path to the RocksDB.
+ * @param columnFamilyNames list of column family names
+ * @param columnFamilyHandles will be filled with ColumnFamilyHandle instances
+ * on open.
+ * @return a {@link RocksDB} instance on success, null if the specified
+ * {@link RocksDB} can not be opened.
+ * @throws RocksDBException
+ */
+ public static RocksDB openReadOnly(Options options, String path,
+ List columnFamilyNames, List columnFamilyHandles)
+ throws RocksDBException {
+ // when non-default Options is used, keeping an Options reference
+ // in RocksDB can prevent Java to GC during the life-time of
+ // the currently-created RocksDB.
+ RocksDB db = new RocksDB();
+ List cfReferences = db.openROnly(options.nativeHandle_, path,
+ columnFamilyNames, columnFamilyNames.size());
+ for (int i=0; i List containing the column family names
+ *
+ * @throws RocksDBException
+ */
+ public static List listColumnFamilies(Options options, String path)
+ throws RocksDBException {
+ return RocksDB.listColumnFamilies(options.nativeHandle_, path);
+ }
+
private void storeOptionsInstance(Options options) {
options_ = options;
}
@@ -155,16 +359,39 @@ public class RocksDB extends RocksObject {
*
* @param key the specified key to be inserted.
* @param value the value associated with the specified key.
+ *
+ * @see RocksDBException
*/
public void put(byte[] key, byte[] value) throws RocksDBException {
put(nativeHandle_, key, key.length, value, value.length);
}
+ /**
+ * Set the database entry for "key" to "value" in the specified
+ * column family.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the specified key to be inserted.
+ * @param value the value associated with the specified key.
+ *
+ * throws IllegalArgumentException if column family is not present
+ *
+ * @see RocksDBException
+ */
+ public void put(ColumnFamilyHandle columnFamilyHandle, byte[] key,
+ byte[] value) throws RocksDBException {
+ put(nativeHandle_, key, key.length, value, value.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
/**
* Set the database entry for "key" to "value".
*
* @param key the specified key to be inserted.
* @param value the value associated with the specified key.
+ *
+ * @see RocksDBException
*/
public void put(WriteOptions writeOpts, byte[] key, byte[] value)
throws RocksDBException {
@@ -172,8 +399,73 @@ public class RocksDB extends RocksObject {
key, key.length, value, value.length);
}
+ /**
+ * Set the database entry for "key" to "value" for the specified
+ * column family.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the specified key to be inserted.
+ * @param value the value associated with the specified key.
+ *
+ * throws IllegalArgumentException if column family is not present
+ *
+ * @see RocksDBException
+ * @see IllegalArgumentException
+ */
+ public void put(ColumnFamilyHandle columnFamilyHandle, WriteOptions writeOpts,
+ byte[] key, byte[] value) throws RocksDBException {
+ put(nativeHandle_, writeOpts.nativeHandle_, key, key.length, value, value.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, else true.
+ *
+ * This check is potentially lighter-weight than invoking DB::Get(). One way
+ * to make this lighter weight is to avoid doing any IOs.
+ *
+ * @param columnFamilyHandle {@link ColumnFamilyHandle} instnace
+ * @param key byte array of a key to search for
+ * @param value StringBuffer instance which is a out parameter if a value is
+ * found in block-cache.
+ * @return boolean value indicating if key does not exist or might exist.
+ */
+ public boolean keyMayExist(ColumnFamilyHandle columnFamilyHandle,
+ byte[] key, StringBuffer value){
+ return keyMayExist(key, key.length, columnFamilyHandle.nativeHandle_,
+ value);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, else true.
+ *
+ * This check is potentially lighter-weight than invoking DB::Get(). One way
+ * to make this lighter weight is to avoid doing any IOs.
+ *
+ * @param readOptions {@link ReadOptions} instance
+ * @param columnFamilyHandle {@link ColumnFamilyHandle} instnace
+ * @param key byte array of a key to search for
+ * @param value StringBuffer instance which is a out parameter if a value is
+ * found in block-cache.
+ * @return boolean value indicating if key does not exist or might exist.
+ */
+ public boolean keyMayExist(ReadOptions readOptions,
+ ColumnFamilyHandle columnFamilyHandle, byte[] key, StringBuffer value){
+ return keyMayExist(readOptions.nativeHandle_,
+ key, key.length, columnFamilyHandle.nativeHandle_,
+ value);
+ }
+
/**
* Apply the specified updates to the database.
+ *
+ * @param writeOpts WriteOptions instance
+ * @param updates WriteBatch instance
+ *
+ * @see RocksDBException
*/
public void write(WriteOptions writeOpts, WriteBatch updates)
throws RocksDBException {
@@ -181,7 +473,7 @@ public class RocksDB extends RocksObject {
}
/**
- * Get the value associated with the specified key.
+ * Get the value associated with the specified key within column family
*
* @param key the key to retrieve the value.
* @param value the out-value to receive the retrieved value.
@@ -191,11 +483,35 @@ public class RocksDB extends RocksObject {
* input buffer {@code value} is insufficient and partial result will
* be returned. RocksDB.NOT_FOUND will be returned if the value not
* found.
+ *
+ * @see RocksDBException
*/
public int get(byte[] key, byte[] value) throws RocksDBException {
return get(nativeHandle_, key, key.length, value, value.length);
}
+ /**
+ * Get the value associated with the specified key within column family.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the key to retrieve the value.
+ * @param value the out-value to receive the retrieved value.
+ * @return The size of the actual value that matches the specified
+ * {@code key} in byte. If the return value is greater than the
+ * length of {@code value}, then it indicates that the size of the
+ * input buffer {@code value} is insufficient and partial result will
+ * be returned. RocksDB.NOT_FOUND will be returned if the value not
+ * found.
+ *
+ * @throws RocksDBException
+ */
+ public int get(ColumnFamilyHandle columnFamilyHandle, byte[] key, byte[] value)
+ throws RocksDBException, IllegalArgumentException {
+ return get(nativeHandle_, key, key.length, value, value.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
/**
* Get the value associated with the specified key.
*
@@ -207,12 +523,35 @@ public class RocksDB extends RocksObject {
* input buffer {@code value} is insufficient and partial result will
* be returned. RocksDB.NOT_FOUND will be returned if the value not
* found.
+ *
+ * @throws RocksDBException
*/
public int get(ReadOptions opt, byte[] key, byte[] value)
throws RocksDBException {
return get(nativeHandle_, opt.nativeHandle_,
key, key.length, value, value.length);
}
+ /**
+ * Get the value associated with the specified key within column family.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the key to retrieve the value.
+ * @param value the out-value to receive the retrieved value.
+ * @return The size of the actual value that matches the specified
+ * {@code key} in byte. If the return value is greater than the
+ * length of {@code value}, then it indicates that the size of the
+ * input buffer {@code value} is insufficient and partial result will
+ * be returned. RocksDB.NOT_FOUND will be returned if the value not
+ * found.
+ *
+ * @throws RocksDBException
+ */
+ public int get(ColumnFamilyHandle columnFamilyHandle, ReadOptions opt, byte[] key,
+ byte[] value) throws RocksDBException {
+ return get(nativeHandle_, opt.nativeHandle_, key, key.length, value,
+ value.length, columnFamilyHandle.nativeHandle_);
+ }
/**
* The simplified version of get which returns a new byte array storing
@@ -223,12 +562,30 @@ public class RocksDB extends RocksObject {
* @return a byte array storing the value associated with the input key if
* any. null if it does not find the specified key.
*
- * @see RocksDBException
+ * @throws RocksDBException
*/
public byte[] get(byte[] key) throws RocksDBException {
return get(nativeHandle_, key, key.length);
}
+ /**
+ * The simplified version of get which returns a new byte array storing
+ * the value associated with the specified input key if any. null will be
+ * returned if the specified key is not found.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the key retrieve the value.
+ * @return a byte array storing the value associated with the input key if
+ * any. null if it does not find the specified key.
+ *
+ * @throws RocksDBException
+ */
+ public byte[] get(ColumnFamilyHandle columnFamilyHandle, byte[] key)
+ throws RocksDBException {
+ return get(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
+ }
+
/**
* The simplified version of get which returns a new byte array storing
* the value associated with the specified input key if any. null will be
@@ -239,12 +596,32 @@ public class RocksDB extends RocksObject {
* @return a byte array storing the value associated with the input key if
* any. null if it does not find the specified key.
*
- * @see RocksDBException
+ * @throws RocksDBException
*/
public byte[] get(ReadOptions opt, byte[] key) throws RocksDBException {
return get(nativeHandle_, opt.nativeHandle_, key, key.length);
}
+ /**
+ * The simplified version of get which returns a new byte array storing
+ * the value associated with the specified input key if any. null will be
+ * returned if the specified key is not found.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key the key retrieve the value.
+ * @param opt Read options.
+ * @return a byte array storing the value associated with the input key if
+ * any. null if it does not find the specified key.
+ *
+ * @throws RocksDBException
+ */
+ public byte[] get(ColumnFamilyHandle columnFamilyHandle, ReadOptions opt,
+ byte[] key) throws RocksDBException {
+ return get(nativeHandle_, opt.nativeHandle_, key, key.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
/**
* Returns a map of keys for which values were found in DB.
*
@@ -252,7 +629,7 @@ public class RocksDB extends RocksObject {
* @return Map where key of map is the key passed by user and value for map
* entry is the corresponding value in DB.
*
- * @see RocksDBException
+ * @throws RocksDBException
*/
public Map multiGet(List keys)
throws RocksDBException {
@@ -273,6 +650,43 @@ public class RocksDB extends RocksObject {
return keyValueMap;
}
+ /**
+ * Returns a map of keys for which values were found in DB.
+ *
+ * Note: Every key needs to have a related column family name in
+ * {@code columnFamilyHandleList}.
+ *
+ *
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @param keys List of keys for which values need to be retrieved.
+ * @return Map where key of map is the key passed by user and value for map
+ * entry is the corresponding value in DB.
+ *
+ * @throws RocksDBException
+ * @throws IllegalArgumentException
+ */
+ public Map multiGet(List columnFamilyHandleList,
+ List keys) throws RocksDBException, IllegalArgumentException {
+ assert(keys.size() != 0);
+ // Check if key size equals cfList size. If not a exception must be
+ // thrown. If not a Segmentation fault happens.
+ if (keys.size()!=columnFamilyHandleList.size()) {
+ throw new IllegalArgumentException(
+ "For each key there must be a ColumnFamilyHandle.");
+ }
+ List values = multiGet(nativeHandle_, keys, keys.size(),
+ columnFamilyHandleList);
+
+ Map keyValueMap = new HashMap();
+ for(int i = 0; i < values.size(); i++) {
+ if (values.get(i) == null) {
+ continue;
+ }
+ keyValueMap.put(keys.get(i), values.get(i));
+ }
+ return keyValueMap;
+ }
/**
* Returns a map of keys for which values were found in DB.
@@ -282,7 +696,7 @@ public class RocksDB extends RocksObject {
* @return Map where key of map is the key passed by user and value for map
* entry is the corresponding value in DB.
*
- * @see RocksDBException
+ * @throws RocksDBException
*/
public Map multiGet(ReadOptions opt, List keys)
throws RocksDBException {
@@ -303,10 +717,56 @@ public class RocksDB extends RocksObject {
return keyValueMap;
}
+ /**
+ * Returns a map of keys for which values were found in DB.
+ *
+ * Note: Every key needs to have a related column family name in
+ * {@code columnFamilyHandleList}.
+ *
+ *
+ * @param opt Read options.
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @param keys of keys for which values need to be retrieved.
+ * @return Map where key of map is the key passed by user and value for map
+ * entry is the corresponding value in DB.
+ *
+ * @throws RocksDBException
+ * @throws java.lang.IllegalArgumentException
+ */
+ public Map multiGet(ReadOptions opt,
+ List columnFamilyHandleList, List keys)
+ throws RocksDBException {
+ assert(keys.size() != 0);
+ // Check if key size equals cfList size. If not a exception must be
+ // thrown. If not a Segmentation fault happens.
+ if (keys.size()!=columnFamilyHandleList.size()){
+ throw new IllegalArgumentException(
+ "For each key there must be a ColumnFamilyHandle.");
+ }
+
+ List values = multiGet(nativeHandle_, opt.nativeHandle_,
+ keys, keys.size(), columnFamilyHandleList);
+
+ Map keyValueMap = new HashMap();
+ for(int i = 0; i < values.size(); i++) {
+ if(values.get(i) == null) {
+ continue;
+ }
+ keyValueMap.put(keys.get(i), values.get(i));
+ }
+
+ return keyValueMap;
+ }
+
/**
* Remove the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
* did not exist in the database.
+ *
+ * @param key Key to delete within database
+ *
+ * @throws RocksDBException
*/
public void remove(byte[] key) throws RocksDBException {
remove(nativeHandle_, key, key.length);
@@ -316,27 +776,102 @@ public class RocksDB extends RocksObject {
* Remove the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
* did not exist in the database.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param key Key to delete within database
+ *
+ * @throws RocksDBException
+ */
+ public void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key)
+ throws RocksDBException {
+ remove(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
+ }
+
+ /**
+ * Remove the database entry (if any) for "key". Returns OK on
+ * success, and a non-OK status on error. It is not an error if "key"
+ * did not exist in the database.
+ *
+ * @param writeOpt WriteOptions to be used with delete operation
+ * @param key Key to delete within database
+ *
+ * @throws RocksDBException
*/
public void remove(WriteOptions writeOpt, byte[] key)
throws RocksDBException {
remove(nativeHandle_, writeOpt.nativeHandle_, key, key.length);
}
+ /**
+ * Remove the database entry (if any) for "key". Returns OK on
+ * success, and a non-OK status on error. It is not an error if "key"
+ * did not exist in the database.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param writeOpt WriteOptions to be used with delete operation
+ * @param key Key to delete within database
+ *
+ * @throws RocksDBException
+ */
+ public void remove(ColumnFamilyHandle columnFamilyHandle, WriteOptions writeOpt,
+ byte[] key) throws RocksDBException {
+ remove(nativeHandle_, writeOpt.nativeHandle_, key, key.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
+ /**
+ * DB implements can export properties about their state
+ * via this method on a per column family level.
+ *
+ * If {@code property} is a valid property understood by this DB
+ * implementation, fills {@code value} with its current value and
+ * returns true. Otherwise returns false.
+ *
+ * Valid property names include:
+ *
+ * - "rocksdb.num-files-at-level" - return the number of files at level ,
+ * where is an ASCII representation of a level number (e.g. "0").
+ * - "rocksdb.stats" - returns a multi-line string that describes statistics
+ * about the internal operation of the DB.
+ * - "rocksdb.sstables" - returns a multi-line string that describes all
+ * of the sstables that make up the db contents.
+ *
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @param property to be fetched. See above for examples
+ * @return property value
+ *
+ * @throws RocksDBException
+ */
+ public String getProperty(ColumnFamilyHandle columnFamilyHandle, String property)
+ throws RocksDBException {
+ return getProperty0(nativeHandle_, columnFamilyHandle.nativeHandle_, property,
+ property.length());
+ }
+
/**
* DB implementations can export properties about their state
- via this method. If "property" is a valid property understood by this
- DB implementation, fills "*value" with its current value and returns
- true. Otherwise returns false.
-
-
- Valid property names include:
-
- "rocksdb.num-files-at-level" - return the number of files at level ,
- where is an ASCII representation of a level number (e.g. "0").
- "rocksdb.stats" - returns a multi-line string that describes statistics
- about the internal operation of the DB.
- "rocksdb.sstables" - returns a multi-line string that describes all
- of the sstables that make up the db contents.
+ * via this method. If "property" is a valid property understood by this
+ * DB implementation, fills "*value" with its current value and returns
+ * true. Otherwise returns false.
+ *
+ * Valid property names include:
+ *
+ * - "rocksdb.num-files-at-level" - return the number of files at level ,
+ * where is an ASCII representation of a level number (e.g. "0").
+ * - "rocksdb.stats" - returns a multi-line string that describes statistics
+ * about the internal operation of the DB.
+ * - "rocksdb.sstables" - returns a multi-line string that describes all
+ * of the sstables that make up the db contents.
+ *
+ *
+ * @param property to be fetched. See above for examples
+ * @return property value
+ *
+ * @throws RocksDBException
*/
public String getProperty(String property) throws RocksDBException {
return getProperty0(nativeHandle_, property, property.length());
@@ -356,6 +891,77 @@ public class RocksDB extends RocksObject {
return new RocksIterator(iterator0(nativeHandle_));
}
+ /**
+ * Return a heap-allocated iterator over the contents of the database.
+ * The result of newIterator() is initially invalid (caller must
+ * call one of the Seek methods on the iterator before using it).
+ *
+ * Caller should close the iterator when it is no longer needed.
+ * The returned iterator should be closed before this db is closed.
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance
+ * @return instance of iterator object.
+ */
+ public RocksIterator newIterator(ColumnFamilyHandle columnFamilyHandle) {
+ return new RocksIterator(iterator0(nativeHandle_, columnFamilyHandle.nativeHandle_));
+ }
+
+ /**
+ * Returns iterators from a consistent database state across multiple
+ * column families. Iterators are heap allocated and need to be deleted
+ * before the db is deleted
+ *
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @return {@link java.util.List} containing {@link org.rocksdb.RocksIterator}
+ * instances
+ *
+ * @throws RocksDBException
+ */
+ public List newIterators(
+ List columnFamilyHandleList) throws RocksDBException {
+ List iterators =
+ new ArrayList(columnFamilyHandleList.size());
+
+ long[] iteratorRefs = iterators(nativeHandle_, columnFamilyHandleList);
+ for (int i=0; i open(long optionsHandle, String path,
+ List columnFamilyNames, int columnFamilyNamesLength)
+ throws RocksDBException;
+ protected native static List listColumnFamilies(
+ long optionsHandle, String path) throws RocksDBException;
+ protected native void openROnly(
+ long optionsHandle, String path) throws RocksDBException;
+ protected native List openROnly(
+ long optionsHandle, String path, List columnFamilyNames,
+ int columnFamilyNamesLength) throws RocksDBException;
protected native void put(
long handle, byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
+ protected native void put(
+ long handle, byte[] key, int keyLen,
+ byte[] value, int valueLen, long cfHandle) throws RocksDBException;
protected native void put(
long handle, long writeOptHandle,
byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
+ protected native void put(
+ long handle, long writeOptHandle,
+ byte[] key, int keyLen,
+ byte[] value, int valueLen, long cfHandle) throws RocksDBException;
protected native void write(
long writeOptHandle, long batchHandle) throws RocksDBException;
+ protected native boolean keyMayExist(byte[] key, int keyLen,
+ long cfHandle, StringBuffer stringBuffer);
+ protected native boolean keyMayExist(long optionsHandle, byte[] key, int keyLen,
+ long cfHandle, StringBuffer stringBuffer);
protected native int get(
long handle, byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
+ protected native int get(
+ long handle, byte[] key, int keyLen,
+ byte[] value, int valueLen, long cfHandle) throws RocksDBException;
protected native int get(
long handle, long readOptHandle, byte[] key, int keyLen,
byte[] value, int valueLen) throws RocksDBException;
+ protected native int get(
+ long handle, long readOptHandle, byte[] key, int keyLen,
+ byte[] value, int valueLen, long cfHandle) throws RocksDBException;
protected native List multiGet(
long dbHandle, List keys, int keysCount);
+ protected native List multiGet(
+ long dbHandle, List keys, int keysCount, List
+ cfHandles);
protected native List multiGet(
long dbHandle, long rOptHandle, List keys, int keysCount);
+ protected native List multiGet(
+ long dbHandle, long rOptHandle, List keys, int keysCount,
+ List cfHandles);
protected native byte[] get(
long handle, byte[] key, int keyLen) throws RocksDBException;
+ protected native byte[] get(
+ long handle, byte[] key, int keyLen, long cfHandle) throws RocksDBException;
protected native byte[] get(
long handle, long readOptHandle,
byte[] key, int keyLen) throws RocksDBException;
+ protected native byte[] get(
+ long handle, long readOptHandle,
+ byte[] key, int keyLen, long cfHandle) throws RocksDBException;
protected native void remove(
long handle, byte[] key, int keyLen) throws RocksDBException;
+ protected native void remove(
+ long handle, byte[] key, int keyLen, long cfHandle) throws RocksDBException;
protected native void remove(
long handle, long writeOptHandle,
byte[] key, int keyLen) throws RocksDBException;
+ protected native void remove(
+ long handle, long writeOptHandle,
+ byte[] key, int keyLen, long cfHandle) throws RocksDBException;
protected native String getProperty0(long nativeHandle,
String property, int propertyLength) throws RocksDBException;
- protected native long iterator0(long optHandle);
+ protected native String getProperty0(long nativeHandle, long cfHandle,
+ String property, int propertyLength) throws RocksDBException;
+ protected native long iterator0(long handle);
+ protected native long iterator0(long handle, long cfHandle);
+ protected native long[] iterators(long handle,
+ List columnFamilyNames) throws RocksDBException;
private native void disposeInternal(long handle);
+ private native long createColumnFamily(long handle, String name) throws RocksDBException;
+ private native void dropColumnFamily(long handle, long cfHandle) throws RocksDBException;
+
protected Options options_;
}
diff --git a/java/org/rocksdb/WriteBatch.java b/java/org/rocksdb/WriteBatch.java
index f538dc1a0..0a16d5104 100644
--- a/java/org/rocksdb/WriteBatch.java
+++ b/java/org/rocksdb/WriteBatch.java
@@ -47,6 +47,16 @@ public class WriteBatch extends RocksObject {
put(key, key.length, value, value.length);
}
+ /**
+ * Store the mapping "key->value" within given column
+ * family.
+ */
+ public void put(ColumnFamilyHandle columnFamilyHandle,
+ byte[] key, byte[] value) {
+ put(key, key.length, value, value.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
/**
* Merge "value" with the existing value of "key" in the database.
* "key->merge(existing, value)"
@@ -55,6 +65,16 @@ public class WriteBatch extends RocksObject {
merge(key, key.length, value, value.length);
}
+ /**
+ * Merge "value" with the existing value of "key" in given column family.
+ * "key->merge(existing, value)"
+ */
+ public void merge(ColumnFamilyHandle columnFamilyHandle,
+ byte[] key, byte[] value) {
+ merge(key, key.length, value, value.length,
+ columnFamilyHandle.nativeHandle_);
+ }
+
/**
* If the database contains a mapping for "key", erase it. Else do nothing.
*/
@@ -62,6 +82,13 @@ public class WriteBatch extends RocksObject {
remove(key, key.length);
}
+ /**
+ * If column family contains a mapping for "key", erase it. Else do nothing.
+ */
+ public void remove(ColumnFamilyHandle columnFamilyHandle, byte[] key) {
+ remove(key, key.length, columnFamilyHandle.nativeHandle_);
+ }
+
/**
* Append a blob of arbitrary size to the records in this batch. The blob will
* be stored in the transaction log but not in any other file. In particular,
@@ -94,9 +121,17 @@ public class WriteBatch extends RocksObject {
private native void newWriteBatch(int reserved_bytes);
private native void put(byte[] key, int keyLen,
byte[] value, int valueLen);
+ private native void put(byte[] key, int keyLen,
+ byte[] value, int valueLen,
+ long cfHandle);
private native void merge(byte[] key, int keyLen,
byte[] value, int valueLen);
+ private native void merge(byte[] key, int keyLen,
+ byte[] value, int valueLen,
+ long cfHandle);
private native void remove(byte[] key, int keyLen);
+ private native void remove(byte[] key, int keyLen,
+ long cfHandle);
private native void putLogData(byte[] blob, int blobLen);
private native void disposeInternal(long handle);
}
diff --git a/java/org/rocksdb/test/BackupableDBTest.java b/java/org/rocksdb/test/BackupableDBTest.java
index 9d3a64c06..ee4509697 100644
--- a/java/org/rocksdb/test/BackupableDBTest.java
+++ b/java/org/rocksdb/test/BackupableDBTest.java
@@ -8,8 +8,8 @@ package org.rocksdb.test;
import org.rocksdb.*;
public class BackupableDBTest {
- static final String db_path = "/tmp/backupablejni_db";
- static final String backup_path = "/tmp/backupablejni_db_backup";
+ static final String db_path = "/tmp/rocksdbjni_backupable_db_test";
+ static final String backup_path = "/tmp/rocksdbjni_backupable_db_backup_test";
static {
RocksDB.loadLibrary();
}
diff --git a/java/org/rocksdb/test/ColumnFamilyTest.java b/java/org/rocksdb/test/ColumnFamilyTest.java
new file mode 100644
index 000000000..57fd2e347
--- /dev/null
+++ b/java/org/rocksdb/test/ColumnFamilyTest.java
@@ -0,0 +1,282 @@
+// Copyright (c) 2014, Facebook, Inc. All rights reserved.
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree. An additional grant
+// of patent rights can be found in the PATENTS file in the same directory.
+
+package org.rocksdb.test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import org.rocksdb.*;
+
+public class ColumnFamilyTest {
+ static final String db_path = "/tmp/rocksdbjni_columnfamily_test";
+ static {
+ RocksDB.loadLibrary();
+ }
+
+ public static void main(String[] args) {
+
+ RocksDB db = null;
+ Options options = new Options();
+ options.setCreateIfMissing(true);
+ try {
+ db = RocksDB.open(options, db_path);
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+ // Test listColumnFamilies
+ List columnFamilyNames;
+ try {
+ columnFamilyNames = RocksDB.listColumnFamilies(options, db_path);
+ if (columnFamilyNames != null && columnFamilyNames.size() > 0) {
+ assert(columnFamilyNames.size() == 1);
+ assert(new String(columnFamilyNames.get(0)).equals("default"));
+ } else {
+ assert(false);
+ }
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+
+ // Test createColumnFamily
+ try {
+ db.createColumnFamily("new_cf");
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+
+ if (db != null) {
+ db.close();
+ }
+
+ // Test listColumnFamilies after create "new_cf"
+ try {
+ columnFamilyNames = RocksDB.listColumnFamilies(options, db_path);
+ if (columnFamilyNames != null && columnFamilyNames.size() > 0) {
+ assert(columnFamilyNames.size() == 2);
+ assert(new String(columnFamilyNames.get(0)).equals("default"));
+ assert(new String(columnFamilyNames.get(1)).equals("new_cf"));
+ } else {
+ assert(false);
+ }
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+
+ // Test open database with column family names
+ List cfNames = new ArrayList();
+ List columnFamilyHandleList =
+ new ArrayList();
+ cfNames.add("default");
+ cfNames.add("new_cf");
+
+ try {
+ db = RocksDB.open(options, db_path, cfNames, columnFamilyHandleList);
+ assert(columnFamilyHandleList.size() == 2);
+ db.put("dfkey1".getBytes(), "dfvalue".getBytes());
+ db.put(columnFamilyHandleList.get(0), "dfkey2".getBytes(),
+ "dfvalue".getBytes());
+ db.put(columnFamilyHandleList.get(1), "newcfkey1".getBytes(),
+ "newcfvalue".getBytes());
+
+ String retVal = new String(db.get(columnFamilyHandleList.get(1),
+ "newcfkey1".getBytes()));
+ assert(retVal.equals("newcfvalue"));
+ assert( (db.get(columnFamilyHandleList.get(1),
+ "dfkey1".getBytes())) == null);
+ db.remove(columnFamilyHandleList.get(1), "newcfkey1".getBytes());
+ assert( (db.get(columnFamilyHandleList.get(1),
+ "newcfkey1".getBytes())) == null);
+ db.remove("dfkey2".getBytes());
+ assert( (db.get(columnFamilyHandleList.get(0),
+ "dfkey2".getBytes())) == null);
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+
+ // Test create write to and drop ColumnFamily
+ ColumnFamilyHandle tmpColumnFamilyHandle = null;
+ try {
+ tmpColumnFamilyHandle = db.createColumnFamily("tmpCF");
+ db.put(tmpColumnFamilyHandle, "key".getBytes(), "value".getBytes());
+ db.dropColumnFamily(tmpColumnFamilyHandle);
+ tmpColumnFamilyHandle.dispose();
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ // Put to disposed column family tmpColumnFamilyHandle must fail
+ try {
+ db.put(tmpColumnFamilyHandle, "key".getBytes(), "value".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+
+ // Remove to disposed column family tmpColumnFamilyHandle must fail
+ try {
+ db.remove(tmpColumnFamilyHandle, "key".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+
+ // Get on a disposed column family tmpColumnFamilyHandle must fail
+ try {
+ db.get(tmpColumnFamilyHandle, "key".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+
+ // Test WriteBatch
+ try {
+ WriteBatch writeBatch = new WriteBatch();
+ WriteOptions writeOpt = new WriteOptions();
+ writeBatch.put("key".getBytes(), "value".getBytes());
+ writeBatch.put(columnFamilyHandleList.get(1), "newcfkey".getBytes(),
+ "value".getBytes());
+ writeBatch.put(columnFamilyHandleList.get(1), "newcfkey2".getBytes(),
+ "value2".getBytes());
+ writeBatch.remove("xyz".getBytes());
+ writeBatch.remove(columnFamilyHandleList.get(1), "xyz".getBytes());
+ db.write(writeOpt, writeBatch);
+ writeBatch.dispose();
+ assert(db.get(columnFamilyHandleList.get(1),
+ "xyz".getBytes()) == null);
+ assert(new String(db.get(columnFamilyHandleList.get(1),
+ "newcfkey".getBytes())).equals("value"));
+ assert(new String(db.get(columnFamilyHandleList.get(1),
+ "newcfkey2".getBytes())).equals("value2"));
+ assert(new String(db.get("key".getBytes())).equals("value"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ assert(false);
+ }
+
+ // Test iterator on column family
+ try {
+ RocksIterator rocksIterator = db.newIterator(
+ columnFamilyHandleList.get(1));
+ rocksIterator.seekToFirst();
+ Map refMap = new HashMap();
+ refMap.put("newcfkey", "value");
+ refMap.put("newcfkey2", "value2");
+ int i = 0;
+ while(rocksIterator.isValid()) {
+ i++;
+ refMap.get(new String(rocksIterator.key())).equals(
+ new String(rocksIterator.value()));
+ rocksIterator.next();
+ }
+ assert(i == 2);
+ rocksIterator.dispose();
+ } catch(Exception e) {
+ assert(false);
+ }
+
+ // Test property handling on column families
+ try {
+ assert(db.getProperty("rocksdb.estimate-num-keys") != null);
+ assert(db.getProperty("rocksdb.stats") != null);
+ assert(db.getProperty(columnFamilyHandleList.get(0),
+ "rocksdb.sstables") != null);
+ assert(db.getProperty(columnFamilyHandleList.get(1),
+ "rocksdb.estimate-num-keys") != null);
+ assert(db.getProperty(columnFamilyHandleList.get(1),
+ "rocksdb.stats") != null);
+ assert(db.getProperty(columnFamilyHandleList.get(1),
+ "rocksdb.sstables") != null);
+ } catch(Exception e) {
+ assert(false);
+ }
+
+ // MultiGet test
+ List cfCustomList = new ArrayList();
+ try {
+ List keys = new ArrayList();
+ keys.add("key".getBytes());
+ keys.add("newcfkey".getBytes());
+ Map retValues = db.multiGet(columnFamilyHandleList,keys);
+ assert(retValues.size() == 2);
+ assert(new String(retValues.get(keys.get(0)))
+ .equals("value"));
+ assert(new String(retValues.get(keys.get(1)))
+ .equals("value"));
+
+ cfCustomList.add(columnFamilyHandleList.get(0));
+ cfCustomList.add(columnFamilyHandleList.get(0));
+ retValues = db.multiGet(cfCustomList, keys);
+ assert(retValues.size() == 1);
+ assert(new String(retValues.get(keys.get(0)))
+ .equals("value"));
+ } catch (RocksDBException e) {
+ assert(false);
+ } catch (IllegalArgumentException e) {
+ assert(false);
+ }
+
+ // Test multiget without correct number of column
+ // families
+ try {
+ List keys = new ArrayList();
+ keys.add("key".getBytes());
+ keys.add("newcfkey".getBytes());
+ cfCustomList.remove(1);
+ db.multiGet(cfCustomList, keys);
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(false);
+ } catch (IllegalArgumentException e) {
+ assert(true);
+ }
+
+ try {
+ // iterate over default key/value pairs
+ List iterators =
+ db.newIterators(columnFamilyHandleList);
+ assert(iterators.size() == 2);
+ RocksIterator iter = iterators.get(0);
+ iter.seekToFirst();
+ Map defRefMap = new HashMap();
+ defRefMap.put("dfkey1", "dfvalue");
+ defRefMap.put("key", "value");
+ while (iter.isValid()) {
+ defRefMap.get(new String(iter.key())).equals(
+ new String(iter.value()));
+ iter.next();
+ }
+ // iterate over new_cf key/value pairs
+ Map cfRefMap = new HashMap();
+ cfRefMap.put("newcfkey", "value");
+ cfRefMap.put("newcfkey2", "value2");
+ iter = iterators.get(1);
+ iter.seekToFirst();
+ while (iter.isValid()) {
+ cfRefMap.get(new String(iter.key())).equals(
+ new String(iter.value()));
+ iter.next();
+ }
+ // free iterators
+ for (RocksIterator iterator : iterators) {
+ iterator.dispose();
+ }
+ assert(true);
+ } catch (RocksDBException e) {
+ assert(false);
+ }
+
+ System.out.println("Passed ColumnFamilyTest");
+ // free cf handles before database close
+ for (ColumnFamilyHandle columnFamilyHandle : columnFamilyHandleList) {
+ columnFamilyHandle.dispose();
+ }
+ // close database
+ db.close();
+ // be sure to dispose c++ pointers
+ options.dispose();
+ }
+}
diff --git a/java/org/rocksdb/test/KeyMayExistTest.java b/java/org/rocksdb/test/KeyMayExistTest.java
new file mode 100644
index 000000000..a4ecb53da
--- /dev/null
+++ b/java/org/rocksdb/test/KeyMayExistTest.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2014, Facebook, Inc. All rights reserved.
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree. An additional grant
+// of patent rights can be found in the PATENTS file in the same directory.
+package org.rocksdb.test;
+
+import org.rocksdb.ColumnFamilyHandle;
+import org.rocksdb.Options;
+import org.rocksdb.RocksDB;
+import org.rocksdb.RocksDBException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class KeyMayExistTest {
+ static final String DB_PATH = "/tmp/rocksdbjni_keymayexit_test";
+ static {
+ RocksDB.loadLibrary();
+ }
+
+ public static void main(String[] args){
+ RocksDB db;
+ Options options = new Options();
+ options.setCreateIfMissing(true)
+ .setCreateMissingColumnFamilies(true);
+ try {
+ // open database using cf names
+ List cfNames = new ArrayList();
+ List columnFamilyHandleList =
+ new ArrayList();
+ cfNames.add("default");
+ cfNames.add("new_cf");
+ db = RocksDB.open(options, DB_PATH, cfNames, columnFamilyHandleList);
+ assert(columnFamilyHandleList.size()==2);
+
+ db.put("key".getBytes(), "value".getBytes());
+ StringBuffer retValue = new StringBuffer();
+ if (db.keyMayExist(columnFamilyHandleList.get(0), "key".getBytes(),
+ retValue)) {
+ assert(retValue.toString().equals("value"));
+ } else {
+ assert(false);
+ }
+ assert(db.keyMayExist(columnFamilyHandleList.get(1), "key".getBytes(),
+ retValue) == false);
+ System.out.println("Passed KeyMayExistTest");
+ }catch (RocksDBException e){
+ e.printStackTrace();
+ assert(false);
+ }
+ }
+}
diff --git a/java/org/rocksdb/test/OptionsTest.java b/java/org/rocksdb/test/OptionsTest.java
index 9f14b40d9..222d87b8d 100644
--- a/java/org/rocksdb/test/OptionsTest.java
+++ b/java/org/rocksdb/test/OptionsTest.java
@@ -26,6 +26,12 @@ public class OptionsTest {
assert(opt.createIfMissing() == boolValue);
}
+ { // CreateMissingColumnFamilies test
+ boolean boolValue = rand.nextBoolean();
+ opt.setCreateMissingColumnFamilies(boolValue);
+ assert(opt.createMissingColumnFamilies() == boolValue);
+ }
+
{ // ErrorIfExists test
boolean boolValue = rand.nextBoolean();
opt.setErrorIfExists(boolValue);
diff --git a/java/org/rocksdb/test/ReadOnlyTest.java b/java/org/rocksdb/test/ReadOnlyTest.java
new file mode 100644
index 000000000..87e8f1e9e
--- /dev/null
+++ b/java/org/rocksdb/test/ReadOnlyTest.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2014, Facebook, Inc. All rights reserved.
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree. An additional grant
+// of patent rights can be found in the PATENTS file in the same directory.
+package org.rocksdb.test;
+
+import org.rocksdb.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReadOnlyTest {
+ static final String DB_PATH = "/tmp/rocksdbjni_readonly_test";
+ static {
+ RocksDB.loadLibrary();
+ }
+
+ public static void main(String[] args){
+ RocksDB db = null, db2 = null, db3 = null;
+ List columnFamilyHandleList =
+ new ArrayList();
+ List db2ColumnFamilyHandleList =
+ new ArrayList();
+ List db3ColumnFamilyHandleList =
+ new ArrayList();
+ Options options = new Options();
+ options.setCreateIfMissing(true);
+ try {
+ db = RocksDB.open(options, DB_PATH);
+ db.put("key".getBytes(), "value".getBytes());
+ db2 = RocksDB.openReadOnly(DB_PATH);
+ assert("value".equals(new String(db2.get("key".getBytes()))));
+ db.close();
+ db2.close();
+
+
+ List cfNames = new ArrayList();
+ cfNames.add("default");
+
+ db = RocksDB.open(DB_PATH, cfNames, columnFamilyHandleList);
+ columnFamilyHandleList.add(db.createColumnFamily("new_cf"));
+ columnFamilyHandleList.add(db.createColumnFamily("new_cf2"));
+ db.put(columnFamilyHandleList.get(2), "key2".getBytes(),
+ "value2".getBytes());
+
+ db2 = RocksDB.openReadOnly(DB_PATH, cfNames, db2ColumnFamilyHandleList);
+ assert(db2.get("key2".getBytes())==null);
+ assert(db2.get(columnFamilyHandleList.get(0), "key2".getBytes())==null);
+
+ List cfNewName = new ArrayList();
+ cfNewName.add("default");
+ cfNewName.add("new_cf2");
+ db3 = RocksDB.openReadOnly(DB_PATH, cfNewName, db3ColumnFamilyHandleList);
+ assert(new String(db3.get(db3ColumnFamilyHandleList.get(1),
+ "key2".getBytes())).equals("value2"));
+ }catch (RocksDBException e){
+ e.printStackTrace();
+ assert(false);
+ }
+ // test that put fails in readonly mode
+ try {
+ db2.put("key".getBytes(), "value".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ try {
+ db3.put(db3ColumnFamilyHandleList.get(1),
+ "key".getBytes(), "value".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ // test that remove fails in readonly mode
+ try {
+ db2.remove("key".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ try {
+ db3.remove(db3ColumnFamilyHandleList.get(1),
+ "key".getBytes());
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ // test that write fails in readonly mode
+ WriteBatch wb = new WriteBatch();
+ wb.put("key".getBytes(), "value".getBytes());
+ try {
+ db2.write(new WriteOptions(), wb);
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ wb.dispose();
+ wb = new WriteBatch();
+ wb.put(db3ColumnFamilyHandleList.get(1),
+ "key".getBytes(), "value".getBytes());
+ try {
+ db3.write(new WriteOptions(), wb);
+ assert(false);
+ } catch (RocksDBException e) {
+ assert(true);
+ }
+ wb.dispose();
+ // cleanup c++ pointers
+ for (ColumnFamilyHandle columnFamilyHandle :
+ columnFamilyHandleList) {
+ columnFamilyHandle.dispose();
+ }
+ db.close();
+ for (ColumnFamilyHandle columnFamilyHandle :
+ db2ColumnFamilyHandleList) {
+ columnFamilyHandle.dispose();
+ }
+ db2.close();
+ for (ColumnFamilyHandle columnFamilyHandle :
+ db3ColumnFamilyHandleList) {
+ columnFamilyHandle.dispose();
+ }
+ db3.close();
+ System.out.println("Passed ReadOnlyTest");
+ }
+}
diff --git a/java/org/rocksdb/test/StatisticsCollectorTest.java b/java/org/rocksdb/test/StatisticsCollectorTest.java
index edbf693e4..5298aa46a 100644
--- a/java/org/rocksdb/test/StatisticsCollectorTest.java
+++ b/java/org/rocksdb/test/StatisticsCollectorTest.java
@@ -9,7 +9,7 @@ import java.util.Collections;
import org.rocksdb.*;
public class StatisticsCollectorTest {
- static final String db_path = "/tmp/backupablejni_db";
+ static final String db_path = "/tmp/rocksdbjni_statistics_collector_test";
static {
RocksDB.loadLibrary();
}
@@ -19,7 +19,7 @@ public class StatisticsCollectorTest {
Options opt = new Options().createStatistics().setCreateIfMissing(true);
Statistics stats = opt.statisticsPtr();
- RocksDB db = RocksDB.open(db_path);
+ RocksDB db = RocksDB.open(opt, db_path);
StatsCallbackMock callback = new StatsCallbackMock();
StatsCollectorInput statsInput = new StatsCollectorInput(stats, callback);
diff --git a/java/rocksjni/columnfamilyhandle.cc b/java/rocksjni/columnfamilyhandle.cc
new file mode 100644
index 000000000..be3b4c82f
--- /dev/null
+++ b/java/rocksjni/columnfamilyhandle.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2014, Facebook, Inc. All rights reserved.
+// This source code is licensed under the BSD-style license found in the
+// LICENSE file in the root directory of this source tree. An additional grant
+// of patent rights can be found in the PATENTS file in the same directory.
+//
+// This file implements the "bridge" between Java and C++ and enables
+// calling c++ rocksdb::Iterator methods from Java side.
+
+#include
+#include
+#include
+
+#include "include/org_rocksdb_ColumnFamilyHandle.h"
+#include "rocksjni/portal.h"
+
+/*
+ * Class: org_rocksdb_ColumnFamilyHandle
+ * Method: disposeInternal
+ * Signature: (J)V
+ */
+void Java_org_rocksdb_ColumnFamilyHandle_disposeInternal(
+ JNIEnv* env, jobject jobj, jlong handle) {
+ auto it = reinterpret_cast(handle);
+ delete it;
+}
diff --git a/java/rocksjni/options.cc b/java/rocksjni/options.cc
index 8d3cb37e0..ef104d92b 100644
--- a/java/rocksjni/options.cc
+++ b/java/rocksjni/options.cc
@@ -8,7 +8,7 @@
#include
#include
#include
-#include
+#include
#include
#include "include/org_rocksdb_Options.h"
@@ -64,6 +64,28 @@ jboolean Java_org_rocksdb_Options_createIfMissing(
return reinterpret_cast(jhandle)->create_if_missing;
}
+/*
+ * Class: org_rocksdb_Options
+ * Method: setCreateMissingColumnFamilies
+ * Signature: (JZ)V
+ */
+void Java_org_rocksdb_Options_setCreateMissingColumnFamilies(
+ JNIEnv* env, jobject jobj, jlong jhandle, jboolean flag) {
+ reinterpret_cast
+ (jhandle)->create_missing_column_families = flag;
+}
+
+/*
+ * Class: org_rocksdb_Options
+ * Method: createMissingColumnFamilies
+ * Signature: (J)Z
+ */
+jboolean Java_org_rocksdb_Options_createMissingColumnFamilies(
+ JNIEnv* env, jobject jobj, jlong jhandle) {
+ return reinterpret_cast
+ (jhandle)->create_missing_column_families;
+}
+
/*
* Class: org_rocksdb_Options
* Method: useReverseBytewiseComparator
diff --git a/java/rocksjni/portal.h b/java/rocksjni/portal.h
index 374d20b0b..14b2cb98a 100644
--- a/java/rocksjni/portal.h
+++ b/java/rocksjni/portal.h
@@ -327,6 +327,39 @@ class FilterJni {
}
};
+class ColumnFamilyHandleJni {
+ public:
+ // Get the java class id of org.rocksdb.ColumnFamilyHandle.
+ static jclass getJClass(JNIEnv* env) {
+ jclass jclazz = env->FindClass("org/rocksdb/ColumnFamilyHandle");
+ assert(jclazz != nullptr);
+ return jclazz;
+ }
+
+ // Get the field id of the member variable of org.rocksdb.ColumnFamilyHandle.
+ // that stores the pointer to rocksdb::ColumnFamilyHandle.
+ static jfieldID getHandleFieldID(JNIEnv* env) {
+ static jfieldID fid = env->GetFieldID(
+ getJClass(env), "nativeHandle_", "J");
+ assert(fid != nullptr);
+ return fid;
+ }
+
+ // Get the pointer to rocksdb::ColumnFamilyHandle.
+ static rocksdb::ColumnFamilyHandle* getHandle(JNIEnv* env, jobject jobj) {
+ return reinterpret_cast(
+ env->GetLongField(jobj, getHandleFieldID(env)));
+ }
+
+ // Pass the rocksdb::ColumnFamilyHandle pointer to the java side.
+ static void setHandle(
+ JNIEnv* env, jobject jobj, const rocksdb::ColumnFamilyHandle* op) {
+ env->SetLongField(
+ jobj, getHandleFieldID(env),
+ reinterpret_cast(op));
+ }
+};
+
class ListJni {
public:
// Get the java class id of java.util.List.
diff --git a/java/rocksjni/rocksjni.cc b/java/rocksjni/rocksjni.cc
index bb3f1a845..fa9a66a7d 100644
--- a/java/rocksjni/rocksjni.cc
+++ b/java/rocksjni/rocksjni.cc
@@ -25,7 +25,7 @@
* Method: open
* Signature: (JLjava/lang/String;)V
*/
-void Java_org_rocksdb_RocksDB_open(
+void Java_org_rocksdb_RocksDB_open__JLjava_lang_String_2(
JNIEnv* env, jobject jdb, jlong jopt_handle, jstring jdb_path) {
auto opt = reinterpret_cast(jopt_handle);
rocksdb::DB* db = nullptr;
@@ -40,12 +40,215 @@ void Java_org_rocksdb_RocksDB_open(
rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: openROnly
+ * Signature: (JLjava/lang/String;)V
+ */
+void Java_org_rocksdb_RocksDB_openROnly__JLjava_lang_String_2(
+ JNIEnv* env, jobject jdb, jlong jopt_handle, jstring jdb_path) {
+ auto opt = reinterpret_cast(jopt_handle);
+ rocksdb::DB* db = nullptr;
+ const char* db_path = env->GetStringUTFChars(jdb_path, 0);
+ rocksdb::Status s = rocksdb::DB::OpenForReadOnly(*opt,
+ db_path, &db);
+ env->ReleaseStringUTFChars(jdb_path, db_path);
+
+ if (s.ok()) {
+ rocksdb::RocksDBJni::setHandle(env, jdb, db);
+ return;
+ }
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: openROnly
+ * Signature: (JLjava/lang/String;Ljava/util/List;I)Ljava/util/List;
+ */
+jobject
+ Java_org_rocksdb_RocksDB_openROnly__JLjava_lang_String_2Ljava_util_List_2I(
+ JNIEnv* env, jobject jdb, jlong jopt_handle, jstring jdb_path,
+ jobject jcfname_list, jint jcfname_count) {
+ auto opt = reinterpret_cast(jopt_handle);
+ rocksdb::DB* db = nullptr;
+ const char* db_path = env->GetStringUTFChars(jdb_path, 0);
+
+ std::vector cfnames_to_free;
+ std::vector jcfnames_for_free;
+
+ std::vector column_families;
+ std::vector handles;
+ // get iterator for cfnames
+ jobject iteratorObj = env->CallObjectMethod(
+ jcfname_list, rocksdb::ListJni::getIteratorMethod(env));
+
+ // iterate over cfnames and convert cfnames to
+ // ColumnFamilyDescriptor instances
+ while (env->CallBooleanMethod(
+ iteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) {
+ jstring jstr = (jstring) env->CallObjectMethod(iteratorObj,
+ rocksdb::ListJni::getNextMethod(env));
+ const char* cfname = env->GetStringUTFChars(jstr, 0);
+
+ // free allocated cfnames after call to open
+ cfnames_to_free.push_back(cfname);
+ jcfnames_for_free.push_back(jstr);
+ column_families.push_back(rocksdb::ColumnFamilyDescriptor(cfname,
+ rocksdb::ColumnFamilyOptions()));
+ }
+
+ rocksdb::Status s = rocksdb::DB::OpenForReadOnly(*opt,
+ db_path, column_families, &handles, &db);
+ env->ReleaseStringUTFChars(jdb_path, db_path);
+ // free jbyte allocations
+ for (std::vector::size_type i = 0;
+ i != cfnames_to_free.size(); i++) {
+ // free cfnames
+ env->ReleaseStringUTFChars(jcfnames_for_free[i], cfnames_to_free[i]);
+ }
+
+ jobject jcfhandle_list = nullptr;
+ // check if open operation was successful
+ if (s.ok()) {
+ rocksdb::RocksDBJni::setHandle(env, jdb, db);
+ jclass jclazz = env->FindClass("java/util/ArrayList");
+ jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(
+ env, jclazz);
+ jobject jcfhandle_list = env->NewObject(jclazz, mid, handles.size());
+ // insert in java list
+ for (std::vector::size_type i = 0;
+ i != handles.size(); i++) {
+ // jlong must be converted to Long due to collections restrictions
+ jclass jclazz = env->FindClass("java/lang/Long");
+ jmethodID mid = env->GetMethodID(jclazz, "", "(J)V");
+ jobject obj = env->NewObject(jclazz, mid,
+ reinterpret_cast(handles[i]));
+ env->CallBooleanMethod(jcfhandle_list,
+ rocksdb::ListJni::getListAddMethodId(env), obj);
+ }
+
+ return jcfhandle_list;
+ }
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ return jcfhandle_list;
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: open
+ * Signature: (JLjava/lang/String;Ljava/util/List;I)Ljava/util/List;
+ */
+jobject Java_org_rocksdb_RocksDB_open__JLjava_lang_String_2Ljava_util_List_2I(
+ JNIEnv* env, jobject jdb, jlong jopt_handle, jstring jdb_path,
+ jobject jcfname_list, jint jcfname_count) {
+ auto opt = reinterpret_cast(jopt_handle);
+ rocksdb::DB* db = nullptr;
+ const char* db_path = env->GetStringUTFChars(jdb_path, 0);
+
+ std::vector cfnames_to_free;
+ std::vector jcfnames_for_free;
+
+ std::vector column_families;
+ std::vector handles;
+ // get iterator for cfnames
+ jobject iteratorObj = env->CallObjectMethod(
+ jcfname_list, rocksdb::ListJni::getIteratorMethod(env));
+
+ // iterate over cfnames and convert cfnames to
+ // ColumnFamilyDescriptor instances
+ while (env->CallBooleanMethod(
+ iteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) {
+ jstring jstr = (jstring) env->CallObjectMethod(iteratorObj,
+ rocksdb::ListJni::getNextMethod(env));
+ const char* cfname = env->GetStringUTFChars(jstr, 0);
+
+ // free allocated cfnames after call to open
+ cfnames_to_free.push_back(cfname);
+ jcfnames_for_free.push_back(jstr);
+ column_families.push_back(rocksdb::ColumnFamilyDescriptor(cfname,
+ rocksdb::ColumnFamilyOptions()));
+ }
+
+ rocksdb::Status s = rocksdb::DB::Open(*opt, db_path, column_families,
+ &handles, &db);
+ env->ReleaseStringUTFChars(jdb_path, db_path);
+ // free jbyte allocations
+ for (std::vector::size_type i = 0;
+ i != cfnames_to_free.size(); i++) {
+ // free cfnames
+ env->ReleaseStringUTFChars(jcfnames_for_free[i], cfnames_to_free[i]);
+ }
+
+ jobject jcfhandle_list = nullptr;
+ // check if open operation was successful
+ if (s.ok()) {
+ rocksdb::RocksDBJni::setHandle(env, jdb, db);
+ jclass jclazz = env->FindClass("java/util/ArrayList");
+ jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(
+ env, jclazz);
+ jobject jcfhandle_list = env->NewObject(jclazz, mid, handles.size());
+ // insert in java list
+ for (std::vector::size_type i = 0;
+ i != handles.size(); i++) {
+ // jlong must be converted to Long due to collections restrictions
+ jclass jclazz = env->FindClass("java/lang/Long");
+ jmethodID mid = env->GetMethodID(jclazz, "", "(J)V");
+ jobject obj = env->NewObject(jclazz, mid,
+ reinterpret_cast(handles[i]));
+ env->CallBooleanMethod(jcfhandle_list,
+ rocksdb::ListJni::getListAddMethodId(env), obj);
+ }
+
+ return jcfhandle_list;
+ }
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ return jcfhandle_list;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// rocksdb::DB::ListColumnFamilies
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: listColumnFamilies
+ * Signature: (JLjava/lang/String;)Ljava/util/List;
+ */
+jobject Java_org_rocksdb_RocksDB_listColumnFamilies(
+ JNIEnv* env, jclass jclazz, jlong jopt_handle, jstring jdb_path) {
+ std::vector column_family_names;
+ auto opt = reinterpret_cast(jopt_handle);
+ const char* db_path = env->GetStringUTFChars(jdb_path, 0);
+ jobject jvalue_list = nullptr;
+
+ rocksdb::Status s = rocksdb::DB::ListColumnFamilies(*opt, db_path,
+ &column_family_names);
+ env->ReleaseStringUTFChars(jdb_path, db_path);
+ if (s.ok()) {
+ // Don't reuse class pointer
+ jclass jclazz = env->FindClass("java/util/ArrayList");
+ jmethodID mid = rocksdb::ListJni::getArrayListConstructorMethodId(env,
+ jclazz);
+ jvalue_list = env->NewObject(jclazz, mid, column_family_names.size());
+
+ for (std::vector::size_type i = 0;
+ i < column_family_names.size(); i++) {
+ jbyteArray jvalue = env->NewByteArray(column_family_names[i].size());
+ env->SetByteArrayRegion(jvalue, 0, column_family_names[i].size(),
+ reinterpret_cast(column_family_names[i].c_str()));
+ env->CallBooleanMethod(jvalue_list,
+ rocksdb::ListJni::getListAddMethodId(env), jvalue);
+ }
+ }
+ return jvalue_list;
+}
+
//////////////////////////////////////////////////////////////////////////////
// rocksdb::DB::Put
void rocksdb_put_helper(
JNIEnv* env, rocksdb::DB* db, const rocksdb::WriteOptions& write_options,
- jbyteArray jkey, jint jkey_len,
+ rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len,
jbyteArray jvalue, jint jvalue_len) {
jbyte* key = env->GetByteArrayElements(jkey, 0);
@@ -53,7 +256,13 @@ void rocksdb_put_helper(
rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
rocksdb::Slice value_slice(reinterpret_cast(value), jvalue_len);
- rocksdb::Status s = db->Put(write_options, key_slice, value_slice);
+ rocksdb::Status s;
+ if (cf_handle != nullptr) {
+ s = db->Put(write_options, cf_handle, key_slice, value_slice);
+ } else {
+ // backwards compatibility
+ s = db->Put(write_options, key_slice, value_slice);
+ }
// trigger java unref on key and value.
// by passing JNI_ABORT, it will simply release the reference without
@@ -80,10 +289,31 @@ void Java_org_rocksdb_RocksDB_put__J_3BI_3BI(
static const rocksdb::WriteOptions default_write_options =
rocksdb::WriteOptions();
- rocksdb_put_helper(env, db, default_write_options,
+ rocksdb_put_helper(env, db, default_write_options, nullptr,
jkey, jkey_len,
jvalue, jvalue_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: put
+ * Signature: (J[BI[BIJ)V
+ */
+void Java_org_rocksdb_RocksDB_put__J_3BI_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto db = reinterpret_cast(jdb_handle);
+ static const rocksdb::WriteOptions default_write_options =
+ rocksdb::WriteOptions();
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ rocksdb_put_helper(env, db, default_write_options, cf_handle,
+ jkey, jkey_len, jvalue, jvalue_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+}
/*
* Class: org_rocksdb_RocksDB
@@ -99,11 +329,34 @@ void Java_org_rocksdb_RocksDB_put__JJ_3BI_3BI(
auto write_options = reinterpret_cast(
jwrite_options_handle);
- rocksdb_put_helper(env, db, *write_options,
+ rocksdb_put_helper(env, db, *write_options, nullptr,
jkey, jkey_len,
jvalue, jvalue_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: put
+ * Signature: (JJ[BI[BIJ)V
+ */
+void Java_org_rocksdb_RocksDB_put__JJ_3BI_3BIJ(
+ JNIEnv* env, jobject jdb,
+ jlong jdb_handle, jlong jwrite_options_handle,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto db = reinterpret_cast(jdb_handle);
+ auto write_options = reinterpret_cast(
+ jwrite_options_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ rocksdb_put_helper(env, db, *write_options, cf_handle,
+ jkey, jkey_len, jvalue, jvalue_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+}
+
//////////////////////////////////////////////////////////////////////////////
// rocksdb::DB::Write
/*
@@ -126,20 +379,94 @@ void Java_org_rocksdb_RocksDB_write(
}
}
+//////////////////////////////////////////////////////////////////////////////
+// rocksdb::DB::KeyMayExist
+jboolean key_may_exist_helper(JNIEnv* env, rocksdb::DB* db,
+ const rocksdb::ReadOptions& read_opt,
+ rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len,
+ jobject jvalue) {
+ std::string value;
+ bool value_found = false;
+ jboolean isCopy;
+ jbyte* key = env->GetByteArrayElements(jkey, &isCopy);
+ rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
+ bool keyMaxExist = db->KeyMayExist(read_opt, cf_handle, key_slice,
+ &value, &value_found);
+ if (value_found && !value.empty()) {
+ jclass clazz = env->GetObjectClass(jvalue);
+ jmethodID mid = env->GetMethodID(clazz, "append",
+ "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+ jstring new_value_str = env->NewStringUTF(value.c_str());
+ env->CallObjectMethod(jvalue, mid, new_value_str);
+ }
+ env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+ return static_cast(keyMaxExist);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: keyMayExist
+ * Signature: ([BIJLjava/lang/StringBuffer;)Z
+ */
+jboolean Java_org_rocksdb_RocksDB_keyMayExist___3BIJLjava_lang_StringBuffer_2(
+ JNIEnv* env, jobject jdb, jbyteArray jkey, jint jkey_len,
+ jlong jcf_handle, jobject jvalue) {
+ rocksdb::DB* db = rocksdb::RocksDBJni::getHandle(env, jdb);
+ auto cf_handle = reinterpret_cast(
+ jcf_handle);
+ if (cf_handle != nullptr) {
+ return key_may_exist_helper(env, db, rocksdb::ReadOptions(),
+ cf_handle, jkey, jkey_len, jvalue);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+ return true;
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: keyMayExist
+ * Signature: (J[BIJLjava/lang/StringBuffer;)Z
+ */
+jboolean Java_org_rocksdb_RocksDB_keyMayExist__J_3BIJLjava_lang_StringBuffer_2(
+ JNIEnv* env, jobject jdb, jlong jread_options_handle,
+ jbyteArray jkey, jint jkey_len, jlong jcf_handle, jobject jvalue) {
+ rocksdb::DB* db = rocksdb::RocksDBJni::getHandle(env, jdb);
+ auto& read_options = *reinterpret_cast(
+ jread_options_handle);
+ auto cf_handle = reinterpret_cast(
+ jcf_handle);
+ if (cf_handle != nullptr) {
+ return key_may_exist_helper(env, db, read_options, cf_handle,
+ jkey, jkey_len, jvalue);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+ return true;
+}
+
//////////////////////////////////////////////////////////////////////////////
// rocksdb::DB::Get
jbyteArray rocksdb_get_helper(
JNIEnv* env, rocksdb::DB* db, const rocksdb::ReadOptions& read_opt,
- jbyteArray jkey, jint jkey_len) {
+ rocksdb::ColumnFamilyHandle* column_family_handle, jbyteArray jkey,
+ jint jkey_len) {
jboolean isCopy;
jbyte* key = env->GetByteArrayElements(jkey, &isCopy);
rocksdb::Slice key_slice(
reinterpret_cast(key), jkey_len);
std::string value;
- rocksdb::Status s = db->Get(
- read_opt, key_slice, &value);
+ rocksdb::Status s;
+ if (column_family_handle != nullptr) {
+ s = db->Get(read_opt, column_family_handle, key_slice, &value);
+ } else {
+ // backwards compatibility
+ s = db->Get(read_opt, key_slice, &value);
+ }
// trigger java unref on key.
// by passing JNI_ABORT, it will simply release the reference without
@@ -172,10 +499,31 @@ jbyteArray Java_org_rocksdb_RocksDB_get__J_3BI(
jbyteArray jkey, jint jkey_len) {
return rocksdb_get_helper(env,
reinterpret_cast(jdb_handle),
- rocksdb::ReadOptions(),
+ rocksdb::ReadOptions(), nullptr,
jkey, jkey_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: get
+ * Signature: (J[BIJ)[B
+ */
+jbyteArray Java_org_rocksdb_RocksDB_get__J_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+ auto db_handle = reinterpret_cast(jdb_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ return rocksdb_get_helper(env, db_handle, rocksdb::ReadOptions(),
+ cf_handle, jkey, jkey_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ // will never be evaluated
+ return env->NewByteArray(0);
+ }
+}
+
/*
* Class: org_rocksdb_RocksDB
* Method: get
@@ -186,14 +534,36 @@ jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BI(
jbyteArray jkey, jint jkey_len) {
return rocksdb_get_helper(env,
reinterpret_cast(jdb_handle),
- *reinterpret_cast(jropt_handle),
+ *reinterpret_cast(jropt_handle), nullptr,
jkey, jkey_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: get
+ * Signature: (JJ[BIJ)[B
+ */
+jbyteArray Java_org_rocksdb_RocksDB_get__JJ_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
+ jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+ auto db_handle = reinterpret_cast(jdb_handle);
+ auto& ro_opt = *reinterpret_cast(jropt_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ return rocksdb_get_helper(env, db_handle, ro_opt, cf_handle,
+ jkey, jkey_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ // will never be evaluated
+ return env->NewByteArray(0);
+ }
+}
+
jint rocksdb_get_helper(
JNIEnv* env, rocksdb::DB* db, const rocksdb::ReadOptions& read_options,
- jbyteArray jkey, jint jkey_len,
- jbyteArray jvalue, jint jvalue_len) {
+ rocksdb::ColumnFamilyHandle* column_family_handle, jbyteArray jkey,
+ jint jkey_len, jbyteArray jvalue, jint jvalue_len) {
static const int kNotFound = -1;
static const int kStatusError = -2;
@@ -204,8 +574,13 @@ jint rocksdb_get_helper(
// TODO(yhchiang): we might save one memory allocation here by adding
// a DB::Get() function which takes preallocated jbyte* as input.
std::string cvalue;
- rocksdb::Status s = db->Get(
- read_options, key_slice, &cvalue);
+ rocksdb::Status s;
+ if (column_family_handle != nullptr) {
+ s = db->Get(read_options, column_family_handle, key_slice, &cvalue);
+ } else {
+ // backwards compatibility
+ s = db->Get(read_options, key_slice, &cvalue);
+ }
// trigger java unref on key.
// by passing JNI_ABORT, it will simply release the reference without
@@ -236,11 +611,31 @@ jint rocksdb_get_helper(
return cvalue_len;
}
+// cf multi get
jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
- const rocksdb::ReadOptions& rOpt, jobject jkey_list, jint jkeys_count) {
+ const rocksdb::ReadOptions& rOpt, jobject jkey_list, jint jkeys_count,
+ jobject jcfhandle_list) {
std::vector keys;
std::vector keys_to_free;
+ std::vector cf_handles;
+ if (jcfhandle_list != nullptr) {
+ // get cf iterator
+ jobject cfIteratorObj = env->CallObjectMethod(
+ jcfhandle_list, rocksdb::ListJni::getIteratorMethod(env));
+
+ // iterate over keys and convert java byte array to slice
+ while (env->CallBooleanMethod(
+ cfIteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) {
+ jobject jobj = (jbyteArray) env->CallObjectMethod(
+ cfIteratorObj, rocksdb::ListJni::getNextMethod(env));
+ rocksdb::ColumnFamilyHandle* cfHandle =
+ rocksdb::ColumnFamilyHandleJni::getHandle(env, jobj);
+ cf_handles.push_back(cfHandle);
+ }
+ }
+
+ // Process key list
// get iterator
jobject iteratorObj = env->CallObjectMethod(
jkey_list, rocksdb::ListJni::getIteratorMethod(env));
@@ -263,7 +658,12 @@ jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
}
std::vector values;
- std::vector s = db->MultiGet(rOpt, keys, &values);
+ std::vector s;
+ if (cf_handles.size() == 0) {
+ s = db->MultiGet(rOpt, keys, &values);
+ } else {
+ s = db->MultiGet(rOpt, cf_handles, keys, &values);
+ }
// Don't reuse class pointer
jclass jclazz = env->FindClass("java/util/ArrayList");
@@ -285,13 +685,11 @@ jobject multi_get_helper(JNIEnv* env, jobject jdb, rocksdb::DB* db,
jvalue_list, rocksdb::ListJni::getListAddMethodId(env), nullptr);
}
}
-
// free up allocated byte arrays
for (std::vector::size_type i = 0; i != keys_to_free.size(); i++) {
delete[] keys_to_free[i];
}
keys_to_free.clear();
-
return jvalue_list;
}
@@ -304,7 +702,20 @@ jobject Java_org_rocksdb_RocksDB_multiGet__JLjava_util_List_2I(
JNIEnv* env, jobject jdb, jlong jdb_handle,
jobject jkey_list, jint jkeys_count) {
return multi_get_helper(env, jdb, reinterpret_cast(jdb_handle),
- rocksdb::ReadOptions(), jkey_list, jkeys_count);
+ rocksdb::ReadOptions(), jkey_list, jkeys_count, nullptr);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: multiGet
+ * Signature: (JLjava/util/List;ILjava/util/List;)Ljava/util/List;
+ */
+jobject
+ Java_org_rocksdb_RocksDB_multiGet__JLjava_util_List_2ILjava_util_List_2(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jobject jkey_list, jint jkeys_count, jobject jcfhandle_list) {
+ return multi_get_helper(env, jdb, reinterpret_cast(jdb_handle),
+ rocksdb::ReadOptions(), jkey_list, jkeys_count, jcfhandle_list);
}
/*
@@ -317,7 +728,22 @@ jobject Java_org_rocksdb_RocksDB_multiGet__JJLjava_util_List_2I(
jlong jropt_handle, jobject jkey_list, jint jkeys_count) {
return multi_get_helper(env, jdb, reinterpret_cast(jdb_handle),
*reinterpret_cast(jropt_handle), jkey_list,
- jkeys_count);
+ jkeys_count, nullptr);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: multiGet
+ * Signature: (JJLjava/util/List;ILjava/util/List;)Ljava/util/List;
+ */
+jobject
+ Java_org_rocksdb_RocksDB_multiGet__JJLjava_util_List_2ILjava_util_List_2(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jlong jropt_handle, jobject jkey_list, jint jkeys_count,
+ jobject jcfhandle_list) {
+ return multi_get_helper(env, jdb, reinterpret_cast(jdb_handle),
+ *reinterpret_cast(jropt_handle), jkey_list,
+ jkeys_count, jcfhandle_list);
}
/*
@@ -331,10 +757,32 @@ jint Java_org_rocksdb_RocksDB_get__J_3BI_3BI(
jbyteArray jvalue, jint jvalue_len) {
return rocksdb_get_helper(env,
reinterpret_cast(jdb_handle),
- rocksdb::ReadOptions(),
+ rocksdb::ReadOptions(), nullptr,
jkey, jkey_len, jvalue, jvalue_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: get
+ * Signature: (J[BI[BIJ)I
+ */
+jint Java_org_rocksdb_RocksDB_get__J_3BI_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto db_handle = reinterpret_cast(jdb_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ return rocksdb_get_helper(env, db_handle, rocksdb::ReadOptions(), cf_handle,
+ jkey, jkey_len, jvalue, jvalue_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ // will never be evaluated
+ return 0;
+ }
+}
+
/*
* Class: org_rocksdb_RocksDB
* Method: get
@@ -347,19 +795,46 @@ jint Java_org_rocksdb_RocksDB_get__JJ_3BI_3BI(
return rocksdb_get_helper(env,
reinterpret_cast(jdb_handle),
*reinterpret_cast(jropt_handle),
- jkey, jkey_len, jvalue, jvalue_len);
+ nullptr, jkey, jkey_len, jvalue, jvalue_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: get
+ * Signature: (JJ[BI[BIJ)I
+ */
+jint Java_org_rocksdb_RocksDB_get__JJ_3BI_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jropt_handle,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto db_handle = reinterpret_cast(jdb_handle);
+ auto& ro_opt = *reinterpret_cast(jropt_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ return rocksdb_get_helper(env, db_handle, ro_opt, cf_handle, jkey,
+ jkey_len, jvalue, jvalue_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ // will never be evaluated
+ return 0;
+ }
+}
//////////////////////////////////////////////////////////////////////////////
// rocksdb::DB::Delete()
void rocksdb_remove_helper(
JNIEnv* env, rocksdb::DB* db, const rocksdb::WriteOptions& write_options,
- jbyteArray jkey, jint jkey_len) {
+ rocksdb::ColumnFamilyHandle* cf_handle, jbyteArray jkey, jint jkey_len) {
jbyte* key = env->GetByteArrayElements(jkey, 0);
rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
- rocksdb::Status s = db->Delete(write_options, key_slice);
-
+ rocksdb::Status s;
+ if (cf_handle != nullptr) {
+ s = db->Delete(write_options, cf_handle, key_slice);
+ } else {
+ // backwards compatibility
+ s = db->Delete(write_options, key_slice);
+ }
// trigger java unref on key and value.
// by passing JNI_ABORT, it will simply release the reference without
// copying the result back to the java byte array.
@@ -382,24 +857,63 @@ void Java_org_rocksdb_RocksDB_remove__J_3BI(
auto db = reinterpret_cast(jdb_handle);
static const rocksdb::WriteOptions default_write_options =
rocksdb::WriteOptions();
-
- rocksdb_remove_helper(env, db, default_write_options, jkey, jkey_len);
+ rocksdb_remove_helper(env, db, default_write_options, nullptr,
+ jkey, jkey_len);
}
/*
* Class: org_rocksdb_RocksDB
* Method: remove
- * Signature: (JJ[BI)V
+ * Signature: (J[BIJ)V
+ */
+void Java_org_rocksdb_RocksDB_remove__J_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+ auto db = reinterpret_cast(jdb_handle);
+ static const rocksdb::WriteOptions default_write_options =
+ rocksdb::WriteOptions();
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ rocksdb_remove_helper(env, db, default_write_options, cf_handle,
+ jkey, jkey_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: remove
+ * Signature: (JJ[BIJ)V
*/
void Java_org_rocksdb_RocksDB_remove__JJ_3BI(
JNIEnv* env, jobject jdb, jlong jdb_handle,
jlong jwrite_options, jbyteArray jkey, jint jkey_len) {
auto db = reinterpret_cast(jdb_handle);
auto write_options = reinterpret_cast(jwrite_options);
-
- rocksdb_remove_helper(env, db, *write_options, jkey, jkey_len);
+ rocksdb_remove_helper(env, db, *write_options, nullptr, jkey, jkey_len);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: remove
+ * Signature: (JJ[BIJ)V
+ */
+void Java_org_rocksdb_RocksDB_remove__JJ_3BIJ(
+ JNIEnv* env, jobject jdb, jlong jdb_handle,
+ jlong jwrite_options, jbyteArray jkey, jint jkey_len,
+ jlong jcf_handle) {
+ auto db = reinterpret_cast(jdb_handle);
+ auto write_options = reinterpret_cast(jwrite_options);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ if (cf_handle != nullptr) {
+ rocksdb_remove_helper(env, db, *write_options, cf_handle, jkey, jkey_len);
+ } else {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env,
+ rocksdb::Status::InvalidArgument("Invalid ColumnFamilyHandle."));
+ }
+}
//////////////////////////////////////////////////////////////////////////////
// rocksdb::DB::~DB()
@@ -418,19 +932,111 @@ void Java_org_rocksdb_RocksDB_disposeInternal(
* Method: iterator0
* Signature: (J)J
*/
-jlong Java_org_rocksdb_RocksDB_iterator0(
+jlong Java_org_rocksdb_RocksDB_iterator0__J(
JNIEnv* env, jobject jdb, jlong db_handle) {
auto db = reinterpret_cast(db_handle);
rocksdb::Iterator* iterator = db->NewIterator(rocksdb::ReadOptions());
return reinterpret_cast(iterator);
}
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: iterator0
+ * Signature: (JJ)J
+ */
+jlong Java_org_rocksdb_RocksDB_iterator0__JJ(
+ JNIEnv* env, jobject jdb, jlong db_handle, jlong jcf_handle) {
+ auto db = reinterpret_cast(db_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ rocksdb::Iterator* iterator = db->NewIterator(rocksdb::ReadOptions(),
+ cf_handle);
+ return reinterpret_cast(iterator);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: iterators
+ * Signature: (JLjava/util/List;)[J
+ */
+jlongArray Java_org_rocksdb_RocksDB_iterators(
+ JNIEnv* env, jobject jdb, jlong db_handle, jobject jcfhandle_list) {
+ auto db = reinterpret_cast(db_handle);
+ std::vector cf_handles;
+ std::vector iterators;
+
+ if (jcfhandle_list != nullptr) {
+ // get cf iterator
+ jobject cfIteratorObj = env->CallObjectMethod(
+ jcfhandle_list, rocksdb::ListJni::getIteratorMethod(env));
+
+ // iterate over keys and convert java byte array to slice
+ while (env->CallBooleanMethod(
+ cfIteratorObj, rocksdb::ListJni::getHasNextMethod(env)) == JNI_TRUE) {
+ jobject jobj = (jbyteArray) env->CallObjectMethod(
+ cfIteratorObj, rocksdb::ListJni::getNextMethod(env));
+ rocksdb::ColumnFamilyHandle* cfHandle =
+ rocksdb::ColumnFamilyHandleJni::getHandle(env, jobj);
+ cf_handles.push_back(cfHandle);
+ }
+ }
+
+ rocksdb::Status s = db->NewIterators(rocksdb::ReadOptions(),
+ cf_handles, &iterators);
+ if (s.ok()) {
+ jlongArray jLongArray = env->NewLongArray(iterators.size());
+ for (std::vector::size_type i = 0;
+ i < iterators.size(); i++) {
+ env->SetLongArrayRegion(jLongArray, i, 1,
+ reinterpret_cast(&iterators[i]));
+ }
+ return jLongArray;
+ }
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ return env->NewLongArray(0);
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: createColumnFamily
+ * Signature: (JLjava/lang/String;)J;
+ */
+jlong Java_org_rocksdb_RocksDB_createColumnFamily(
+ JNIEnv* env, jobject jdb, jlong jdb_handle, jstring jcfname) {
+ rocksdb::ColumnFamilyHandle* handle;
+ const char* cfname = env->GetStringUTFChars(jcfname, 0);
+ auto db_handle = reinterpret_cast(jdb_handle);
+ rocksdb::Status s = db_handle->CreateColumnFamily(
+ rocksdb::ColumnFamilyOptions(), cfname, &handle);
+ env->ReleaseStringUTFChars(jcfname, cfname);
+
+ if (s.ok()) {
+ return reinterpret_cast(handle);
+ }
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ return 0;
+}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: dropColumnFamily
+ * Signature: (JJ)V;
+ */
+void Java_org_rocksdb_RocksDB_dropColumnFamily(
+ JNIEnv* env, jobject jdb, jlong jdb_handle, jlong jcf_handle) {
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ auto db_handle = reinterpret_cast(jdb_handle);
+ rocksdb::Status s = db_handle->DropColumnFamily(cf_handle);
+ if (!s.ok()) {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
+ }
+}
+
/*
* Class: org_rocksdb_RocksDB
* Method: getProperty0
* Signature: (JLjava/lang/String;I)Ljava/lang/String;
*/
-jstring Java_org_rocksdb_RocksDB_getProperty0(
+jstring Java_org_rocksdb_RocksDB_getProperty0__JLjava_lang_String_2I(
JNIEnv* env, jobject jdb, jlong db_handle, jstring jproperty,
jint jproperty_len) {
auto db = reinterpret_cast(db_handle);
@@ -448,3 +1054,28 @@ jstring Java_org_rocksdb_RocksDB_getProperty0(
return env->NewStringUTF(property_value.data());
}
+
+/*
+ * Class: org_rocksdb_RocksDB
+ * Method: getProperty0
+ * Signature: (JJLjava/lang/String;I)Ljava/lang/String;
+ */
+jstring Java_org_rocksdb_RocksDB_getProperty0__JJLjava_lang_String_2I(
+ JNIEnv* env, jobject jdb, jlong db_handle, jlong jcf_handle,
+ jstring jproperty, jint jproperty_len) {
+ auto db = reinterpret_cast(db_handle);
+ auto cf_handle = reinterpret_cast(jcf_handle);
+
+ const char* property = env->GetStringUTFChars(jproperty, 0);
+ rocksdb::Slice property_slice(property, jproperty_len);
+
+ std::string property_value;
+ bool retCode = db->GetProperty(cf_handle, property_slice, &property_value);
+ env->ReleaseStringUTFChars(jproperty, property);
+
+ if (!retCode) {
+ rocksdb::RocksDBExceptionJni::ThrowNew(env, rocksdb::Status::NotFound());
+ }
+
+ return env->NewStringUTF(property_value.data());
+}
diff --git a/java/rocksjni/write_batch.cc b/java/rocksjni/write_batch.cc
index a51cfce12..10937db14 100644
--- a/java/rocksjni/write_batch.cc
+++ b/java/rocksjni/write_batch.cc
@@ -60,14 +60,13 @@ void Java_org_rocksdb_WriteBatch_clear(JNIEnv* env, jobject jobj) {
}
/*
- * Class: org_rocksdb_WriteBatch
- * Method: put
- * Signature: ([BI[BI)V
+ * Helper for WriteBatch put operations
*/
-void Java_org_rocksdb_WriteBatch_put(
+void write_batch_put_helper(
JNIEnv* env, jobject jobj,
jbyteArray jkey, jint jkey_len,
- jbyteArray jvalue, jint jvalue_len) {
+ jbyteArray jvalue, jint jvalue_len,
+ rocksdb::ColumnFamilyHandle* cf_handle) {
rocksdb::WriteBatch* wb = rocksdb::WriteBatchJni::getHandle(env, jobj);
assert(wb != nullptr);
@@ -75,7 +74,64 @@ void Java_org_rocksdb_WriteBatch_put(
jbyte* value = env->GetByteArrayElements(jvalue, nullptr);
rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
rocksdb::Slice value_slice(reinterpret_cast(value), jvalue_len);
- wb->Put(key_slice, value_slice);
+ if (cf_handle != nullptr) {
+ wb->Put(cf_handle, key_slice, value_slice);
+ } else {
+ // backwards compatibility
+ wb->Put(key_slice, value_slice);
+ }
+ env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+ env->ReleaseByteArrayElements(jvalue, value, JNI_ABORT);
+}
+
+/*
+ * Class: org_rocksdb_WriteBatch
+ * Method: put
+ * Signature: ([BI[BI)V
+ */
+void Java_org_rocksdb_WriteBatch_put___3BI_3BI(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len) {
+ write_batch_put_helper(env, jobj, jkey, jkey_len, jvalue,
+ jvalue_len, nullptr);
+}
+
+/*
+ * Class: org_rocksdb_WriteBatch
+ * Method: put
+ * Signature: ([BI[BIJ)V
+ */
+void Java_org_rocksdb_WriteBatch_put___3BI_3BIJ(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ write_batch_put_helper(env, jobj, jkey, jkey_len, jvalue,
+ jvalue_len, cf_handle);
+}
+
+/*
+ * Helper for write batch merge operations
+ */
+void write_batch_merge_helper(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len,
+ rocksdb::ColumnFamilyHandle* cf_handle) {
+ rocksdb::WriteBatch* wb = rocksdb::WriteBatchJni::getHandle(env, jobj);
+ assert(wb != nullptr);
+
+ jbyte* key = env->GetByteArrayElements(jkey, nullptr);
+ jbyte* value = env->GetByteArrayElements(jvalue, nullptr);
+ rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
+ rocksdb::Slice value_slice(reinterpret_cast(value), jvalue_len);
+ if (cf_handle != nullptr) {
+ wb->Merge(cf_handle, key_slice, value_slice);
+ } else {
+ // backwards compatibility
+ wb->Merge(key_slice, value_slice);
+ }
env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
env->ReleaseByteArrayElements(jvalue, value, JNI_ABORT);
}
@@ -85,20 +141,46 @@ void Java_org_rocksdb_WriteBatch_put(
* Method: merge
* Signature: ([BI[BI)V
*/
-JNIEXPORT void JNICALL Java_org_rocksdb_WriteBatch_merge(
+void Java_org_rocksdb_WriteBatch_merge___3BI_3BI(
JNIEnv* env, jobject jobj,
jbyteArray jkey, jint jkey_len,
jbyteArray jvalue, jint jvalue_len) {
+ write_batch_merge_helper(env, jobj, jkey, jkey_len,
+ jvalue, jvalue_len, nullptr);
+}
+
+/*
+ * Class: org_rocksdb_WriteBatch
+ * Method: merge
+ * Signature: ([BI[BIJ)V
+ */
+void Java_org_rocksdb_WriteBatch_merge___3BI_3BIJ(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len,
+ jbyteArray jvalue, jint jvalue_len, jlong jcf_handle) {
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ write_batch_merge_helper(env, jobj, jkey, jkey_len,
+ jvalue, jvalue_len, cf_handle);
+}
+
+/*
+ * Helper for write batch remove operations
+ */
+void write_batch_remove_helper(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len,
+ rocksdb::ColumnFamilyHandle* cf_handle) {
rocksdb::WriteBatch* wb = rocksdb::WriteBatchJni::getHandle(env, jobj);
assert(wb != nullptr);
jbyte* key = env->GetByteArrayElements(jkey, nullptr);
- jbyte* value = env->GetByteArrayElements(jvalue, nullptr);
rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
- rocksdb::Slice value_slice(reinterpret_cast(value), jvalue_len);
- wb->Merge(key_slice, value_slice);
+ if (cf_handle != nullptr) {
+ wb->Delete(cf_handle, key_slice);
+ } else {
+ wb->Delete(key_slice);
+ }
env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
- env->ReleaseByteArrayElements(jvalue, value, JNI_ABORT);
}
/*
@@ -106,16 +188,22 @@ JNIEXPORT void JNICALL Java_org_rocksdb_WriteBatch_merge(
* Method: remove
* Signature: ([BI)V
*/
-JNIEXPORT void JNICALL Java_org_rocksdb_WriteBatch_remove(
+void Java_org_rocksdb_WriteBatch_remove___3BI(
JNIEnv* env, jobject jobj,
jbyteArray jkey, jint jkey_len) {
- rocksdb::WriteBatch* wb = rocksdb::WriteBatchJni::getHandle(env, jobj);
- assert(wb != nullptr);
+ write_batch_remove_helper(env, jobj, jkey, jkey_len, nullptr);
+}
- jbyte* key = env->GetByteArrayElements(jkey, nullptr);
- rocksdb::Slice key_slice(reinterpret_cast(key), jkey_len);
- wb->Delete(key_slice);
- env->ReleaseByteArrayElements(jkey, key, JNI_ABORT);
+/*
+ * Class: org_rocksdb_WriteBatch
+ * Method: remove
+ * Signature: ([BIJ)V
+ */
+void Java_org_rocksdb_WriteBatch_remove___3BIJ(
+ JNIEnv* env, jobject jobj,
+ jbyteArray jkey, jint jkey_len, jlong jcf_handle) {
+ auto cf_handle = reinterpret_cast(jcf_handle);
+ write_batch_remove_helper(env, jobj, jkey, jkey_len, cf_handle);
}
/*