Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.tidesdb</groupId>
<artifactId>tidesdb-java</artifactId>
<version>0.2.0</version>
<version>0.3.0</version>
<packaging>jar</packaging>

<name>TidesDB Java</name>
Expand Down
4 changes: 2 additions & 2 deletions src/main/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ project(tidesdb_jni C)

set(CMAKE_C_STANDARD 11)

# Find JNI
find_package(JNI REQUIRED)
# Find JNI (AWT not required for JNI bindings)
find_package(JNI REQUIRED COMPONENTS JVM)

# Find TidesDB
find_library(TIDESDB_LIBRARY tidesdb HINTS /usr/local/lib /opt/tidesdb/lib ${CMAKE_PREFIX_PATH}/lib)
Expand Down
92 changes: 91 additions & 1 deletion src/main/c/com_tidesdb_TidesDB.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCreateColumnFamily(
.min_levels = minLevels,
.dividing_level_offset = dividingLevelOffset,
.klog_value_threshold = (size_t)klogValueThreshold,
.compression_algo = (compression_algorithm)compressionAlgorithm,
.compression_algorithm = (compression_algorithm)compressionAlgorithm,
.enable_bloom_filter = enableBloomFilter ? 1 : 0,
.bloom_fpr = bloomFPR,
.enable_block_indexes = enableBlockIndexes ? 1 : 0,
Expand Down Expand Up @@ -341,6 +341,59 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeRegisterComparator(JNIEnv
}
}

JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeBackup(JNIEnv *env, jclass cls, jlong handle,
jstring dir)
{
tidesdb_t *db = (tidesdb_t *)(uintptr_t)handle;
const char *backupDir = (*env)->GetStringUTFChars(env, dir, NULL);
if (backupDir == NULL)
{
throwTidesDBException(env, TDB_ERR_MEMORY, "Failed to get backup directory");
return;
}

int result = tidesdb_backup(db, (char *)backupDir);

(*env)->ReleaseStringUTFChars(env, dir, backupDir);

if (result != TDB_SUCCESS)
{
throwTidesDBException(env, result, getErrorMessage(result));
}
}

JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeRenameColumnFamily(JNIEnv *env, jclass cls,
jlong handle,
jstring oldName,
jstring newName)
{
tidesdb_t *db = (tidesdb_t *)(uintptr_t)handle;
const char *oldCfName = (*env)->GetStringUTFChars(env, oldName, NULL);
if (oldCfName == NULL)
{
throwTidesDBException(env, TDB_ERR_MEMORY, "Failed to get old column family name");
return;
}

const char *newCfName = (*env)->GetStringUTFChars(env, newName, NULL);
if (newCfName == NULL)
{
(*env)->ReleaseStringUTFChars(env, oldName, oldCfName);
throwTidesDBException(env, TDB_ERR_MEMORY, "Failed to get new column family name");
return;
}

int result = tidesdb_rename_column_family(db, oldCfName, newCfName);

(*env)->ReleaseStringUTFChars(env, oldName, oldCfName);
(*env)->ReleaseStringUTFChars(env, newName, newCfName);

if (result != TDB_SUCCESS)
{
throwTidesDBException(env, result, getErrorMessage(result));
}
}

JNIEXPORT jobject JNICALL Java_com_tidesdb_ColumnFamily_nativeGetStats(JNIEnv *env, jclass cls,
jlong handle)
{
Expand Down Expand Up @@ -415,6 +468,43 @@ JNIEXPORT void JNICALL Java_com_tidesdb_ColumnFamily_nativeFlushMemtable(JNIEnv
}
}

JNIEXPORT jboolean JNICALL Java_com_tidesdb_ColumnFamily_nativeIsFlushing(JNIEnv *env, jclass cls,
jlong handle)
{
tidesdb_column_family_t *cf = (tidesdb_column_family_t *)(uintptr_t)handle;
return tidesdb_is_flushing(cf) != 0;
}

JNIEXPORT jboolean JNICALL Java_com_tidesdb_ColumnFamily_nativeIsCompacting(JNIEnv *env, jclass cls,
jlong handle)
{
tidesdb_column_family_t *cf = (tidesdb_column_family_t *)(uintptr_t)handle;
return tidesdb_is_compacting(cf) != 0;
}

JNIEXPORT void JNICALL Java_com_tidesdb_ColumnFamily_nativeUpdateRuntimeConfig(
JNIEnv *env, jclass cls, jlong handle, jlong writeBufferSize, jint skipListMaxLevel,
jfloat skipListProbability, jdouble bloomFPR, jint indexSampleRatio, jint syncMode,
jlong syncIntervalUs, jboolean persistToDisk)
{
tidesdb_column_family_t *cf = (tidesdb_column_family_t *)(uintptr_t)handle;

tidesdb_column_family_config_t config = {.write_buffer_size = (size_t)writeBufferSize,
.skip_list_max_level = skipListMaxLevel,
.skip_list_probability = skipListProbability,
.bloom_fpr = bloomFPR,
.index_sample_ratio = indexSampleRatio,
.sync_mode = syncMode,
.sync_interval_us = (uint64_t)syncIntervalUs};

int result = tidesdb_cf_update_runtime_config(cf, &config, persistToDisk ? 1 : 0);

if (result != TDB_SUCCESS)
{
throwTidesDBException(env, result, getErrorMessage(result));
}
}

