diff --git a/pom.xml b/pom.xml
index 2a7c501..8d599e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.tidesdb
tidesdb-java
- 0.6.7
+ 0.6.8
jar
TidesDB Java
diff --git a/src/main/c/com_tidesdb_TidesDB.c b/src/main/c/com_tidesdb_TidesDB.c
index d885fd1..6ff9b0c 100644
--- a/src/main/c/com_tidesdb_TidesDB.c
+++ b/src/main/c/com_tidesdb_TidesDB.c
@@ -81,7 +81,12 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeOpen(
jlong logTruncationAt, jlong maxMemoryUsage, jboolean unifiedMemtable,
jlong unifiedMemtableWriteBufferSize, jint unifiedMemtableSkipListMaxLevel,
jfloat unifiedMemtableSkipListProbability, jint unifiedMemtableSyncMode,
- jlong unifiedMemtableSyncIntervalUs)
+ jlong unifiedMemtableSyncIntervalUs, jstring objectStoreFsPath, jstring oscLocalCachePath,
+ jlong oscLocalCacheMaxBytes, jboolean oscCacheOnRead, jboolean oscCacheOnWrite,
+ jint oscMaxConcurrentUploads, jint oscMaxConcurrentDownloads, jlong oscMultipartThreshold,
+ jlong oscMultipartPartSize, jboolean oscSyncManifestToObject, jboolean oscReplicateWal,
+ jboolean oscWalUploadSync, jlong oscWalSyncThresholdBytes, jboolean oscWalSyncOnCommit,
+ jboolean oscReplicaMode, jlong oscReplicaSyncIntervalUs, jboolean oscReplicaReplayWal)
{
const char *path = (*env)->GetStringUTFChars(env, dbPath, NULL);
if (path == NULL)
@@ -90,6 +95,43 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeOpen(
return 0;
}
+ /* object store connector (filesystem) */
+ tidesdb_objstore_t *obj_store = NULL;
+ const char *fs_path = NULL;
+ if (objectStoreFsPath != NULL)
+ {
+ fs_path = (*env)->GetStringUTFChars(env, objectStoreFsPath, NULL);
+ if (fs_path != NULL)
+ {
+ obj_store = tidesdb_objstore_fs_create(fs_path);
+ }
+ }
+
+ /* object store behavior config */
+ const char *cache_path = NULL;
+ if (oscLocalCachePath != NULL)
+ {
+ cache_path = (*env)->GetStringUTFChars(env, oscLocalCachePath, NULL);
+ }
+
+ tidesdb_objstore_config_t os_cfg = {
+ .local_cache_path = cache_path,
+ .local_cache_max_bytes = (size_t)oscLocalCacheMaxBytes,
+ .cache_on_read = oscCacheOnRead ? 1 : 0,
+ .cache_on_write = oscCacheOnWrite ? 1 : 0,
+ .max_concurrent_uploads = oscMaxConcurrentUploads,
+ .max_concurrent_downloads = oscMaxConcurrentDownloads,
+ .multipart_threshold = (size_t)oscMultipartThreshold,
+ .multipart_part_size = (size_t)oscMultipartPartSize,
+ .sync_manifest_to_object = oscSyncManifestToObject ? 1 : 0,
+ .replicate_wal = oscReplicateWal ? 1 : 0,
+ .wal_upload_sync = oscWalUploadSync ? 1 : 0,
+ .wal_sync_threshold_bytes = (size_t)oscWalSyncThresholdBytes,
+ .wal_sync_on_commit = oscWalSyncOnCommit ? 1 : 0,
+ .replica_mode = oscReplicaMode ? 1 : 0,
+ .replica_sync_interval_us = (uint64_t)oscReplicaSyncIntervalUs,
+ .replica_replay_wal = oscReplicaReplayWal ? 1 : 0};
+
tidesdb_config_t config = {
.db_path = (char *)path,
.num_flush_threads = numFlushThreads,
@@ -105,12 +147,22 @@ JNIEXPORT jlong JNICALL Java_com_tidesdb_TidesDB_nativeOpen(
.unified_memtable_skip_list_max_level = unifiedMemtableSkipListMaxLevel,
.unified_memtable_skip_list_probability = unifiedMemtableSkipListProbability,
.unified_memtable_sync_mode = unifiedMemtableSyncMode,
- .unified_memtable_sync_interval_us = (uint64_t)unifiedMemtableSyncIntervalUs};
+ .unified_memtable_sync_interval_us = (uint64_t)unifiedMemtableSyncIntervalUs,
+ .object_store = obj_store,
+ .object_store_config = obj_store != NULL ? &os_cfg : NULL};
tidesdb_t *db = NULL;
int result = tidesdb_open(&config, &db);
(*env)->ReleaseStringUTFChars(env, dbPath, path);
+ if (fs_path != NULL)
+ {
+ (*env)->ReleaseStringUTFChars(env, objectStoreFsPath, fs_path);
+ }
+ if (cache_path != NULL)
+ {
+ (*env)->ReleaseStringUTFChars(env, oscLocalCachePath, cache_path);
+ }
if (result != TDB_SUCCESS)
{
@@ -137,7 +189,8 @@ 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)
+ jint l0QueueStallThreshold, jboolean useBtree, jlong objectTargetFileSize,
+ jboolean objectLazyCompaction, jboolean objectPrefetchCompaction)
{
tidesdb_t *db = (tidesdb_t *)(uintptr_t)handle;
const char *cfName = (*env)->GetStringUTFChars(env, name, NULL);
@@ -173,7 +226,10 @@ JNIEXPORT void JNICALL Java_com_tidesdb_TidesDB_nativeCreateColumnFamily(
.min_disk_space = (uint64_t)minDiskSpace,
.l1_file_count_trigger = l1FileCountTrigger,
.l0_queue_stall_threshold = l0QueueStallThreshold,
- .use_btree = useBtree ? 1 : 0};
+ .use_btree = useBtree ? 1 : 0,
+ .object_target_file_size = (size_t)objectTargetFileSize,
+ .object_lazy_compaction = objectLazyCompaction ? 1 : 0,
+ .object_prefetch_compaction = objectPrefetchCompaction ? 1 : 0};
memset(config.comparator_name, 0, TDB_MAX_COMPARATOR_NAME);
if (compName != NULL && strlen(compName) > 0)
diff --git a/src/main/java/com/tidesdb/ColumnFamilyConfig.java b/src/main/java/com/tidesdb/ColumnFamilyConfig.java
index 04d6471..8d421fb 100644
--- a/src/main/java/com/tidesdb/ColumnFamilyConfig.java
+++ b/src/main/java/com/tidesdb/ColumnFamilyConfig.java
@@ -44,7 +44,10 @@ public class ColumnFamilyConfig {
private int l1FileCountTrigger;
private int l0QueueStallThreshold;
private boolean useBtree;
-
+ private long objectTargetFileSize;
+ private boolean objectLazyCompaction;
+ private boolean objectPrefetchCompaction;
+
private ColumnFamilyConfig(Builder builder) {
this.writeBufferSize = builder.writeBufferSize;
this.levelSizeRatio = builder.levelSizeRatio;
@@ -67,6 +70,9 @@ 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;
}
/**
@@ -97,6 +103,9 @@ public static ColumnFamilyConfig defaultConfig() {
.l1FileCountTrigger(4)
.l0QueueStallThreshold(20)
.useBtree(false)
+ .objectTargetFileSize(0)
+ .objectLazyCompaction(false)
+ .objectPrefetchCompaction(true)
.build();
}
@@ -130,7 +139,10 @@ 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; }
+
/**
* Builder for ColumnFamilyConfig.
*/
@@ -156,7 +168,10 @@ 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;
+
public Builder writeBufferSize(long writeBufferSize) {
this.writeBufferSize = writeBufferSize;
return this;
@@ -261,7 +276,22 @@ public Builder useBtree(boolean useBtree) {
this.useBtree = useBtree;
return this;
}
-
+
+ public Builder objectTargetFileSize(long objectTargetFileSize) {
+ this.objectTargetFileSize = objectTargetFileSize;
+ return this;
+ }
+
+ public Builder objectLazyCompaction(boolean objectLazyCompaction) {
+ this.objectLazyCompaction = objectLazyCompaction;
+ return this;
+ }
+
+ public Builder objectPrefetchCompaction(boolean objectPrefetchCompaction) {
+ this.objectPrefetchCompaction = objectPrefetchCompaction;
+ return this;
+ }
+
public ColumnFamilyConfig build() {
return new ColumnFamilyConfig(this);
}
diff --git a/src/main/java/com/tidesdb/Config.java b/src/main/java/com/tidesdb/Config.java
index b0fdd13..abf4ebe 100644
--- a/src/main/java/com/tidesdb/Config.java
+++ b/src/main/java/com/tidesdb/Config.java
@@ -38,6 +38,8 @@ public class Config {
private float unifiedMemtableSkipListProbability;
private int unifiedMemtableSyncMode;
private long unifiedMemtableSyncIntervalUs;
+ private String objectStoreFsPath;
+ private ObjectStoreConfig objectStoreConfig;
private Config(Builder builder) {
this.dbPath = builder.dbPath;
@@ -55,6 +57,8 @@ private Config(Builder builder) {
this.unifiedMemtableSkipListProbability = builder.unifiedMemtableSkipListProbability;
this.unifiedMemtableSyncMode = builder.unifiedMemtableSyncMode;
this.unifiedMemtableSyncIntervalUs = builder.unifiedMemtableSyncIntervalUs;
+ this.objectStoreFsPath = builder.objectStoreFsPath;
+ this.objectStoreConfig = builder.objectStoreConfig;
}
/**
@@ -145,6 +149,14 @@ public long getUnifiedMemtableSyncIntervalUs() {
return unifiedMemtableSyncIntervalUs;
}
+ public String getObjectStoreFsPath() {
+ return objectStoreFsPath;
+ }
+
+ public ObjectStoreConfig getObjectStoreConfig() {
+ return objectStoreConfig;
+ }
+
/**
* Builder for Config.
*/
@@ -164,6 +176,8 @@ public static class Builder {
private float unifiedMemtableSkipListProbability = 0;
private int unifiedMemtableSyncMode = 0;
private long unifiedMemtableSyncIntervalUs = 0;
+ private String objectStoreFsPath = null;
+ private ObjectStoreConfig objectStoreConfig = null;
public Builder dbPath(String dbPath) {
this.dbPath = dbPath;
@@ -240,6 +254,16 @@ public Builder unifiedMemtableSyncIntervalUs(long unifiedMemtableSyncIntervalUs)
return this;
}
+ public Builder objectStoreFsPath(String objectStoreFsPath) {
+ this.objectStoreFsPath = objectStoreFsPath;
+ return this;
+ }
+
+ public Builder objectStoreConfig(ObjectStoreConfig objectStoreConfig) {
+ this.objectStoreConfig = objectStoreConfig;
+ return this;
+ }
+
public Config build() {
validate();
return new Config(this);
diff --git a/src/main/java/com/tidesdb/ObjectStoreConfig.java b/src/main/java/com/tidesdb/ObjectStoreConfig.java
new file mode 100644
index 0000000..1e89bbd
--- /dev/null
+++ b/src/main/java/com/tidesdb/ObjectStoreConfig.java
@@ -0,0 +1,202 @@
+/**
+ *
+ * Copyright (C) TidesDB
+ *
+ * Original Author: Alex Gaetano Padula
+ *
+ * Licensed under the Mozilla Public License, v. 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.mozilla.org/en-US/MPL/2.0/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tidesdb;
+
+/**
+ * Configuration for object store mode behavior.
+ */
+public class ObjectStoreConfig {
+
+ private String localCachePath;
+ private long localCacheMaxBytes;
+ private boolean cacheOnRead;
+ private boolean cacheOnWrite;
+ private int maxConcurrentUploads;
+ private int maxConcurrentDownloads;
+ private long multipartThreshold;
+ private long multipartPartSize;
+ private boolean syncManifestToObject;
+ private boolean replicateWal;
+ private boolean walUploadSync;
+ private long walSyncThresholdBytes;
+ private boolean walSyncOnCommit;
+ private boolean replicaMode;
+ private long replicaSyncIntervalUs;
+ private boolean replicaReplayWal;
+
+ private ObjectStoreConfig(Builder builder) {
+ this.localCachePath = builder.localCachePath;
+ this.localCacheMaxBytes = builder.localCacheMaxBytes;
+ this.cacheOnRead = builder.cacheOnRead;
+ this.cacheOnWrite = builder.cacheOnWrite;
+ this.maxConcurrentUploads = builder.maxConcurrentUploads;
+ this.maxConcurrentDownloads = builder.maxConcurrentDownloads;
+ this.multipartThreshold = builder.multipartThreshold;
+ this.multipartPartSize = builder.multipartPartSize;
+ this.syncManifestToObject = builder.syncManifestToObject;
+ this.replicateWal = builder.replicateWal;
+ this.walUploadSync = builder.walUploadSync;
+ this.walSyncThresholdBytes = builder.walSyncThresholdBytes;
+ this.walSyncOnCommit = builder.walSyncOnCommit;
+ this.replicaMode = builder.replicaMode;
+ this.replicaSyncIntervalUs = builder.replicaSyncIntervalUs;
+ this.replicaReplayWal = builder.replicaReplayWal;
+ }
+
+ /**
+ * Creates a default object store configuration matching tidesdb_objstore_default_config().
+ *
+ * @return a new ObjectStoreConfig with default values
+ */
+ public static ObjectStoreConfig defaultConfig() {
+ return new Builder().build();
+ }
+
+ /**
+ * Creates a new builder for ObjectStoreConfig.
+ *
+ * @return a new Builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public String getLocalCachePath() { return localCachePath; }
+ public long getLocalCacheMaxBytes() { return localCacheMaxBytes; }
+ public boolean isCacheOnRead() { return cacheOnRead; }
+ public boolean isCacheOnWrite() { return cacheOnWrite; }
+ public int getMaxConcurrentUploads() { return maxConcurrentUploads; }
+ public int getMaxConcurrentDownloads() { return maxConcurrentDownloads; }
+ public long getMultipartThreshold() { return multipartThreshold; }
+ public long getMultipartPartSize() { return multipartPartSize; }
+ public boolean isSyncManifestToObject() { return syncManifestToObject; }
+ public boolean isReplicateWal() { return replicateWal; }
+ public boolean isWalUploadSync() { return walUploadSync; }
+ public long getWalSyncThresholdBytes() { return walSyncThresholdBytes; }
+ public boolean isWalSyncOnCommit() { return walSyncOnCommit; }
+ public boolean isReplicaMode() { return replicaMode; }
+ public long getReplicaSyncIntervalUs() { return replicaSyncIntervalUs; }
+ public boolean isReplicaReplayWal() { return replicaReplayWal; }
+
+ /**
+ * Builder for ObjectStoreConfig.
+ */
+ public static class Builder {
+ private String localCachePath = null;
+ private long localCacheMaxBytes = 0;
+ private boolean cacheOnRead = true;
+ private boolean cacheOnWrite = true;
+ private int maxConcurrentUploads = 4;
+ private int maxConcurrentDownloads = 8;
+ private long multipartThreshold = 64 * 1024 * 1024;
+ private long multipartPartSize = 8 * 1024 * 1024;
+ private boolean syncManifestToObject = true;
+ private boolean replicateWal = true;
+ private boolean walUploadSync = false;
+ private long walSyncThresholdBytes = 1048576;
+ private boolean walSyncOnCommit = false;
+ private boolean replicaMode = false;
+ private long replicaSyncIntervalUs = 5000000;
+ private boolean replicaReplayWal = true;
+
+ public Builder localCachePath(String localCachePath) {
+ this.localCachePath = localCachePath;
+ return this;
+ }
+
+ public Builder localCacheMaxBytes(long localCacheMaxBytes) {
+ this.localCacheMaxBytes = localCacheMaxBytes;
+ return this;
+ }
+
+ public Builder cacheOnRead(boolean cacheOnRead) {
+ this.cacheOnRead = cacheOnRead;
+ return this;
+ }
+
+ public Builder cacheOnWrite(boolean cacheOnWrite) {
+ this.cacheOnWrite = cacheOnWrite;
+ return this;
+ }
+
+ public Builder maxConcurrentUploads(int maxConcurrentUploads) {
+ this.maxConcurrentUploads = maxConcurrentUploads;
+ return this;
+ }
+
+ public Builder maxConcurrentDownloads(int maxConcurrentDownloads) {
+ this.maxConcurrentDownloads = maxConcurrentDownloads;
+ return this;
+ }
+
+ public Builder multipartThreshold(long multipartThreshold) {
+ this.multipartThreshold = multipartThreshold;
+ return this;
+ }
+
+ public Builder multipartPartSize(long multipartPartSize) {
+ this.multipartPartSize = multipartPartSize;
+ return this;
+ }
+
+ public Builder syncManifestToObject(boolean syncManifestToObject) {
+ this.syncManifestToObject = syncManifestToObject;
+ return this;
+ }
+
+ public Builder replicateWal(boolean replicateWal) {
+ this.replicateWal = replicateWal;
+ return this;
+ }
+
+ public Builder walUploadSync(boolean walUploadSync) {
+ this.walUploadSync = walUploadSync;
+ return this;
+ }
+
+ public Builder walSyncThresholdBytes(long walSyncThresholdBytes) {
+ this.walSyncThresholdBytes = walSyncThresholdBytes;
+ return this;
+ }
+
+ public Builder walSyncOnCommit(boolean walSyncOnCommit) {
+ this.walSyncOnCommit = walSyncOnCommit;
+ return this;
+ }
+
+ public Builder replicaMode(boolean replicaMode) {
+ this.replicaMode = replicaMode;
+ return this;
+ }
+
+ public Builder replicaSyncIntervalUs(long replicaSyncIntervalUs) {
+ this.replicaSyncIntervalUs = replicaSyncIntervalUs;
+ return this;
+ }
+
+ public Builder replicaReplayWal(boolean replicaReplayWal) {
+ this.replicaReplayWal = replicaReplayWal;
+ return this;
+ }
+
+ public ObjectStoreConfig build() {
+ return new ObjectStoreConfig(this);
+ }
+ }
+}
diff --git a/src/main/java/com/tidesdb/TidesDB.java b/src/main/java/com/tidesdb/TidesDB.java
index a21562a..bef9caf 100644
--- a/src/main/java/com/tidesdb/TidesDB.java
+++ b/src/main/java/com/tidesdb/TidesDB.java
@@ -52,6 +52,8 @@ public static TidesDB open(Config config) throws TidesDBException {
throw new IllegalArgumentException("Database path cannot be null or empty");
}
+ ObjectStoreConfig osc = config.getObjectStoreConfig();
+
long handle = nativeOpen(
config.getDbPath(),
config.getNumFlushThreads(),
@@ -67,7 +69,24 @@ public static TidesDB open(Config config) throws TidesDBException {
config.getUnifiedMemtableSkipListMaxLevel(),
config.getUnifiedMemtableSkipListProbability(),
config.getUnifiedMemtableSyncMode(),
- config.getUnifiedMemtableSyncIntervalUs()
+ config.getUnifiedMemtableSyncIntervalUs(),
+ config.getObjectStoreFsPath(),
+ osc != null ? osc.getLocalCachePath() : null,
+ osc != null ? osc.getLocalCacheMaxBytes() : 0,
+ osc != null ? osc.isCacheOnRead() : true,
+ osc != null ? osc.isCacheOnWrite() : true,
+ osc != null ? osc.getMaxConcurrentUploads() : 4,
+ osc != null ? osc.getMaxConcurrentDownloads() : 8,
+ osc != null ? osc.getMultipartThreshold() : 64 * 1024 * 1024,
+ osc != null ? osc.getMultipartPartSize() : 8 * 1024 * 1024,
+ osc != null ? osc.isSyncManifestToObject() : true,
+ osc != null ? osc.isReplicateWal() : true,
+ osc != null ? osc.isWalUploadSync() : false,
+ osc != null ? osc.getWalSyncThresholdBytes() : 1048576,
+ osc != null ? osc.isWalSyncOnCommit() : false,
+ osc != null ? osc.isReplicaMode() : false,
+ osc != null ? osc.getReplicaSyncIntervalUs() : 5000000,
+ osc != null ? osc.isReplicaReplayWal() : true
);
return new TidesDB(handle);
@@ -122,7 +141,10 @@ public void createColumnFamily(String name, ColumnFamilyConfig config) throws Ti
config.getMinDiskSpace(),
config.getL1FileCountTrigger(),
config.getL0QueueStallThreshold(),
- config.isUseBtree()
+ config.isUseBtree(),
+ config.getObjectTargetFileSize(),
+ config.isObjectLazyCompaction(),
+ config.isObjectPrefetchCompaction()
);
}
@@ -356,7 +378,17 @@ private static native long nativeOpen(String dbPath, int numFlushThreads, int nu
int unifiedMemtableSkipListMaxLevel,
float unifiedMemtableSkipListProbability,
int unifiedMemtableSyncMode,
- long unifiedMemtableSyncIntervalUs) throws TidesDBException;
+ long unifiedMemtableSyncIntervalUs,
+ String objectStoreFsPath,
+ String oscLocalCachePath, long oscLocalCacheMaxBytes,
+ boolean oscCacheOnRead, boolean oscCacheOnWrite,
+ int oscMaxConcurrentUploads, int oscMaxConcurrentDownloads,
+ long oscMultipartThreshold, long oscMultipartPartSize,
+ boolean oscSyncManifestToObject, boolean oscReplicateWal,
+ boolean oscWalUploadSync, long oscWalSyncThresholdBytes,
+ boolean oscWalSyncOnCommit, boolean oscReplicaMode,
+ long oscReplicaSyncIntervalUs,
+ boolean oscReplicaReplayWal) throws TidesDBException;
private static native void nativeClose(long handle);
@@ -366,7 +398,9 @@ 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, boolean useBtree) throws TidesDBException;
+ int l1FileCountTrigger, int l0QueueStallThreshold, boolean useBtree,
+ long objectTargetFileSize, boolean objectLazyCompaction,
+ boolean objectPrefetchCompaction) throws TidesDBException;
private static native void nativeDropColumnFamily(long handle, String name) throws TidesDBException;