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
15 changes: 15 additions & 0 deletions src/TidesDB/ColumnFamily.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,21 @@ public double RangeCost(ReadOnlySpan<byte> keyA, ReadOnlySpan<byte> keyB)
return cost;
}

/// <summary>
/// Updates runtime-safe configuration settings for this column family.
/// Changes apply to new operations only. Existing SSTables and memtables
/// retain their original settings.
/// </summary>
/// <param name="config">The new column family configuration.</param>
/// <param name="persistToDisk">If true, saves changes to config.ini on disk.</param>
public void UpdateRuntimeConfig(ColumnFamilyConfig config, bool persistToDisk = true)
{
var nativeConfig = TidesDb.CreateNativeColumnFamilyConfigPublic(config);
var result = NativeMethods.tidesdb_cf_update_runtime_config(
Handle, ref nativeConfig, persistToDisk ? 1 : 0);
TidesDBException.ThrowIfError(result, "failed to update runtime config");
}

/// <summary>
/// Gets statistics about this column family.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/TidesDB/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public sealed class Config
/// </summary>
public ulong MaxOpenSstables { get; init; } = 256;

/// <summary>
/// Global memory limit in bytes (default: 0 = auto, 50% of system RAM; minimum: 5% of system RAM).
/// </summary>
public ulong MaxMemoryUsage { get; init; } = 0;

/// <summary>
/// Flag to determine if debug logging should be written to a file (default: false).
/// </summary>
Expand Down
8 changes: 8 additions & 0 deletions src/TidesDB/Native/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ internal static partial class NativeMethods
[LibraryImport(LibraryName, EntryPoint = "tidesdb_cf_set_commit_hook")]
internal static partial int tidesdb_cf_set_commit_hook(nint cf, nint fn, nint ctx);

// Runtime config update
[LibraryImport(LibraryName, EntryPoint = "tidesdb_cf_update_runtime_config")]
internal static partial int tidesdb_cf_update_runtime_config(nint cf, ref NativeColumnFamilyConfig config, int persistToDisk);

// Get comparator
[LibraryImport(LibraryName, EntryPoint = "tidesdb_get_comparator", StringMarshalling = StringMarshalling.Utf8)]
internal static partial int tidesdb_get_comparator(nint db, string name, out nint fn, out nint ctx);

// Range cost estimation
[LibraryImport(LibraryName, EntryPoint = "tidesdb_range_cost")]
internal static unsafe partial int tidesdb_range_cost(nint cf, byte* keyA, nuint keyASize, byte* keyB, nuint keyBSize, out double cost);
Expand Down
1 change: 1 addition & 0 deletions src/TidesDB/Native/NativeStructs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal struct NativeConfig
public int LogLevel;
public nuint BlockCacheSize;
public nuint MaxOpenSstables;
public nuint MaxMemoryUsage;
public int LogToFile;
public nuint LogTruncationAt;
}
Expand Down
17 changes: 17 additions & 0 deletions src/TidesDB/TidesDB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static TidesDb Open(Config config)
LogLevel = (int)config.LogLevel,
BlockCacheSize = (nuint)config.BlockCacheSize,
MaxOpenSstables = (nuint)config.MaxOpenSstables,
MaxMemoryUsage = (nuint)config.MaxMemoryUsage,
LogToFile = config.LogToFile ? 1 : 0,
LogTruncationAt = (nuint)config.LogTruncationAt
};
Expand Down Expand Up @@ -214,6 +215,19 @@ public void RegisterComparator(string name, string? ctxStr = null)
TidesDBException.ThrowIfError(result, "failed to register comparator");
}

/// <summary>
/// Retrieves a previously registered comparator by name.
/// Returns true if the comparator is registered, false otherwise.
/// </summary>
/// <param name="name">The comparator name.</param>
/// <returns>True if the comparator is registered.</returns>
public bool GetComparator(string name)
{
ThrowIfDisposed();
var result = NativeMethods.tidesdb_get_comparator(_handle, name, out _, out _);
return result == 0;
}

/// <summary>
/// Gets statistics about the block cache.
/// </summary>
Expand All @@ -237,6 +251,9 @@ public CacheStats GetCacheStats()
};
}

internal static unsafe NativeColumnFamilyConfig CreateNativeColumnFamilyConfigPublic(ColumnFamilyConfig config)
=> CreateNativeColumnFamilyConfig(config);

private static unsafe NativeColumnFamilyConfig CreateNativeColumnFamilyConfig(ColumnFamilyConfig config)
{
var nativeConfig = new NativeColumnFamilyConfig
Expand Down
2 changes: 1 addition & 1 deletion src/TidesDB/TidesDB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<!-- Package metadata -->
<PackageId>TidesDB</PackageId>
<Version>0.4.3</Version>
<Version>0.4.4</Version>
<Authors>TidesDB</Authors>
<Company>TidesDB</Company>
<Description>Official C# bindings for TidesDB - A high-performance embedded key-value storage engine</Description>
Expand Down
69 changes: 69 additions & 0 deletions tests/TidesDB.Tests/TidesDBTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -852,4 +852,73 @@ public void RangeCost_ReversedKeys_ShouldReturnSameResult()

Assert.Equal(costAB, costBA);
}

[Fact]
public void UpdateRuntimeConfig_ShouldSucceed()
{
using var db = OpenDatabase();
db.CreateColumnFamily("test_cf");
var cf = db.GetColumnFamily("test_cf")!;

var newConfig = new ColumnFamilyConfig
{
WriteBufferSize = 128 * 1024 * 1024,
BloomFpr = 0.001,
CompressionAlgorithm = CompressionAlgorithm.Zstd,
};

cf.UpdateRuntimeConfig(newConfig);
}

[Fact]
public void UpdateRuntimeConfig_WithoutPersist_ShouldSucceed()
{
using var db = OpenDatabase();
db.CreateColumnFamily("test_cf");
var cf = db.GetColumnFamily("test_cf")!;

var newConfig = new ColumnFamilyConfig
{
WriteBufferSize = 256 * 1024 * 1024,
};

cf.UpdateRuntimeConfig(newConfig, persistToDisk: false);
}

[Fact]
public void GetComparator_BuiltIn_ShouldReturnTrue()
{
using var db = OpenDatabase();

Assert.True(db.GetComparator("memcmp"));
Assert.True(db.GetComparator("reverse"));
}

[Fact]
public void GetComparator_NonExistent_ShouldReturnFalse()
{
using var db = OpenDatabase();

Assert.False(db.GetComparator("nonexistent_comparator"));
}

[Fact]
public void ReleaseSavepoint_ShouldSucceed()
{
using var db = OpenDatabase();
db.CreateColumnFamily("test_cf");
var cf = db.GetColumnFamily("test_cf")!;

using var txn = db.BeginTransaction();

txn.Put(cf, Encoding.UTF8.GetBytes("key1"), Encoding.UTF8.GetBytes("value1"));
txn.Savepoint("sp1");
txn.Put(cf, Encoding.UTF8.GetBytes("key2"), Encoding.UTF8.GetBytes("value2"));
txn.ReleaseSavepoint("sp1");
txn.Commit();

using var readTxn = db.BeginTransaction();
Assert.NotNull(readTxn.Get(cf, Encoding.UTF8.GetBytes("key1")));
Assert.NotNull(readTxn.Get(cf, Encoding.UTF8.GetBytes("key2")));
}
}
Loading