JNIEXPORT void JNICALL Java_com_tidesdb_Transaction_nativePut(JNIEnv *env, jclass cls, jlong handle,
jlong cfHandle, jbyteArray key,
jbyteArray value, jlong ttl)
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/tidesdb/ColumnFamily.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,68 @@ public void flushMemtable() throws TidesDBException {
nativeFlushMemtable(nativeHandle);
}

/**
* Checks if a flush operation is currently in progress for this column family.
*
* @return true if flushing is in progress
*/
public boolean isFlushing() {
return nativeIsFlushing(nativeHandle);
}

/**
* Checks if a compaction operation is currently in progress for this column family.
*
* @return true if compaction is in progress
*/
public boolean isCompacting() {
return nativeIsCompacting(nativeHandle);
}

/**
* Updates runtime-safe configuration settings for this column family.
* Configuration changes are applied to new operations only.
*
* <p>Updatable settings (safe to change at runtime):</p>
* <ul>
* <li>writeBufferSize - Memtable flush threshold</li>
* <li>skipListMaxLevel - Skip list level for new memtables</li>
* <li>skipListProbability - Skip list probability for new memtables</li>
* <li>bloomFPR - False positive rate for new SSTables</li>
* <li>indexSampleRatio - Index sampling ratio for new SSTables</li>
* <li>syncMode - Durability mode</li>
* <li>syncIntervalUs - Sync interval in microseconds</li>
* </ul>
*
* @param config the new configuration
* @param persistToDisk if true, saves changes to config.ini
* @throws TidesDBException if the update fails
*/
public void updateRuntimeConfig(ColumnFamilyConfig config, boolean persistToDisk) throws TidesDBException {
if (config == null) {
throw new IllegalArgumentException("Config cannot be null");
}
nativeUpdateRuntimeConfig(nativeHandle,
config.getWriteBufferSize(),
config.getSkipListMaxLevel(),
config.getSkipListProbability(),
config.getBloomFPR(),
config.getIndexSampleRatio(),
config.getSyncMode().getValue(),
config.getSyncIntervalUs(),
persistToDisk);
}

long getNativeHandle() {
return nativeHandle;
}

