Skip to content

Commit 2e79384

Browse files
committed
continuation of object storage support, finalize option handling
1 parent db7ef47 commit 2e79384

3 files changed

Lines changed: 178 additions & 4 deletions

File tree

src/tidesdb.lua

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ ffi.cdef[[
8888
int object_prefetch_compaction;
8989
} tidesdb_column_family_config_t;
9090

91+
// Object store configuration
92+
typedef struct {
93+
const char *local_cache_path;
94+
size_t local_cache_max_bytes;
95+
int cache_on_read;
96+
int cache_on_write;
97+
int max_concurrent_uploads;
98+
int max_concurrent_downloads;
99+
size_t multipart_threshold;
100+
size_t multipart_part_size;
101+
int sync_manifest_to_object;
102+
int replicate_wal;
103+
int wal_upload_sync;
104+
size_t wal_sync_threshold_bytes;
105+
int wal_sync_on_commit;
106+
int replica_mode;
107+
uint64_t replica_sync_interval_us;
108+
int replica_replay_wal;
109+
} tidesdb_objstore_config_t;
110+
91111
typedef struct {
92112
const char* db_path;
93113
int num_flush_threads;
@@ -105,7 +125,7 @@ ffi.cdef[[
105125
int unified_memtable_sync_mode;
106126
uint64_t unified_memtable_sync_interval_us;
107127
void* object_store;
108-
void* object_store_config;
128+
tidesdb_objstore_config_t* object_store_config;
109129
} tidesdb_config_t;
110130

111131
typedef struct {
@@ -137,6 +157,10 @@ ffi.cdef[[
137157
size_t num_partitions;
138158
} tidesdb_cache_stats_t;
139159

160+
// Object store functions
161+
tidesdb_objstore_config_t tidesdb_objstore_default_config(void);
162+
void* tidesdb_objstore_fs_create(const char* root_dir);
163+
140164
// Database functions
141165
tidesdb_column_family_config_t tidesdb_default_column_family_config(void);
142166
tidesdb_config_t tidesdb_default_config(void);
@@ -466,6 +490,59 @@ function tidesdb.default_column_family_config()
466490
}
467491
end
468492

493+
-- Object store configuration
494+
function tidesdb.default_objstore_config()
495+
local c_config = lib.tidesdb_objstore_default_config()
496+
return {
497+
local_cache_path = c_config.local_cache_path ~= nil and ffi.string(c_config.local_cache_path) or nil,
498+
local_cache_max_bytes = tonumber(c_config.local_cache_max_bytes),
499+
cache_on_read = c_config.cache_on_read ~= 0,
500+
cache_on_write = c_config.cache_on_write ~= 0,
501+
max_concurrent_uploads = c_config.max_concurrent_uploads,
502+
max_concurrent_downloads = c_config.max_concurrent_downloads,
503+
multipart_threshold = tonumber(c_config.multipart_threshold),
504+
multipart_part_size = tonumber(c_config.multipart_part_size),
505+
sync_manifest_to_object = c_config.sync_manifest_to_object ~= 0,
506+
replicate_wal = c_config.replicate_wal ~= 0,
507+
wal_upload_sync = c_config.wal_upload_sync ~= 0,
508+
wal_sync_threshold_bytes = tonumber(c_config.wal_sync_threshold_bytes),
509+
wal_sync_on_commit = c_config.wal_sync_on_commit ~= 0,
510+
replica_mode = c_config.replica_mode ~= 0,
511+
replica_sync_interval_us = tonumber(c_config.replica_sync_interval_us),
512+
replica_replay_wal = c_config.replica_replay_wal ~= 0,
513+
}
514+
end
515+
516+
-- Convert Lua objstore config to C struct
517+
local function objstore_config_to_c_struct(config)
518+
local c_config = ffi.new("tidesdb_objstore_config_t")
519+
c_config.local_cache_path = config.local_cache_path
520+
c_config.local_cache_max_bytes = config.local_cache_max_bytes or 0
521+
c_config.cache_on_read = (config.cache_on_read == nil or config.cache_on_read) and 1 or 0
522+
c_config.cache_on_write = (config.cache_on_write == nil or config.cache_on_write) and 1 or 0
523+
c_config.max_concurrent_uploads = config.max_concurrent_uploads or 4
524+
c_config.max_concurrent_downloads = config.max_concurrent_downloads or 8
525+
c_config.multipart_threshold = config.multipart_threshold or 67108864
526+
c_config.multipart_part_size = config.multipart_part_size or 8388608
527+
c_config.sync_manifest_to_object = (config.sync_manifest_to_object == nil or config.sync_manifest_to_object) and 1 or 0
528+
c_config.replicate_wal = (config.replicate_wal == nil or config.replicate_wal) and 1 or 0
529+
c_config.wal_upload_sync = config.wal_upload_sync and 1 or 0
530+
c_config.wal_sync_threshold_bytes = config.wal_sync_threshold_bytes or 1048576
531+
c_config.wal_sync_on_commit = config.wal_sync_on_commit and 1 or 0
532+
c_config.replica_mode = config.replica_mode and 1 or 0
533+
c_config.replica_sync_interval_us = config.replica_sync_interval_us or 5000000
534+
c_config.replica_replay_wal = (config.replica_replay_wal == nil or config.replica_replay_wal) and 1 or 0
535+
return c_config
536+
end
537+
538+
function tidesdb.objstore_fs_create(root_dir)
539+
local store = lib.tidesdb_objstore_fs_create(root_dir)
540+
if store == nil then
541+
error(TidesDBError.new("failed to create filesystem object store connector"))
542+
end
543+
return store
544+
end
545+
469546
-- Convert Lua config to C struct
470547
local function config_to_c_struct(config, cf_name)
471548
local c_config = ffi.new("tidesdb_column_family_config_t")
@@ -957,6 +1034,17 @@ function TidesDB.new(config)
9571034
c_config.unified_memtable_sync_mode = config.unified_memtable_sync_mode or tidesdb.SyncMode.SYNC_INTERVAL
9581035
c_config.unified_memtable_sync_interval_us = config.unified_memtable_sync_interval_us or 128000
9591036

1037+
-- Object store configuration
1038+
if config.object_store then
1039+
c_config.object_store = config.object_store
1040+
end
1041+
1042+
local os_config_holder
1043+
if config.object_store_config then
1044+
os_config_holder = objstore_config_to_c_struct(config.object_store_config)
1045+
c_config.object_store_config = os_config_holder
1046+
end
1047+
9601048
local db_ptr = ffi.new("void*[1]")
9611049
local result = lib.tidesdb_open(c_config, db_ptr)
9621050
check_result(result, "failed to open database")
@@ -983,6 +1071,8 @@ function TidesDB.open(path, options)
9831071
unified_memtable_skip_list_probability = options.unified_memtable_skip_list_probability,
9841072
unified_memtable_sync_mode = options.unified_memtable_sync_mode,
9851073
unified_memtable_sync_interval_us = options.unified_memtable_sync_interval_us,
1074+
object_store = options.object_store,
1075+
object_store_config = options.object_store_config,
9861076
}
9871077
return TidesDB.new(config)
9881078
end
@@ -1277,6 +1367,6 @@ function tidesdb.save_config_to_ini(ini_file, section_name, config)
12771367
end
12781368

12791369
-- Version
1280-
tidesdb._VERSION = "0.5.7"
1370+
tidesdb._VERSION = "0.5.8"
12811371

12821372
return tidesdb

tests/test_tidesdb.lua

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,90 @@ function tests.test_db_stats_extended_fields()
12321232
print("PASS: test_db_stats_extended_fields")
12331233
end
12341234

1235+
function tests.test_objstore_config_defaults()
1236+
-- Test default object store config has correct fields and defaults
1237+
local os_config = tidesdb.default_objstore_config()
1238+
1239+
assert_true(os_config.local_cache_max_bytes ~= nil, "local_cache_max_bytes should exist")
1240+
assert_eq(os_config.local_cache_max_bytes, 0, "local_cache_max_bytes should default to 0")
1241+
assert_eq(os_config.cache_on_read, true, "cache_on_read should default to true")
1242+
assert_eq(os_config.cache_on_write, true, "cache_on_write should default to true")
1243+
assert_eq(os_config.max_concurrent_uploads, 4, "max_concurrent_uploads should default to 4")
1244+
assert_eq(os_config.max_concurrent_downloads, 8, "max_concurrent_downloads should default to 8")
1245+
assert_true(os_config.multipart_threshold > 0, "multipart_threshold should be > 0")
1246+
assert_true(os_config.multipart_part_size > 0, "multipart_part_size should be > 0")
1247+
assert_eq(os_config.sync_manifest_to_object, true, "sync_manifest_to_object should default to true")
1248+
assert_eq(os_config.replicate_wal, true, "replicate_wal should default to true")
1249+
assert_eq(os_config.wal_upload_sync, false, "wal_upload_sync should default to false")
1250+
assert_true(os_config.wal_sync_threshold_bytes > 0, "wal_sync_threshold_bytes should be > 0")
1251+
assert_eq(os_config.wal_sync_on_commit, false, "wal_sync_on_commit should default to false")
1252+
assert_eq(os_config.replica_mode, false, "replica_mode should default to false")
1253+
assert_true(os_config.replica_sync_interval_us > 0, "replica_sync_interval_us should be > 0")
1254+
assert_eq(os_config.replica_replay_wal, true, "replica_replay_wal should default to true")
1255+
1256+
print("PASS: test_objstore_config_defaults")
1257+
end
1258+
1259+
function tests.test_objstore_fs_create()
1260+
local path = "./test_objstore_root"
1261+
os.execute("rm -rf " .. path)
1262+
os.execute("mkdir -p " .. path)
1263+
1264+
-- Create filesystem connector
1265+
local store = tidesdb.objstore_fs_create(path)
1266+
assert_true(store ~= nil, "filesystem object store connector should be created")
1267+
1268+
os.execute("rm -rf " .. path)
1269+
print("PASS: test_objstore_fs_create")
1270+
end
1271+
1272+
function tests.test_objstore_open_with_fs_connector()
1273+
local db_path = "./test_db_objstore"
1274+
local store_path = "./test_objstore_data"
1275+
local cleanup_db = function(p) os.execute("rm -rf " .. p) end
1276+
cleanup_db(db_path)
1277+
cleanup_db(store_path)
1278+
os.execute("mkdir -p " .. store_path)
1279+
1280+
-- Create filesystem connector and config
1281+
local store = tidesdb.objstore_fs_create(store_path)
1282+
local os_config = tidesdb.default_objstore_config()
1283+
os_config.local_cache_max_bytes = 128 * 1024 * 1024
1284+
os_config.max_concurrent_uploads = 2
1285+
1286+
-- Open database with object store
1287+
local db = tidesdb.TidesDB.open(db_path, {
1288+
log_level = tidesdb.LogLevel.LOG_WARN,
1289+
object_store = store,
1290+
object_store_config = os_config,
1291+
})
1292+
assert_true(db ~= nil, "database should open with object store connector")
1293+
1294+
-- Basic operations should work
1295+
db:create_column_family("test_cf")
1296+
local cf = db:get_column_family("test_cf")
1297+
1298+
local txn = db:begin_txn()
1299+
txn:put(cf, "key1", "value1")
1300+
txn:commit()
1301+
txn:free()
1302+
1303+
local read_txn = db:begin_txn()
1304+
local v = read_txn:get(cf, "key1")
1305+
assert_eq(v, "value1", "should read value with object store enabled")
1306+
read_txn:free()
1307+
1308+
-- Verify object store stats reflect enabled state
1309+
local db_stats = db:get_db_stats()
1310+
assert_eq(db_stats.object_store_enabled, true, "object_store_enabled should be true")
1311+
1312+
db:drop_column_family("test_cf")
1313+
db:close()
1314+
cleanup_db(db_path)
1315+
cleanup_db(store_path)
1316+
print("PASS: test_objstore_open_with_fs_connector")
1317+
end
1318+
12351319
function tests.test_promote_to_primary()
12361320
local path = "./test_db_promote"
12371321
cleanup_db(path)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package = "tidesdb"
2-
version = "0.5.7-1"
2+
version = "0.5.8-1"
33
source = {
44
url = "git://github.com/tidesdb/tidesdb-lua.git",
5-
tag = "v0.5.7"
5+
tag = "v0.5.8"
66
}
77
description = {
88
summary = "Official Lua bindings for TidesDB - A high-performance embedded key-value storage engine",

0 commit comments

Comments
 (0)