From 106a0a4b747f54a963ea8367159fc17581b1d5de Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Mon, 26 Oct 2026 18:11:02 -0700 Subject: [PATCH] feat!: let the engine control SystemConfig defaults Stop pinning a copy of every engine default in this binding. SystemConfig fields are now boxed (Long/Boolean) defaulting to null, meaning "use the engine default". The JNI layer starts from lbug_default_system_config() and only applies non-null values. The legacy lbugDatabaseInit native is removed; its callers now pass nulls for fields the overload predates. Unset settings follow engine-side default changes automatically (e.g. LadybugDB/ladybug#1435's enable_multi_writes flip needs no binding change). Explicitly passed values behave exactly as before. BREAKING CHANGE: SystemConfig fields changed from primitives to boxed types; the lbugDatabaseInit native was removed. --- .../com/ladybugdb/example/MainActivity.kt | 2 +- src/jni/lbug_java.cpp | 92 +++++++++++++------ src/main/java/com/lbugdb/Database.java | 32 ++----- src/main/java/com/lbugdb/Native.java | 18 ++-- src/main/java/com/lbugdb/SystemConfig.java | 26 +++--- 5 files changed, 94 insertions(+), 76 deletions(-) diff --git a/examples/android-kotlin/app/src/main/kotlin/com/ladybugdb/example/MainActivity.kt b/examples/android-kotlin/app/src/main/kotlin/com/ladybugdb/example/MainActivity.kt index fcbecf7..d21da51 100644 --- a/examples/android-kotlin/app/src/main/kotlin/com/ladybugdb/example/MainActivity.kt +++ b/examples/android-kotlin/app/src/main/kotlin/com/ladybugdb/example/MainActivity.kt @@ -17,7 +17,7 @@ class MainActivity : Activity() { } fun exampleConfig(): SystemConfig = SystemConfig().apply { - maxNumThreads = 2 + maxNumThreads = 2L enableDefaultHashIndex = true } diff --git a/src/jni/lbug_java.cpp b/src/jni/lbug_java.cpp index ee0cdb0..87d70ae 100644 --- a/src/jni/lbug_java.cpp +++ b/src/jni/lbug_java.cpp @@ -581,40 +581,83 @@ JNIEXPORT void JNICALL Java_com_ladybugdb_Native_lbugNativeReloadLibrary(JNIEnv* } } +namespace { + +// Boxed Java settings: null means "keep the engine default". The config +// below already starts from lbug_default_system_config(), so nulls are simply +// skipped. +bool unboxBoolean(JNIEnv* env, jobject boxed, bool& out) { + if (boxed == nullptr) { + return false; + } + jclass cls = env->FindClass("java/lang/Boolean"); + jmethodID mid = env->GetMethodID(cls, "booleanValue", "()Z"); + out = env->CallBooleanMethod(boxed, mid); + return true; +} + +bool unboxLong(JNIEnv* env, jobject boxed, int64_t& out) { + if (boxed == nullptr) { + return false; + } + jclass cls = env->FindClass("java/lang/Long"); + jmethodID mid = env->GetMethodID(cls, "longValue", "()J"); + out = env->CallLongMethod(boxed, mid); + return true; +} + +} // namespace + JNIEXPORT jlong JNICALL Java_com_ladybugdb_Native_lbugDatabaseInitExtended(JNIEnv* env, jclass, - jstring databasePath, jlong bufferPoolSize, jlong maxNumThreads, jboolean enableCompression, - jboolean readOnly, jlong maxDbSize, jboolean autoCheckpoint, jlong checkpointThreshold, - jboolean throwOnWalReplayFailure, jboolean enableChecksums, jboolean enableMultiWrites, - jboolean enableDefaultHashIndex) { + jstring databasePath, jobject bufferPoolSize, jobject maxNumThreads, jobject enableCompression, + jobject readOnly, jobject maxDbSize, jobject autoCheckpoint, jobject checkpointThreshold, + jobject throwOnWalReplayFailure, jobject enableChecksums, jobject enableMultiWrites, + jobject enableDefaultHashIndex) { try { const char* path = env->GetStringUTFChars(databasePath, JNI_FALSE); auto systemConfig = lbug_default_system_config(); - if (bufferPoolSize != 0) { - systemConfig.buffer_pool_size = static_cast(bufferPoolSize); + int64_t longValue = 0; + bool boolValue = false; + if (unboxLong(env, bufferPoolSize, longValue) && longValue != 0) { + systemConfig.buffer_pool_size = static_cast(longValue); } - if (maxNumThreads != 0) { - systemConfig.max_num_threads = static_cast(maxNumThreads); + if (unboxLong(env, maxNumThreads, longValue) && longValue != 0) { + systemConfig.max_num_threads = static_cast(longValue); } - systemConfig.enable_compression = enableCompression; - systemConfig.read_only = readOnly; - if (maxDbSize != 0) { - auto unsignedMaxDbSize = static_cast(maxDbSize); + if (unboxBoolean(env, enableCompression, boolValue)) { + systemConfig.enable_compression = boolValue; + } + if (unboxBoolean(env, readOnly, boolValue)) { + systemConfig.read_only = boolValue; + } + if (unboxLong(env, maxDbSize, longValue) && longValue != 0) { + auto unsignedMaxDbSize = static_cast(longValue); if ((unsignedMaxDbSize & (unsignedMaxDbSize - 1)) != 0) { env->ReleaseStringUTFChars(databasePath, path); env->ThrowNew(J_C_Exception, "Buffer manager exception: The given max db size should be a power of 2."); return 0; } - systemConfig.max_db_size = static_cast(maxDbSize); + systemConfig.max_db_size = static_cast(longValue); + } + if (unboxBoolean(env, autoCheckpoint, boolValue)) { + systemConfig.auto_checkpoint = boolValue; + } + if (unboxLong(env, checkpointThreshold, longValue) && longValue >= 0) { + systemConfig.checkpoint_threshold = static_cast(longValue); + } + if (unboxBoolean(env, throwOnWalReplayFailure, boolValue)) { + systemConfig.throw_on_wal_replay_failure = boolValue; } - systemConfig.auto_checkpoint = autoCheckpoint; - if (checkpointThreshold >= 0) { - systemConfig.checkpoint_threshold = static_cast(checkpointThreshold); + if (unboxBoolean(env, enableChecksums, boolValue)) { + systemConfig.enable_checksums = boolValue; + } + if (unboxBoolean(env, enableMultiWrites, boolValue)) { + systemConfig.enable_multi_writes = boolValue; + } + if (unboxBoolean(env, enableDefaultHashIndex, boolValue)) { + systemConfig.enable_default_hash_index = boolValue; } - systemConfig.throw_on_wal_replay_failure = throwOnWalReplayFailure; - systemConfig.enable_checksums = enableChecksums; - systemConfig.enable_multi_writes = enableMultiWrites; - systemConfig.enable_default_hash_index = enableDefaultHashIndex; try { auto* db = new lbug_database(); auto state = lbug_database_init(path, systemConfig, db); @@ -642,15 +685,6 @@ JNIEXPORT jlong JNICALL Java_com_ladybugdb_Native_lbugDatabaseInitExtended(JNIEn return 0; } -JNIEXPORT jlong JNICALL Java_com_ladybugdb_Native_lbugDatabaseInit(JNIEnv* env, jclass clazz, - jstring databasePath, jlong bufferPoolSize, jboolean enableCompression, jboolean readOnly, - jlong maxDbSize, jboolean autoCheckpoint, jlong checkpointThreshold, - jboolean throwOnWalReplayFailure, jboolean enableChecksums) { - return Java_com_ladybugdb_Native_lbugDatabaseInitExtended(env, clazz, databasePath, - bufferPoolSize, 0, enableCompression, readOnly, maxDbSize, autoCheckpoint, - checkpointThreshold, throwOnWalReplayFailure, enableChecksums, false, true); -} - JNIEXPORT void JNICALL Java_com_ladybugdb_Native_lbugDatabaseDestroy(JNIEnv* env, jclass, jobject thisDB) { try { diff --git a/src/main/java/com/lbugdb/Database.java b/src/main/java/com/lbugdb/Database.java index e316d31..822bdd2 100644 --- a/src/main/java/com/lbugdb/Database.java +++ b/src/main/java/com/lbugdb/Database.java @@ -9,14 +9,7 @@ public class Database implements AutoCloseable { String db_path; long buffer_size; long max_db_size; - boolean enableCompression = true; boolean destroyed = false; - boolean readOnly = false; - boolean autoCheckpoint = true; - boolean throwOnWalReplayFailure = true; - boolean enableChecksums = true; - boolean enableMultiWrites = false; - boolean enableDefaultHashIndex = true; long max_num_threads; long checkpointThreshold; @@ -40,8 +33,9 @@ public Database(String databasePath) { this.max_num_threads = 0; this.max_db_size = 0; this.checkpointThreshold = -1; - db_ref = Native.lbugDatabaseInit(databasePath, 0, true, false, max_db_size, - autoCheckpoint, checkpointThreshold, throwOnWalReplayFailure, enableChecksums); + // All nulls: pure engine defaults. + db_ref = Native.lbugDatabaseInitExtended(databasePath, null, null, null, null, null, null, + null, null, null, null, null); } /** @@ -91,16 +85,13 @@ public Database(String databasePath, long bufferPoolSize, boolean enableCompress this.db_path = databasePath; this.buffer_size = bufferPoolSize; this.max_num_threads = 0; - this.enableCompression = enableCompression; - this.readOnly = readOnly; this.max_db_size = maxDBSize; - this.autoCheckpoint = autoCheckpoint; this.checkpointThreshold = checkpointThreshold; - this.throwOnWalReplayFailure = throwOnWalReplayFailure; - this.enableChecksums = enableChecksums; - db_ref = Native.lbugDatabaseInit(databasePath, bufferPoolSize, enableCompression, readOnly, - maxDBSize, autoCheckpoint, checkpointThreshold, throwOnWalReplayFailure, - enableChecksums); + // Fields this overload predates (maxNumThreads, enableMultiWrites, + // enableDefaultHashIndex) are left null so the engine default applies. + db_ref = Native.lbugDatabaseInitExtended(databasePath, bufferPoolSize, null, + enableCompression, readOnly, maxDBSize, autoCheckpoint, checkpointThreshold, + throwOnWalReplayFailure, enableChecksums, null, null); } /** @@ -127,15 +118,8 @@ public Database(String databasePath, long bufferPoolSize, long maxNumThreads, this.db_path = databasePath; this.buffer_size = bufferPoolSize; this.max_num_threads = maxNumThreads; - this.enableCompression = enableCompression; - this.readOnly = readOnly; this.max_db_size = maxDBSize; - this.autoCheckpoint = autoCheckpoint; this.checkpointThreshold = checkpointThreshold; - this.throwOnWalReplayFailure = throwOnWalReplayFailure; - this.enableChecksums = enableChecksums; - this.enableMultiWrites = enableMultiWrites; - this.enableDefaultHashIndex = enableDefaultHashIndex; db_ref = Native.lbugDatabaseInitExtended(databasePath, bufferPoolSize, maxNumThreads, enableCompression, readOnly, maxDBSize, autoCheckpoint, checkpointThreshold, throwOnWalReplayFailure, enableChecksums, enableMultiWrites, diff --git a/src/main/java/com/lbugdb/Native.java b/src/main/java/com/lbugdb/Native.java index 9502b5a..6081e0c 100644 --- a/src/main/java/com/lbugdb/Native.java +++ b/src/main/java/com/lbugdb/Native.java @@ -73,17 +73,13 @@ else if (os_name_detect.startsWith("windows")) { protected static native void lbugNativeReloadLibrary(String libPath); // Database - protected static native long lbugDatabaseInit(String databasePath, long bufferPoolSize, - boolean enableCompression, boolean readOnly, long maxDbSize, boolean autoCheckpoint, - long checkpointThreshold, boolean throwOnWalReplayFailure, boolean enableChecksums); - - // TODO: Collapse this back into lbugDatabaseInit after published main-repo - // Java native artifacts have been rebuilt with the extended system_config fields. - protected static native long lbugDatabaseInitExtended(String databasePath, long bufferPoolSize, - long maxNumThreads, - boolean enableCompression, boolean readOnly, long maxDbSize, boolean autoCheckpoint, - long checkpointThreshold, boolean throwOnWalReplayFailure, boolean enableChecksums, - boolean enableMultiWrites, boolean enableDefaultHashIndex); + // + // All settings are boxed: null means "use the engine default" and only + // non-null values override the engine configuration. + protected static native long lbugDatabaseInitExtended(String databasePath, Long bufferPoolSize, + Long maxNumThreads, Boolean enableCompression, Boolean readOnly, Long maxDbSize, + Boolean autoCheckpoint, Long checkpointThreshold, Boolean throwOnWalReplayFailure, + Boolean enableChecksums, Boolean enableMultiWrites, Boolean enableDefaultHashIndex); protected static native void lbugDatabaseDestroy(Database db); diff --git a/src/main/java/com/lbugdb/SystemConfig.java b/src/main/java/com/lbugdb/SystemConfig.java index 3bce7fb..54a5fd4 100644 --- a/src/main/java/com/lbugdb/SystemConfig.java +++ b/src/main/java/com/lbugdb/SystemConfig.java @@ -2,17 +2,21 @@ /** * Runtime configuration for creating or opening a Database. + * + *

All fields default to {@code null}, which means "use the engine default". + * Only explicitly set fields override the engine configuration, so engine-side + * default changes apply automatically without a binding update. */ public class SystemConfig { - public long bufferPoolSize = 0; - public long maxNumThreads = 0; - public boolean enableCompression = true; - public boolean readOnly = false; - public long maxDBSize = 0; - public boolean autoCheckpoint = true; - public long checkpointThreshold = -1; - public boolean throwOnWalReplayFailure = true; - public boolean enableChecksums = true; - public boolean enableMultiWrites = false; - public boolean enableDefaultHashIndex = true; + public Long bufferPoolSize = null; + public Long maxNumThreads = null; + public Boolean enableCompression = null; + public Boolean readOnly = null; + public Long maxDBSize = null; + public Boolean autoCheckpoint = null; + public Long checkpointThreshold = null; + public Boolean throwOnWalReplayFailure = null; + public Boolean enableChecksums = null; + public Boolean enableMultiWrites = null; + public Boolean enableDefaultHashIndex = null; }