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.3.2</version>
<version>0.4.0</version>
<packaging>jar</packaging>

<name>TidesDB Java</name>
Expand Down
11 changes: 7 additions & 4 deletions src/main/c/com_tidesdb_TidesDB.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,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)
jint l0QueueStallThreshold, jboolean useBtree)
{
tidesdb_t *db = (tidesdb_t *)(uintptr_t)handle;
const char *cfName = (*env)->GetStringUTFChars(env, name, NULL);
Expand Down Expand Up @@ -161,7 +161,8 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCreateColumnFamily(
.default_isolation_level = (tidesdb_isolation_level_t)defaultIsolationLevel,
.min_disk_space = (uint64_t)minDiskSpace,
.l1_file_count_trigger = l1FileCountTrigger,
.l0_queue_stall_threshold = l0QueueStallThreshold};
.l0_queue_stall_threshold = l0QueueStallThreshold,
.use_btree = useBtree ? 1 : 0};

memset(config.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (compName != NULL && strlen(compName) > 0)
Expand Down Expand Up @@ -448,13 +449,15 @@ JNIEXPORT jobject JNICALL Java_com_tidesdb_ColumnFamily_nativeGetStats(JNIEnv *e

jclass statsClass = (*env)->FindClass(env, "com/tidesdb/Stats");
jmethodID constructor = (*env)->GetMethodID(env, statsClass, "<init>",
"(IJ[J[ILcom/tidesdb/ColumnFamilyConfig;JJDD[JDD)V");
"(IJ[J[ILcom/tidesdb/ColumnFamilyConfig;JJDD[JDDZJID)V");

jobject statsObj = (*env)->NewObject(env, statsClass, constructor, stats->num_levels,
(jlong)stats->memtable_size, levelSizes, levelNumSSTables,
NULL, (jlong)stats->total_keys, (jlong)stats->total_data_size,
stats->avg_key_size, stats->avg_value_size, levelKeyCounts,
stats->read_amp, stats->hit_rate);
stats->read_amp, stats->hit_rate,
stats->use_btree != 0, (jlong)stats->btree_total_nodes,
(jint)stats->btree_max_height, stats->btree_avg_height);

