diff --git a/java/org/rocksdb/ColumnFamilyOptions.java b/java/org/rocksdb/ColumnFamilyOptions.java index 9ce1e9a98bc62d066af8eb39e50b749806d6851c..7fa4545b5118d01aec0fc6467b0fe5d4e2554c8a 100644 --- a/java/org/rocksdb/ColumnFamilyOptions.java +++ b/java/org/rocksdb/ColumnFamilyOptions.java @@ -5,6 +5,8 @@ package org.rocksdb; +import java.util.Properties; + /** * ColumnFamilyOptions to control the behavior of a database. It will be used * during the creation of a {@link org.rocksdb.RocksDB} (i.e., RocksDB.open()). @@ -29,6 +31,58 @@ public class ColumnFamilyOptions extends RocksObject newColumnFamilyOptions(); } + /** + *

Private constructor to be used by + * {@link #getColumnFamilyOptionsFromProps(java.util.Properties)}

+ * + * @param handle native handle to ColumnFamilyOptions instance. + */ + private ColumnFamilyOptions(long handle) { + super(); + nativeHandle_ = handle; + } + + /** + *

Method to get a options instance by using pre-configured + * property values. If one or many values are undefined in + * the context of RocksDB the method will return a null + * value.

+ * + *

Note: Property keys can be derived from + * getter methods within the options class. Example: the method + * {@code writeBufferSize()} has a property key: + * {@code write_buffer_size}.

+ * + * @param properties {@link java.util.Properties} instance. + * + * @return {@link org.rocksdb.ColumnFamilyOptions instance} + * or null. + * + * @throws java.lang.IllegalArgumentException if null or empty + * {@link Properties} instance is passed to the method call. + */ + public static ColumnFamilyOptions getColumnFamilyOptionsFromProps( + Properties properties) { + if (properties == null || properties.size() == 0) { + throw new IllegalArgumentException( + "Properties value must contain at least one value."); + } + ColumnFamilyOptions columnFamilyOptions = null; + StringBuilder stringBuilder = new StringBuilder(); + for (final String name : properties.stringPropertyNames()){ + stringBuilder.append(name); + stringBuilder.append("="); + stringBuilder.append(properties.getProperty(name)); + stringBuilder.append(";"); + } + long handle = getColumnFamilyOptionsFromProps( + stringBuilder.toString()); + if (handle != 0){ + columnFamilyOptions = new ColumnFamilyOptions(handle); + } + return columnFamilyOptions; + } + @Override public ColumnFamilyOptions optimizeForPointLookup( long blockCacheSizeMb) { @@ -522,6 +576,9 @@ public class ColumnFamilyOptions extends RocksObject disposeInternal(nativeHandle_); } + private static native long getColumnFamilyOptionsFromProps( + String optString); + private native void newColumnFamilyOptions(); private native void disposeInternal(long handle); diff --git a/java/org/rocksdb/DBOptions.java b/java/org/rocksdb/DBOptions.java index e19ee9a0ab281bd3e37718006f76c6178cddc0c2..45113c0f2ad4c205424fa026680687e59c218550 100644 --- a/java/org/rocksdb/DBOptions.java +++ b/java/org/rocksdb/DBOptions.java @@ -5,6 +5,8 @@ package org.rocksdb; +import java.util.Properties; + /** * DBOptions to control the behavior of a database. It will be used * during the creation of a {@link org.rocksdb.RocksDB} (i.e., RocksDB.open()). @@ -29,6 +31,58 @@ public class DBOptions extends RocksObject implements DBOptionsInterface { newDBOptions(); } + /** + *

Private constructor to be used by + * {@link #getDBOptionsFromProps(java.util.Properties)}

+ * + * @param handle native handle to DBOptions instance. + */ + private DBOptions(long handle) { + super(); + nativeHandle_ = handle; + } + + /** + *

Method to get a options instance by using pre-configured + * property values. If one or many values are undefined in + * the context of RocksDB the method will return a null + * value.

+ * + *

Note: Property keys can be derived from + * getter methods within the options class. Example: the method + * {@code allowMmapReads()} has a property key: + * {@code allow_mmap_reads}.

+ * + * @param properties {@link java.util.Properties} instance. + * + * @return {@link org.rocksdb.DBOptions instance} + * or null. + * + * @throws java.lang.IllegalArgumentException if null or empty + * {@link java.util.Properties} instance is passed to the method call. + */ + public static DBOptions getDBOptionsFromProps( + Properties properties) { + if (properties == null || properties.size() == 0) { + throw new IllegalArgumentException( + "Properties value must contain at least one value."); + } + DBOptions dbOptions = null; + StringBuilder stringBuilder = new StringBuilder(); + for (final String name : properties.stringPropertyNames()){ + stringBuilder.append(name); + stringBuilder.append("="); + stringBuilder.append(properties.getProperty(name)); + stringBuilder.append(";"); + } + long handle = getDBOptionsFromProps( + stringBuilder.toString()); + if (handle != 0){ + dbOptions = new DBOptions(handle); + } + return dbOptions; + } + @Override public DBOptions setCreateIfMissing(boolean flag) { assert(isInitialized()); @@ -487,6 +541,9 @@ public class DBOptions extends RocksObject implements DBOptionsInterface { static final int DEFAULT_NUM_SHARD_BITS = -1; + private static native long getDBOptionsFromProps( + String optString); + private native void newDBOptions(); private native void disposeInternal(long handle); diff --git a/java/org/rocksdb/test/ColumnFamilyOptionsTest.java b/java/org/rocksdb/test/ColumnFamilyOptionsTest.java index 7fcfee14c4e24368d4285bf843855b4e153622f9..aae9b57493c595c19fd0f8a091d31f8ef41fb579 100644 --- a/java/org/rocksdb/test/ColumnFamilyOptionsTest.java +++ b/java/org/rocksdb/test/ColumnFamilyOptionsTest.java @@ -9,6 +9,7 @@ import org.junit.ClassRule; import org.junit.Test; import org.rocksdb.*; +import java.util.Properties; import java.util.Random; import static org.assertj.core.api.Assertions.assertThat; @@ -22,6 +23,57 @@ public class ColumnFamilyOptionsTest { public static final Random rand = PlatformRandomHelper. getPlatformSpecificRandomFactory(); + @Test + public void getColumnFamilyOptionsFromProps() { + ColumnFamilyOptions opt = null; + try { + // setup sample properties + Properties properties = new Properties(); + properties.put("write_buffer_size", "112"); + properties.put("max_write_buffer_number", "13"); + opt = ColumnFamilyOptions. + getColumnFamilyOptionsFromProps(properties); + assertThat(opt).isNotNull(); + assertThat(String.valueOf(opt.writeBufferSize())). + isEqualTo(properties.get("write_buffer_size")); + assertThat(String.valueOf(opt.maxWriteBufferNumber())). + isEqualTo(properties.get("max_write_buffer_number")); + } finally { + if (opt != null) { + opt.dispose(); + } + } + } + + @Test + public void failColumnFamilyOptionsFromPropsWithIllegalValue() { + ColumnFamilyOptions opt = null; + try { + // setup sample properties + Properties properties = new Properties(); + properties.put("tomato", "1024"); + properties.put("burger", "2"); + opt = ColumnFamilyOptions. + getColumnFamilyOptionsFromProps(properties); + assertThat(opt).isNull(); + } finally { + if (opt != null) { + opt.dispose(); + } + } + } + + @Test(expected = IllegalArgumentException.class) + public void failColumnFamilyOptionsFromPropsWithNullValue() { + ColumnFamilyOptions.getColumnFamilyOptionsFromProps(null); + } + + @Test(expected = IllegalArgumentException.class) + public void failColumnFamilyOptionsFromPropsWithEmptyProps() { + ColumnFamilyOptions.getColumnFamilyOptionsFromProps( + new Properties()); + } + @Test public void writeBufferSize() throws RocksDBException { ColumnFamilyOptions opt = null; diff --git a/java/org/rocksdb/test/DBOptionsTest.java b/java/org/rocksdb/test/DBOptionsTest.java index 9a15658e7fd903a8de01fdbf9f66053edea6caae..6064dd6942a3004d95d602da4d0e412d5c3cd18d 100644 --- a/java/org/rocksdb/test/DBOptionsTest.java +++ b/java/org/rocksdb/test/DBOptionsTest.java @@ -9,6 +9,7 @@ import org.junit.ClassRule; import org.junit.Test; import org.rocksdb.*; +import java.util.Properties; import java.util.Random; import static org.assertj.core.api.Assertions.assertThat; @@ -22,6 +23,56 @@ public class DBOptionsTest { public static final Random rand = PlatformRandomHelper. getPlatformSpecificRandomFactory(); + @Test + public void getDBOptionsFromProps() { + DBOptions opt = null; + try { + // setup sample properties + Properties properties = new Properties(); + properties.put("allow_mmap_reads", "true"); + properties.put("bytes_per_sync", "13"); + opt = DBOptions.getDBOptionsFromProps(properties); + assertThat(opt).isNotNull(); + assertThat(String.valueOf(opt.allowMmapReads())). + isEqualTo(properties.get("allow_mmap_reads")); + assertThat(String.valueOf(opt.bytesPerSync())). + isEqualTo(properties.get("bytes_per_sync")); + } finally { + if (opt != null) { + opt.dispose(); + } + } + } + + @Test + public void failDBOptionsFromPropsWithIllegalValue() { + DBOptions opt = null; + try { + // setup sample properties + Properties properties = new Properties(); + properties.put("tomato", "1024"); + properties.put("burger", "2"); + opt = DBOptions. + getDBOptionsFromProps(properties); + assertThat(opt).isNull(); + } finally { + if (opt != null) { + opt.dispose(); + } + } + } + + @Test(expected = IllegalArgumentException.class) + public void failDBOptionsFromPropsWithNullValue() { + DBOptions.getDBOptionsFromProps(null); + } + + @Test(expected = IllegalArgumentException.class) + public void failDBOptionsFromPropsWithEmptyProps() { + DBOptions.getDBOptionsFromProps( + new Properties()); + } + @Test public void createIfMissing() { DBOptions opt = null; diff --git a/java/rocksjni/options.cc b/java/rocksjni/options.cc index 50bab7a1bb4bba980c1e3c1dfd513688d0731be3..82fb1fd1b2a9e67dade984ddf25f46e1cc2028d8 100644 --- a/java/rocksjni/options.cc +++ b/java/rocksjni/options.cc @@ -31,6 +31,7 @@ #include "rocksdb/rate_limiter.h" #include "rocksdb/comparator.h" #include "rocksdb/merge_operator.h" +#include "rocksdb/utilities/convenience.h" #include "utilities/merge_operators.h" /* @@ -1776,6 +1777,31 @@ void Java_org_rocksdb_ColumnFamilyOptions_newColumnFamilyOptions( rocksdb::ColumnFamilyOptionsJni::setHandle(env, jobj, op); } +/* + * Class: org_rocksdb_ColumnFamilyOptions + * Method: getColumnFamilyOptionsFromProps + * Signature: (Ljava/util/String;)J + */ +jlong Java_org_rocksdb_ColumnFamilyOptions_getColumnFamilyOptionsFromProps( + JNIEnv* env, jclass jclazz, jstring jopt_string) { + jlong ret_value = 0; + rocksdb::ColumnFamilyOptions* cf_options = + new rocksdb::ColumnFamilyOptions(); + const char* opt_string = env->GetStringUTFChars(jopt_string, 0); + bool status = rocksdb::GetColumnFamilyOptionsFromString( + rocksdb::ColumnFamilyOptions(), opt_string, cf_options); + env->ReleaseStringUTFChars(jopt_string, opt_string); + // Check if ColumnFamilyOptions creation was possible. + if (status) { + ret_value = reinterpret_cast(cf_options); + } else { + // if operation failed the ColumnFamilyOptions need to be deleted + // again to prevent a memory leak. + delete cf_options; + } + return ret_value; +} + /* * Class: org_rocksdb_ColumnFamilyOptions * Method: disposeInternal @@ -2751,6 +2777,31 @@ void Java_org_rocksdb_DBOptions_newDBOptions(JNIEnv* env, rocksdb::DBOptionsJni::setHandle(env, jobj, dbop); } +/* + * Class: org_rocksdb_DBOptions + * Method: getDBOptionsFromProps + * Signature: (Ljava/util/String;)J + */ +jlong Java_org_rocksdb_DBOptions_getDBOptionsFromProps( + JNIEnv* env, jclass jclazz, jstring jopt_string) { + jlong ret_value = 0; + rocksdb::DBOptions* db_options = + new rocksdb::DBOptions(); + const char* opt_string = env->GetStringUTFChars(jopt_string, 0); + bool status = rocksdb::GetDBOptionsFromString( + rocksdb::DBOptions(), opt_string, db_options); + env->ReleaseStringUTFChars(jopt_string, opt_string); + // Check if DBOptions creation was possible. + if (status) { + ret_value = reinterpret_cast(db_options); + } else { + // if operation failed the DBOptions need to be deleted + // again to prevent a memory leak. + delete db_options; + } + return ret_value; +} + /* * Class: org_rocksdb_DBOptions * Method: disposeInternal