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
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,3 @@ Multiple licenses apply:
## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

- [Discord](https://discord.gg/tWEmjR66cy)
- [GitHub Issues](https://github.com/tidesdb/tidesdb-java/issues)
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.6.8</version>
<version>0.7.0</version>
<packaging>jar</packaging>

<name>TidesDB Java</name>
Expand Down
24 changes: 22 additions & 2 deletions src/main/c/com_tidesdb_TidesDB.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCreateColumnFamily(
jboolean enableBlockIndexes, jint indexSampleRatio, jint blockIndexPrefixLen, jint syncMode,
jlong syncIntervalUs, jstring comparatorName, jint skipListMaxLevel, jfloat skipListProbability,
jint defaultIsolationLevel, jlong minDiskSpace, jint l1FileCountTrigger,
jint l0QueueStallThreshold, jboolean useBtree, jlong objectTargetFileSize,
jint l0QueueStallThreshold, jboolean useBtree,
jboolean objectLazyCompaction, jboolean objectPrefetchCompaction)
{
tidesdb_t *db = (tidesdb_t *)(uintptr_t)handle;
Expand Down Expand Up @@ -227,7 +227,6 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCreateColumnFamily(
.l1_file_count_trigger = l1FileCountTrigger,
.l0_queue_stall_threshold = l0QueueStallThreshold,
.use_btree = useBtree ? 1 : 0,
.object_target_file_size = (size_t)objectTargetFileSize,
.object_lazy_compaction = objectLazyCompaction ? 1 : 0,
.object_prefetch_compaction = objectPrefetchCompaction ? 1 : 0};

Expand Down Expand Up @@ -724,6 +723,27 @@ JNIEXPORT void JNICALL Java_com_tidesdb_Transaction_nativeDelete(JNIEnv *env, jc
}
}

JNIEXPORT void JNICALL Java_com_tidesdb_Transaction_nativeSingleDelete(JNIEnv *env, jclass cls,
jlong handle,
jlong cfHandle,
jbyteArray key)
{
tidesdb_txn_t *txn = (tidesdb_txn_t *)(uintptr_t)handle;
tidesdb_column_family_t *cf = (tidesdb_column_family_t *)(uintptr_t)cfHandle;

jsize keyLen = (*env)->GetArrayLength(env, key);
jbyte *keyBytes = (*env)->GetByteArrayElements(env, key, NULL);

int result = tidesdb_txn_single_delete(txn, cf, (uint8_t *)keyBytes, keyLen);

(*env)->ReleaseByteArrayElements(env, key, keyBytes, JNI_ABORT);

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

JNIEXPORT void JNICALL Java_com_tidesdb_Transaction_nativeCommit(JNIEnv *env, jclass cls,
jlong handle)
{
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/tidesdb/ColumnFamily.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ public void syncWal() throws TidesDBException {

/**
* Estimates the computational cost of iterating between two keys in this column family.
* The returned value is an opaque double meaningful only for comparison with other
* The returned value is an opaque double - meaningful only for comparison with other
* values from the same method. Uses only in-memory metadata and performs no disk I/O.
* Key order does not matter the method normalizes the range internally.
* Key order does not matter - the method normalizes the range internally.
*
* @param keyA first key (bound of range)
* @param keyB second key (bound of range)
Expand Down
10 changes: 0 additions & 10 deletions src/main/java/com/tidesdb/ColumnFamilyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public class ColumnFamilyConfig {
private int l1FileCountTrigger;
private int l0QueueStallThreshold;
private boolean useBtree;
private long objectTargetFileSize;
private boolean objectLazyCompaction;
private boolean objectPrefetchCompaction;

Expand All @@ -70,7 +69,6 @@ private ColumnFamilyConfig(Builder builder) {
this.l1FileCountTrigger = builder.l1FileCountTrigger;
this.l0QueueStallThreshold = builder.l0QueueStallThreshold;
this.useBtree = builder.useBtree;
this.objectTargetFileSize = builder.objectTargetFileSize;
this.objectLazyCompaction = builder.objectLazyCompaction;
this.objectPrefetchCompaction = builder.objectPrefetchCompaction;
}
Expand Down Expand Up @@ -103,7 +101,6 @@ public static ColumnFamilyConfig defaultConfig() {
.l1FileCountTrigger(4)
.l0QueueStallThreshold(20)
.useBtree(false)
.objectTargetFileSize(0)
.objectLazyCompaction(false)
.objectPrefetchCompaction(true)
.build();
Expand Down Expand Up @@ -139,7 +136,6 @@ public static Builder builder() {
public int getL1FileCountTrigger() { return l1FileCountTrigger; }
public int getL0QueueStallThreshold() { return l0QueueStallThreshold; }
public boolean isUseBtree() { return useBtree; }
public long getObjectTargetFileSize() { return objectTargetFileSize; }
public boolean isObjectLazyCompaction() { return objectLazyCompaction; }
public boolean isObjectPrefetchCompaction() { return objectPrefetchCompaction; }

Expand Down Expand Up @@ -168,7 +164,6 @@ public static class Builder {
private int l1FileCountTrigger = 4;
private int l0QueueStallThreshold = 20;
private boolean useBtree = false;
private long objectTargetFileSize = 0;
private boolean objectLazyCompaction = false;
private boolean objectPrefetchCompaction = true;

Expand Down Expand Up @@ -277,11 +272,6 @@ public Builder useBtree(boolean useBtree) {
return this;
}

public Builder objectTargetFileSize(long objectTargetFileSize) {
this.objectTargetFileSize = objectTargetFileSize;
return this;
}

public Builder objectLazyCompaction(boolean objectLazyCompaction) {
this.objectLazyCompaction = objectLazyCompaction;
return this;
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/tidesdb/TidesDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ public void createColumnFamily(String name, ColumnFamilyConfig config) throws Ti
config.getL1FileCountTrigger(),
config.getL0QueueStallThreshold(),
config.isUseBtree(),
config.getObjectTargetFileSize(),
config.isObjectLazyCompaction(),
config.isObjectPrefetchCompaction()
);
Expand Down Expand Up @@ -399,7 +398,7 @@ private static native void nativeCreateColumnFamily(long handle, String name,
int syncMode, long syncIntervalUs, String comparatorName, int skipListMaxLevel,
float skipListProbability, int defaultIsolationLevel, long minDiskSpace,
int l1FileCountTrigger, int l0QueueStallThreshold, boolean useBtree,
long objectTargetFileSize, boolean objectLazyCompaction,
boolean objectLazyCompaction,
boolean objectPrefetchCompaction) throws TidesDBException;

private static native void nativeDropColumnFamily(long handle, String name) throws TidesDBException;
Expand Down
29 changes: 28 additions & 1 deletion src/main/java/com/tidesdb/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,33 @@ public void delete(ColumnFamily cf, byte[] key) throws TidesDBException {
}
nativeDelete(nativeHandle, cf.getNativeHandle(), key);
}


/**
* Writes a single-delete tombstone for a key. Has the same read semantics as
* {@link #delete}, but lets compaction drop the put and tombstone together as
* soon as both appear in the same merge input.
*
* Caller contract: between any two single-deletes on the same key (and from
* the start of the key's history to its first single-delete) the key has been
* put at most once. The engine cannot verify this; violating it can leave
* older puts visible after the single-delete. Use only for workloads that
* insert each key once and delete it once. When in doubt, prefer {@link #delete}.
*
* @param cf the column family
* @param key the key
* @throws TidesDBException if the single-delete fails
*/
public void singleDelete(ColumnFamily cf, byte[] key) throws TidesDBException {
checkNotFreed();
if (cf == null) {
throw new IllegalArgumentException("Column family cannot be null");
}
if (key == null || key.length == 0) {
throw new IllegalArgumentException("Key cannot be null");
}
nativeSingleDelete(nativeHandle, cf.getNativeHandle(), key);
}

/**
* Commits the transaction.
*
Expand Down Expand Up @@ -234,6 +260,7 @@ long getNativeHandle() {
private static native void nativePut(long handle, long cfHandle, byte[] key, byte[] value, long ttl) throws TidesDBException;
private static native byte[] nativeGet(long handle, long cfHandle, byte[] key) throws TidesDBException;
private static native void nativeDelete(long handle, long cfHandle, byte[] key) throws TidesDBException;
private static native void nativeSingleDelete(long handle, long cfHandle, byte[] key) throws TidesDBException;
private static native void nativeCommit(long handle) throws TidesDBException;
private static native void nativeRollback(long handle) throws TidesDBException;
private static native void nativeSavepoint(long handle, String name) throws TidesDBException;
Expand Down
84 changes: 77 additions & 7 deletions src/test/java/com/tidesdb/TidesDBTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ void testCommitHookClear() throws TidesDBException {
return 0;
});

// First commit hook should fire
// First commit - hook should fire
try (Transaction txn = db.beginTransaction()) {
txn.put(cf, "key1".getBytes(), "value1".getBytes());
txn.commit();
Expand All @@ -1034,7 +1034,7 @@ void testCommitHookClear() throws TidesDBException {
// Clear the hook
cf.clearCommitHook();

// Second commit hook should NOT fire
// Second commit - hook should NOT fire
try (Transaction txn = db.beginTransaction()) {
txn.put(cf, "key2".getBytes(), "value2".getBytes());
txn.commit();
Expand Down Expand Up @@ -1505,21 +1505,91 @@ void testTransactionResetNullIsolation() throws TidesDBException {
.blockCacheSize(64 * 1024 * 1024)
.maxOpenSSTables(256)
.build();

try (TidesDB db = TidesDB.open(config)) {
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.defaultConfig();
db.createColumnFamily("test_cf", cfConfig);

ColumnFamily cf = db.getColumnFamily("test_cf");

Transaction txn = db.beginTransaction();
txn.put(cf, "key1".getBytes(), "value1".getBytes());
txn.commit();

// Null isolation level should throw IllegalArgumentException
assertThrows(IllegalArgumentException.class, () -> txn.reset(null));

txn.free();
}
}

@Test
@Order(42)
void testTransactionSingleDelete() throws TidesDBException {
Config config = Config.builder(tempDir.resolve("testdb_single_delete").toString())
.numFlushThreads(2)
.numCompactionThreads(2)
.logLevel(LogLevel.INFO)
.blockCacheSize(64 * 1024 * 1024)
.maxOpenSSTables(256)
.build();

try (TidesDB db = TidesDB.open(config)) {
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.defaultConfig();
db.createColumnFamily("test_cf", cfConfig);

ColumnFamily cf = db.getColumnFamily("test_cf");

byte[] key = "single_key".getBytes(StandardCharsets.UTF_8);
byte[] value = "single_value".getBytes(StandardCharsets.UTF_8);

try (Transaction txn = db.beginTransaction()) {
txn.put(cf, key, value);
txn.commit();
}

try (Transaction txn = db.beginTransaction()) {
byte[] result = txn.get(cf, key);
assertNotNull(result);
assertArrayEquals(value, result);
}

try (Transaction txn = db.beginTransaction()) {
txn.singleDelete(cf, key);
txn.commit();
}

try (Transaction txn = db.beginTransaction()) {
assertThrows(TidesDBException.class, () -> txn.get(cf, key));
}
}
}

@Test
@Order(43)
void testTransactionSingleDeleteNullArgs() throws TidesDBException {
Config config = Config.builder(tempDir.resolve("testdb_single_delete_null").toString())
.numFlushThreads(2)
.numCompactionThreads(2)
.logLevel(LogLevel.INFO)
.blockCacheSize(64 * 1024 * 1024)
.maxOpenSSTables(256)
.build();

try (TidesDB db = TidesDB.open(config)) {
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.defaultConfig();
db.createColumnFamily("test_cf", cfConfig);

ColumnFamily cf = db.getColumnFamily("test_cf");

try (Transaction txn = db.beginTransaction()) {
assertThrows(IllegalArgumentException.class,
() -> txn.singleDelete(null, "k".getBytes()));
assertThrows(IllegalArgumentException.class,
() -> txn.singleDelete(cf, null));
assertThrows(IllegalArgumentException.class,
() -> txn.singleDelete(cf, new byte[0]));
}
}
}
}
Loading