private static native Stats nativeGetStats(long handle) throws TidesDBException;
private static native void nativeCompact(long handle) throws TidesDBException;
private static native void nativeFlushMemtable(long handle) throws TidesDBException;
private static native boolean nativeIsFlushing(long handle);
private static native boolean nativeIsCompacting(long handle);
private static native void nativeUpdateRuntimeConfig(long handle, long writeBufferSize,
int skipListMaxLevel, float skipListProbability, double bloomFPR, int indexSampleRatio,
int syncMode, long syncIntervalUs, boolean persistToDisk) throws TidesDBException;
}
48 changes: 24 additions & 24 deletions src/main/java/com/tidesdb/ColumnFamilyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,26 @@ private ColumnFamilyConfig(Builder builder) {
*/
public static ColumnFamilyConfig defaultConfig() {
return new Builder()
.writeBufferSize(64 * 1024 * 1024)
.writeBufferSize(128 * 1024 * 1024)
.levelSizeRatio(10)
.minLevels(4)
.minLevels(5)
.dividingLevelOffset(2)
.klogValueThreshold(1024)
.compressionAlgorithm(CompressionAlgorithm.NO_COMPRESSION)
.enableBloomFilter(false)
.klogValueThreshold(512)
.compressionAlgorithm(CompressionAlgorithm.LZ4_COMPRESSION)
.enableBloomFilter(true)
.bloomFPR(0.01)
.enableBlockIndexes(false)
.indexSampleRatio(16)
.blockIndexPrefixLen(4)
.syncMode(SyncMode.SYNC_NONE)
.syncIntervalUs(0)
.enableBlockIndexes(true)
.indexSampleRatio(1)
.blockIndexPrefixLen(16)
.syncMode(SyncMode.SYNC_FULL)
.syncIntervalUs(1000000)
.comparatorName("")
.skipListMaxLevel(12)
.skipListProbability(0.25f)
.defaultIsolationLevel(IsolationLevel.READ_COMMITTED)
.minDiskSpace(1024 * 1024 * 1024)
.minDiskSpace(100 * 1024 * 1024)
.l1FileCountTrigger(4)
.l0QueueStallThreshold(8)
.l0QueueStallThreshold(20)
.build();
}

Expand Down Expand Up @@ -131,26 +131,26 @@ public static Builder builder() {
* Builder for ColumnFamilyConfig.
*/
public static class Builder {
private long writeBufferSize = 64 * 1024 * 1024;
private long writeBufferSize = 128 * 1024 * 1024;
private long levelSizeRatio = 10;
private int minLevels = 4;
private int minLevels = 5;
private int dividingLevelOffset = 2;
private long klogValueThreshold = 1024;
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.NO_COMPRESSION;
private boolean enableBloomFilter = false;
private long klogValueThreshold = 512;
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.LZ4_COMPRESSION;
private boolean enableBloomFilter = true;
private double bloomFPR = 0.01;
private boolean enableBlockIndexes = false;
private int indexSampleRatio = 16;
private int blockIndexPrefixLen = 4;
private SyncMode syncMode = SyncMode.SYNC_NONE;
private long syncIntervalUs = 0;
private boolean enableBlockIndexes = true;
private int indexSampleRatio = 1;
private int blockIndexPrefixLen = 16;
private SyncMode syncMode = SyncMode.SYNC_FULL;
private long syncIntervalUs = 1000000;
private String comparatorName = "";
private int skipListMaxLevel = 12;
private float skipListProbability = 0.25f;
private IsolationLevel defaultIsolationLevel = IsolationLevel.READ_COMMITTED;
private long minDiskSpace = 1024 * 1024 * 1024;
private long minDiskSpace = 100 * 1024 * 1024;
private int l1FileCountTrigger = 4;
private int l0QueueStallThreshold = 8;
private int l0QueueStallThreshold = 20;

public Builder writeBufferSize(long writeBufferSize) {
this.writeBufferSize = writeBufferSize;
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/com/tidesdb/CompressionAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
*/
public enum CompressionAlgorithm {
NO_COMPRESSION(0),
LZ4_COMPRESSION(1),
ZSTD_COMPRESSION(2),
LZ4_FAST_COMPRESSION(3);
SNAPPY_COMPRESSION(1),
LZ4_COMPRESSION(2),
ZSTD_COMPRESSION(3),
LZ4_FAST_COMPRESSION(4);

private final int value;

Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/tidesdb/TidesDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,39 @@ public void registerComparator(String name, String context) throws TidesDBExcept
nativeRegisterComparator(nativeHandle, name, context);
}

/**
* Creates an on-disk snapshot of the database without blocking normal reads/writes.
*
* @param dir the backup directory (must be non-existent or empty)
* @throws TidesDBException if the backup fails
*/
public void backup(String dir) throws TidesDBException {
checkNotClosed();
if (dir == null || dir.isEmpty()) {
throw new IllegalArgumentException("Backup directory cannot be null or empty");
}
nativeBackup(nativeHandle, dir);
}

/**
* Atomically renames a column family and its underlying directory.
* The operation waits for any in-progress flush or compaction to complete before renaming.
*
* @param oldName the current column family name
* @param newName the new column family name
* @throws TidesDBException if the rename fails
*/
public void renameColumnFamily(String oldName, String newName) throws TidesDBException {
checkNotClosed();
if (oldName == null || oldName.isEmpty()) {
throw new IllegalArgumentException("Old column family name cannot be null or empty");
}
if (newName == null || newName.isEmpty()) {
throw new IllegalArgumentException("New column family name cannot be null or empty");
}
nativeRenameColumnFamily(nativeHandle, oldName, newName);
}

private void checkNotClosed() {
if (closed) {
throw new IllegalStateException("TidesDB instance is closed");
Expand Down Expand Up @@ -247,4 +280,8 @@ private static native void nativeCreateColumnFamily(long handle, String name,
private static native CacheStats nativeGetCacheStats(long handle) throws TidesDBException;

private static native void nativeRegisterComparator(long handle, String name, String context) throws TidesDBException;

private static native void nativeBackup(long handle, String dir) throws TidesDBException;

private static native void nativeRenameColumnFamily(long handle, String oldName, String newName) throws TidesDBException;
}
24 changes: 12 additions & 12 deletions src/main/java/com/tidesdb/TidesDBException.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ public class TidesDBException extends Exception {
* Error codes from TidesDB.
*/
public static final int ERR_SUCCESS = 0;
public static final int ERR_MEMORY = 1;
public static final int ERR_INVALID_ARGS = 2;
public static final int ERR_NOT_FOUND = 3;
public static final int ERR_IO = 4;
public static final int ERR_CORRUPTION = 5;
public static final int ERR_EXISTS = 6;
public static final int ERR_CONFLICT = 7;
public static final int ERR_TOO_LARGE = 8;
public static final int ERR_MEMORY_LIMIT = 9;
public static final int ERR_INVALID_DB = 10;
public static final int ERR_UNKNOWN = 11;
public static final int ERR_LOCKED = 12;
public static final int ERR_MEMORY = -1;
public static final int ERR_INVALID_ARGS = -2;
public static final int ERR_NOT_FOUND = -3;
public static final int ERR_IO = -4;
public static final int ERR_CORRUPTION = -5;
public static final int ERR_EXISTS = -6;
public static final int ERR_CONFLICT = -7;
public static final int ERR_TOO_LARGE = -8;
public static final int ERR_MEMORY_LIMIT = -9;
public static final int ERR_INVALID_DB = -10;
public static final int ERR_UNKNOWN = -11;
public static final int ERR_LOCKED = -12;

public TidesDBException(String message) {
super(message);
Expand Down
Loading