@@ -70,6 +70,8 @@ static const char *getErrorMessage(int code)
7070 return "database is locked" ;
7171 case TDB_ERR_READONLY :
7272 return "database is read-only" ;
73+ case TDB_ERR_BUSY :
74+ return "resource is busy" ;
7375 default :
7476 return "unknown error" ;
7577 }
@@ -87,7 +89,7 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeOpen(
8789 jlong oscMultipartPartSize , jboolean oscSyncManifestToObject , jboolean oscReplicateWal ,
8890 jboolean oscWalUploadSync , jlong oscWalSyncThresholdBytes , jboolean oscWalSyncOnCommit ,
8991 jboolean oscReplicaMode , jlong oscReplicaSyncIntervalUs , jboolean oscReplicaReplayWal ,
90- jint maxConcurrentFlushes )
92+ jint maxConcurrentFlushes , jboolean finishCompactionsOnClose )
9193{
9294 const char * path = (* env )-> GetStringUTFChars (env , dbPath , NULL );
9395 if (path == NULL )
@@ -151,7 +153,8 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeOpen(
151153 .unified_memtable_sync_interval_us = (uint64_t )unifiedMemtableSyncIntervalUs ,
152154 .object_store = obj_store ,
153155 .object_store_config = obj_store != NULL ? & os_cfg : NULL ,
154- .max_concurrent_flushes = maxConcurrentFlushes };
156+ .max_concurrent_flushes = maxConcurrentFlushes ,
157+ .finish_compactions_on_close = finishCompactionsOnClose ? 1 : 0 };
155158
156159 tidesdb_t * db = NULL ;
157160 int result = tidesdb_open (& config , & db );
@@ -632,7 +635,7 @@ JNIEXPORT jobject JNICALL Java_com_tidesdb_ColumnFamily_nativeGetStats(JNIEnv *e
632635
633636 jclass statsClass = (* env )-> FindClass (env , "com/tidesdb/Stats" );
634637 jmethodID constructor = (* env )-> GetMethodID (env , statsClass , "<init>" ,
635- "(IJ[J[ILcom/tidesdb/ColumnFamilyConfig;JJDD[JDDZJIDJD[JDI )V" );
638+ "(IJ[J[ILcom/tidesdb/ColumnFamilyConfig;JJDD[JDDZJIDJD[JDIJJJJJJJ )V" );
636639
637640 jobject statsObj = (* env )-> NewObject (env , statsClass , constructor , stats -> num_levels ,
638641 (jlong )stats -> memtable_size , levelSizes , levelNumSSTables ,
@@ -646,7 +649,14 @@ JNIEXPORT jobject JNICALL Java_com_tidesdb_ColumnFamily_nativeGetStats(JNIEnv *e
646649 (jdouble )stats -> tombstone_ratio ,
647650 levelTombstoneCounts ,
648651 (jdouble )stats -> max_sst_density ,
649- (jint )stats -> max_sst_density_level );
652+ (jint )stats -> max_sst_density_level ,
653+ (jlong )stats -> wal_bytes_written ,
654+ (jlong )stats -> flush_bytes_written ,
655+ (jlong )stats -> compaction_bytes_written ,
656+ (jlong )stats -> compaction_bytes_read ,
657+ (jlong )stats -> user_bytes_written ,
658+ (jlong )stats -> flush_count ,
659+ (jlong )stats -> compaction_count );
650660
651661 tidesdb_free_stats (stats );
652662
@@ -1323,7 +1333,7 @@ JNIEXPORT jobject JNICALL Java_com_tidesdb_TidesDB_nativeGetDbStats(JNIEnv *env,
13231333 boolean, String, long, long, int, long, long, long, long, boolean */
13241334 jmethodID constructor = (* env )-> GetMethodID (
13251335 env , dbStatsClass , "<init>" ,
1326- "(IJJJIIJIIJIJJJJZJIZIJZLjava/lang/String;JJIJJJJZ )V" );
1336+ "(IJJJIIJIIJIJJJJZJIZIJZLjava/lang/String;JJIJJJJZJJJJJJJJ )V" );
13271337
13281338 jstring connectorStr = NULL ;
13291339 if (db_stats .object_store_connector != NULL )
@@ -1362,7 +1372,15 @@ JNIEXPORT jobject JNICALL Java_com_tidesdb_TidesDB_nativeGetDbStats(JNIEnv *env,
13621372 (jlong )db_stats .upload_queue_depth ,
13631373 (jlong )db_stats .total_uploads ,
13641374 (jlong )db_stats .total_upload_failures ,
1365- db_stats .replica_mode != 0 );
1375+ db_stats .replica_mode != 0 ,
1376+ (jlong )db_stats .uwal_bytes_written ,
1377+ (jlong )db_stats .wal_bytes_written ,
1378+ (jlong )db_stats .flush_bytes_written ,
1379+ (jlong )db_stats .compaction_bytes_written ,
1380+ (jlong )db_stats .compaction_bytes_read ,
1381+ (jlong )db_stats .user_bytes_written ,
1382+ (jlong )db_stats .flush_count ,
1383+ (jlong )db_stats .compaction_count );
13661384}
13671385
13681386JNIEXPORT jdouble JNICALL Java_com_tidesdb_ColumnFamily_nativeRangeCost (JNIEnv * env , jclass cls ,
@@ -1422,6 +1440,25 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativePromoteToPrimary(JNIEnv *e
14221440 }
14231441}
14241442
1443+ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCancelBackgroundWork (JNIEnv * env , jclass cls ,
1444+ jlong handle )
1445+ {
1446+ tidesdb_t * db = (tidesdb_t * )(uintptr_t )handle ;
1447+
1448+ int result = tidesdb_cancel_background_work (db );
1449+
1450+ if (result != TDB_SUCCESS )
1451+ {
1452+ throwTidesDBException (env , result , getErrorMessage (result ));
1453+ }
1454+ }
1455+
1456+ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeRaiseOpenFileLimit (JNIEnv * env , jclass cls ,
1457+ jlong desired )
1458+ {
1459+ return (jlong )tidesdb_raise_open_file_limit ((long )desired );
1460+ }
1461+
14251462JNIEXPORT jint JNICALL Java_com_tidesdb_Config_nativeDefaultMaxConcurrentFlushes (JNIEnv * env ,
14261463 jclass cls )
14271464{
@@ -1443,6 +1480,159 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_ColumnFamilyConfig_nativeDefaultTombsto
14431480 return (jlong )cfg .tombstone_density_min_entries ;
14441481}
14451482
1483+ /**
1484+ * Builds a com.tidesdb.ColumnFamilyConfig from a native config struct via the
1485+ * ColumnFamilyConfig.fromNative static factory. Returns a local ref, or NULL on error.
1486+ */
1487+ static jobject buildCfConfigObject (JNIEnv * env , const tidesdb_column_family_config_t * cfg )
1488+ {
1489+ jclass cfConfigClass = (* env )-> FindClass (env , "com/tidesdb/ColumnFamilyConfig" );
1490+ if (cfConfigClass == NULL ) return NULL ;
1491+
1492+ jmethodID fromNative = (* env )-> GetStaticMethodID (
1493+ env , cfConfigClass , "fromNative" ,
1494+ "(JJIIJIZDZIIIJLjava/lang/String;IFIJIIDJZZZ)Lcom/tidesdb/ColumnFamilyConfig;" );
1495+ if (fromNative == NULL )
1496+ {
1497+ (* env )-> DeleteLocalRef (env , cfConfigClass );
1498+ return NULL ;
1499+ }
1500+
1501+ jstring comparatorName = (* env )-> NewStringUTF (env , cfg -> comparator_name );
1502+
1503+ jobject obj = (* env )-> CallStaticObjectMethod (
1504+ env , cfConfigClass , fromNative ,
1505+ (jlong )cfg -> write_buffer_size , (jlong )cfg -> level_size_ratio , (jint )cfg -> min_levels ,
1506+ (jint )cfg -> dividing_level_offset , (jlong )cfg -> klog_value_threshold ,
1507+ (jint )cfg -> compression_algorithm ,
1508+ cfg -> enable_bloom_filter != 0 ? JNI_TRUE : JNI_FALSE , (jdouble )cfg -> bloom_fpr ,
1509+ cfg -> enable_block_indexes != 0 ? JNI_TRUE : JNI_FALSE , (jint )cfg -> index_sample_ratio ,
1510+ (jint )cfg -> block_index_prefix_len , (jint )cfg -> sync_mode , (jlong )cfg -> sync_interval_us ,
1511+ comparatorName , (jint )cfg -> skip_list_max_level , (jfloat )cfg -> skip_list_probability ,
1512+ (jint )cfg -> default_isolation_level , (jlong )cfg -> min_disk_space ,
1513+ (jint )cfg -> l1_file_count_trigger , (jint )cfg -> l0_queue_stall_threshold ,
1514+ (jdouble )cfg -> tombstone_density_trigger , (jlong )cfg -> tombstone_density_min_entries ,
1515+ cfg -> use_btree != 0 ? JNI_TRUE : JNI_FALSE ,
1516+ cfg -> object_lazy_compaction != 0 ? JNI_TRUE : JNI_FALSE ,
1517+ cfg -> object_prefetch_compaction != 0 ? JNI_TRUE : JNI_FALSE );
1518+
1519+ (* env )-> DeleteLocalRef (env , comparatorName );
1520+ (* env )-> DeleteLocalRef (env , cfConfigClass );
1521+ return obj ;
1522+ }
1523+
1524+ JNIEXPORT void JNICALL Java_com_tidesdb_ColumnFamilyConfig_nativeSaveToIni (
1525+ JNIEnv * env , jclass cls , jstring iniFile , jstring sectionName , jlong writeBufferSize ,
1526+ jlong levelSizeRatio , jint minLevels , jint dividingLevelOffset , jlong klogValueThreshold ,
1527+ jint compressionAlgorithm , jboolean enableBloomFilter , jdouble bloomFPR ,
1528+ jboolean enableBlockIndexes , jint indexSampleRatio , jint blockIndexPrefixLen , jint syncMode ,
1529+ jlong syncIntervalUs , jstring comparatorName , jint skipListMaxLevel , jfloat skipListProbability ,
1530+ jint defaultIsolationLevel , jlong minDiskSpace , jint l1FileCountTrigger ,
1531+ jint l0QueueStallThreshold , jdouble tombstoneDensityTrigger , jlong tombstoneDensityMinEntries ,
1532+ jboolean useBtree , jboolean objectLazyCompaction , jboolean objectPrefetchCompaction )
1533+ {
1534+ const char * ini = (* env )-> GetStringUTFChars (env , iniFile , NULL );
1535+ if (ini == NULL )
1536+ {
1537+ throwTidesDBException (env , TDB_ERR_MEMORY , "Failed to get INI file path" );
1538+ return ;
1539+ }
1540+ const char * section = (* env )-> GetStringUTFChars (env , sectionName , NULL );
1541+ if (section == NULL )
1542+ {
1543+ (* env )-> ReleaseStringUTFChars (env , iniFile , ini );
1544+ throwTidesDBException (env , TDB_ERR_MEMORY , "Failed to get section name" );
1545+ return ;
1546+ }
1547+
1548+ const char * compName = NULL ;
1549+ if (comparatorName != NULL )
1550+ {
1551+ compName = (* env )-> GetStringUTFChars (env , comparatorName , NULL );
1552+ }
1553+
1554+ tidesdb_column_family_config_t config = {
1555+ .write_buffer_size = (size_t )writeBufferSize ,
1556+ .level_size_ratio = (size_t )levelSizeRatio ,
1557+ .min_levels = minLevels ,
1558+ .dividing_level_offset = dividingLevelOffset ,
1559+ .klog_value_threshold = (size_t )klogValueThreshold ,
1560+ .compression_algorithm = (compression_algorithm )compressionAlgorithm ,
1561+ .enable_bloom_filter = enableBloomFilter ? 1 : 0 ,
1562+ .bloom_fpr = bloomFPR ,
1563+ .enable_block_indexes = enableBlockIndexes ? 1 : 0 ,
1564+ .index_sample_ratio = indexSampleRatio ,
1565+ .block_index_prefix_len = blockIndexPrefixLen ,
1566+ .sync_mode = syncMode ,
1567+ .sync_interval_us = (uint64_t )syncIntervalUs ,
1568+ .skip_list_max_level = skipListMaxLevel ,
1569+ .skip_list_probability = skipListProbability ,
1570+ .default_isolation_level = (tidesdb_isolation_level_t )defaultIsolationLevel ,
1571+ .min_disk_space = (uint64_t )minDiskSpace ,
1572+ .l1_file_count_trigger = l1FileCountTrigger ,
1573+ .l0_queue_stall_threshold = l0QueueStallThreshold ,
1574+ .tombstone_density_trigger = tombstoneDensityTrigger ,
1575+ .tombstone_density_min_entries = (uint64_t )tombstoneDensityMinEntries ,
1576+ .use_btree = useBtree ? 1 : 0 ,
1577+ .object_lazy_compaction = objectLazyCompaction ? 1 : 0 ,
1578+ .object_prefetch_compaction = objectPrefetchCompaction ? 1 : 0 };
1579+
1580+ memset (config .comparator_name , 0 , TDB_MAX_COMPARATOR_NAME );
1581+ if (compName != NULL && strlen (compName ) > 0 )
1582+ {
1583+ strncpy (config .comparator_name , compName , TDB_MAX_COMPARATOR_NAME - 1 );
1584+ }
1585+ memset (config .comparator_ctx_str , 0 , TDB_MAX_COMPARATOR_CTX );
1586+
1587+ int result = tidesdb_cf_config_save_to_ini (ini , section , & config );
1588+
1589+ (* env )-> ReleaseStringUTFChars (env , iniFile , ini );
1590+ (* env )-> ReleaseStringUTFChars (env , sectionName , section );
1591+ if (compName != NULL )
1592+ {
1593+ (* env )-> ReleaseStringUTFChars (env , comparatorName , compName );
1594+ }
1595+
1596+ if (result != TDB_SUCCESS )
1597+ {
1598+ throwTidesDBException (env , result , getErrorMessage (result ));
1599+ }
1600+ }
1601+
1602+ JNIEXPORT jobject JNICALL Java_com_tidesdb_ColumnFamilyConfig_nativeLoadFromIni (
1603+ JNIEnv * env , jclass cls , jstring iniFile , jstring sectionName )
1604+ {
1605+ const char * ini = (* env )-> GetStringUTFChars (env , iniFile , NULL );
1606+ if (ini == NULL )
1607+ {
1608+ throwTidesDBException (env , TDB_ERR_MEMORY , "Failed to get INI file path" );
1609+ return NULL ;
1610+ }
1611+ const char * section = (* env )-> GetStringUTFChars (env , sectionName , NULL );
1612+ if (section == NULL )
1613+ {
1614+ (* env )-> ReleaseStringUTFChars (env , iniFile , ini );
1615+ throwTidesDBException (env , TDB_ERR_MEMORY , "Failed to get section name" );
1616+ return NULL ;
1617+ }
1618+
1619+ /* start from engine defaults so fields absent from the INI section keep sane values */
1620+ tidesdb_column_family_config_t config = tidesdb_default_column_family_config ();
1621+
1622+ int result = tidesdb_cf_config_load_from_ini (ini , section , & config );
1623+
1624+ (* env )-> ReleaseStringUTFChars (env , iniFile , ini );
1625+ (* env )-> ReleaseStringUTFChars (env , sectionName , section );
1626+
1627+ if (result != TDB_SUCCESS )
1628+ {
1629+ throwTidesDBException (env , result , getErrorMessage (result ));
1630+ return NULL ;
1631+ }
1632+
1633+ return buildCfConfigObject (env , & config );
1634+ }
1635+
14461636JNIEXPORT jobject JNICALL Java_com_tidesdb_TidesDBIterator_nativeKeyValue (JNIEnv * env , jclass cls ,
14471637 jlong handle )
14481638{
0 commit comments