tidesdb_free_stats(stats);

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/tidesdb/ColumnFamilyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class ColumnFamilyConfig {
private long minDiskSpace;
private int l1FileCountTrigger;
private int l0QueueStallThreshold;
private boolean useBtree;

private ColumnFamilyConfig(Builder builder) {
this.writeBufferSize = builder.writeBufferSize;
Expand All @@ -65,6 +66,7 @@ private ColumnFamilyConfig(Builder builder) {
this.minDiskSpace = builder.minDiskSpace;
this.l1FileCountTrigger = builder.l1FileCountTrigger;
this.l0QueueStallThreshold = builder.l0QueueStallThreshold;
this.useBtree = builder.useBtree;
}

/**
Expand Down Expand Up @@ -94,6 +96,7 @@ public static ColumnFamilyConfig defaultConfig() {
.minDiskSpace(100 * 1024 * 1024)
.l1FileCountTrigger(4)
.l0QueueStallThreshold(20)
.useBtree(false)
.build();
}

Expand Down Expand Up @@ -126,6 +129,7 @@ public static Builder builder() {
public long getMinDiskSpace() { return minDiskSpace; }
public int getL1FileCountTrigger() { return l1FileCountTrigger; }
public int getL0QueueStallThreshold() { return l0QueueStallThreshold; }
public boolean isUseBtree() { return useBtree; }

/**
* Builder for ColumnFamilyConfig.
Expand All @@ -151,6 +155,7 @@ public static class Builder {
private long minDiskSpace = 100 * 1024 * 1024;
private int l1FileCountTrigger = 4;
private int l0QueueStallThreshold = 20;
private boolean useBtree = false;

public Builder writeBufferSize(long writeBufferSize) {
this.writeBufferSize = writeBufferSize;
Expand Down Expand Up @@ -252,6 +257,11 @@ public Builder l0QueueStallThreshold(int l0QueueStallThreshold) {
return this;
}

public Builder useBtree(boolean useBtree) {
this.useBtree = useBtree;
return this;
}

public ColumnFamilyConfig build() {
return new ColumnFamilyConfig(this);
}
Expand Down
56 changes: 55 additions & 1 deletion src/main/java/com/tidesdb/Stats.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ public class Stats {
private final long[] levelKeyCounts;
private final double readAmp;
private final double hitRate;
private final boolean useBtree;
private final long btreeTotalNodes;
private final int btreeMaxHeight;
private final double btreeAvgHeight;

public Stats(int numLevels, long memtableSize, long[] levelSizes, int[] levelNumSSTables,
ColumnFamilyConfig config, long totalKeys, long totalDataSize,
double avgKeySize, double avgValueSize, long[] levelKeyCounts,
double readAmp, double hitRate) {
double readAmp, double hitRate, boolean useBtree, long btreeTotalNodes,
int btreeMaxHeight, double btreeAvgHeight) {
this.numLevels = numLevels;
this.memtableSize = memtableSize;
this.levelSizes = levelSizes;
Expand All @@ -52,6 +57,10 @@ public Stats(int numLevels, long memtableSize, long[] levelSizes, int[] levelNum
this.levelKeyCounts = levelKeyCounts;
this.readAmp = readAmp;
this.hitRate = hitRate;
this.useBtree = useBtree;
this.btreeTotalNodes = btreeTotalNodes;
this.btreeMaxHeight = btreeMaxHeight;
this.btreeAvgHeight = btreeAvgHeight;
}

/**
Expand Down Expand Up @@ -162,6 +171,45 @@ public double getHitRate() {
return hitRate;
}

/**
* Returns whether this column family uses B+tree format.
*
* @return true if B+tree format is used
*/
public boolean isUseBtree() {
return useBtree;
}

/**
* Gets the total number of B+tree nodes across all SSTables.
* Only populated when useBtree is true.
*
* @return total B+tree nodes
*/
public long getBtreeTotalNodes() {
return btreeTotalNodes;
}

/**
* Gets the maximum B+tree height across all SSTables.
* Only populated when useBtree is true.
*
* @return maximum tree height
*/
public int getBtreeMaxHeight() {
return btreeMaxHeight;
}

/**
* Gets the average B+tree height across all SSTables.
* Only populated when useBtree is true.
*
* @return average tree height
*/
public double getBtreeAvgHeight() {
return btreeAvgHeight;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expand All @@ -173,6 +221,12 @@ public String toString() {
sb.append(", avgValueSize=").append(avgValueSize);
sb.append(", readAmp=").append(readAmp);
sb.append(", hitRate=").append(hitRate);
sb.append(", useBtree=").append(useBtree);
if (useBtree) {
sb.append(", btreeTotalNodes=").append(btreeTotalNodes);
sb.append(", btreeMaxHeight=").append(btreeMaxHeight);
sb.append(", btreeAvgHeight=").append(btreeAvgHeight);
}
if (levelSizes != null) {
sb.append(", levelSizes=[");
for (int i = 0; i < levelSizes.length; i++) {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/tidesdb/TidesDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public void createColumnFamily(String name, ColumnFamilyConfig config) throws Ti
config.getDefaultIsolationLevel().getValue(),
config.getMinDiskSpace(),
config.getL1FileCountTrigger(),
config.getL0QueueStallThreshold()
config.getL0QueueStallThreshold(),
config.isUseBtree()
);
}

Expand Down Expand Up @@ -268,7 +269,7 @@ private static native void nativeCreateColumnFamily(long handle, String name,
double bloomFPR, boolean enableBlockIndexes, int indexSampleRatio, int blockIndexPrefixLen,
int syncMode, long syncIntervalUs, String comparatorName, int skipListMaxLevel,
float skipListProbability, int defaultIsolationLevel, long minDiskSpace,
int l1FileCountTrigger, int l0QueueStallThreshold) throws TidesDBException;
int l1FileCountTrigger, int l0QueueStallThreshold, boolean useBtree) throws TidesDBException;

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

Expand Down
110 changes: 110 additions & 0 deletions src/test/java/com/tidesdb/TidesDBTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,13 @@ void testColumnFamilyStats() throws TidesDBException {
Stats stats = cf.getStats();
assertNotNull(stats);
assertTrue(stats.getNumLevels() >= 0);
assertTrue(stats.getTotalKeys() >= 0);
assertTrue(stats.getTotalDataSize() >= 0);
assertTrue(stats.getAvgKeySize() >= 0);
assertTrue(stats.getAvgValueSize() >= 0);
assertTrue(stats.getReadAmp() >= 0);
assertTrue(stats.getHitRate() >= 0.0 && stats.getHitRate() <= 1.0);
assertFalse(stats.isUseBtree());
}
}

Expand Down Expand Up @@ -446,6 +453,109 @@ void testCustomColumnFamilyConfig() throws TidesDBException {

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

try (TidesDB db = TidesDB.open(config)) {
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.builder()
.writeBufferSize(128 * 1024 * 1024)
.levelSizeRatio(10)
.minLevels(5)
.compressionAlgorithm(CompressionAlgorithm.LZ4_COMPRESSION)
.enableBloomFilter(true)
.bloomFPR(0.01)
.enableBlockIndexes(true)
.syncMode(SyncMode.SYNC_FULL)
.useBtree(true)
.build();

db.createColumnFamily("btree_cf", cfConfig);

ColumnFamily cf = db.getColumnFamily("btree_cf");
assertNotNull(cf);
assertEquals("btree_cf", cf.getName());

try (Transaction txn = db.beginTransaction()) {
for (int i = 0; i < 100; i++) {
txn.put(cf, ("key" + i).getBytes(), ("value" + i).getBytes());
}
txn.commit();
}

try (Transaction txn = db.beginTransaction()) {
byte[] result = txn.get(cf, "key50".getBytes());
assertNotNull(result);
assertArrayEquals("value50".getBytes(), result);
}

Stats stats = cf.getStats();
assertNotNull(stats);
assertTrue(stats.isUseBtree());
assertTrue(stats.getBtreeTotalNodes() >= 0);
assertTrue(stats.getBtreeMaxHeight() >= 0);
assertTrue(stats.getBtreeAvgHeight() >= 0.0);
}
}

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

try (TidesDB db = TidesDB.open(config)) {
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.builder()
.writeBufferSize(128 * 1024 * 1024)
.compressionAlgorithm(CompressionAlgorithm.LZ4_COMPRESSION)
.enableBloomFilter(true)
.useBtree(true)
.build();

db.createColumnFamily("btree_iter_cf", cfConfig);

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

try (Transaction txn = db.beginTransaction()) {
for (int i = 0; i < 10; i++) {
String key = String.format("key%02d", i);
String value = "value" + i;
txn.put(cf, key.getBytes(), value.getBytes());
}
txn.commit();
}

try (Transaction txn = db.beginTransaction()) {
try (TidesDBIterator iter = txn.newIterator(cf)) {
iter.seekToFirst();

int count = 0;
while (iter.isValid()) {
byte[] key = iter.key();
byte[] value = iter.value();
assertNotNull(key);
assertNotNull(value);
count++;
iter.next();
}
assertEquals(10, count);
}
}
}
}

@Test
@Order(15)
void testTransactionPutGetDeleteBadKey() throws TidesDBException {
Config config = Config.builder(tempDir.resolve("testdb3").toString())
.numFlushThreads(2)
Expand Down
Loading