Initialize CBDD solution and add a .NET-focused gitignore for generated artifacts.

This commit is contained in:
Joseph Doherty
2026-02-20 12:54:07 -05:00
commit b8ed5ec500
214 changed files with 101452 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
using ZB.MOM.WW.CBDD.Bson;
using ZB.MOM.WW.CBDD.Core.Storage;
using ZB.MOM.WW.CBDD.Shared;
namespace ZB.MOM.WW.CBDD.Tests;
public class CompactionWalCoordinationTests
{
[Fact]
public void OfflineCompact_ShouldCheckpointAndLeaveWalEmpty()
{
var dbPath = NewDbPath();
var markerPath = $"{dbPath}.compact.state";
try
{
using var db = new TestDbContext(dbPath);
for (var i = 0; i < 80; i++)
{
db.Users.Insert(new User { Name = $"wal-compact-{i:D3}", Age = i });
}
db.SaveChanges();
db.Storage.GetWalSize().ShouldBeGreaterThan(0);
var stats = db.Compact(new CompactionOptions
{
EnableTailTruncation = true,
NormalizeFreeList = true,
DefragmentSlottedPages = true
});
stats.OnlineMode.ShouldBeFalse();
db.Storage.GetWalSize().ShouldBe(0);
File.Exists(markerPath).ShouldBeFalse();
db.Users.Count().ShouldBe(80);
}
finally
{
CleanupFiles(dbPath);
}
}
[Fact]
public void Compact_AfterWalRecovery_ShouldKeepDataDurable()
{
var dbPath = NewDbPath();
var walPath = Path.ChangeExtension(dbPath, ".wal");
var expected = new List<(ObjectId Id, string Name)>();
try
{
using (var writer = new TestDbContext(dbPath))
{
for (var i = 0; i < 48; i++)
{
var name = $"recoverable-{i:D3}";
var id = writer.Users.Insert(new User { Name = name, Age = i % 13 });
expected.Add((id, name));
}
writer.SaveChanges();
writer.Storage.GetWalSize().ShouldBeGreaterThan(0);
}
new FileInfo(walPath).Length.ShouldBeGreaterThan(0);
using (var recovered = new TestDbContext(dbPath))
{
recovered.Users.Count().ShouldBe(expected.Count);
foreach (var item in expected)
{
recovered.Users.FindById(item.Id)!.Name.ShouldBe(item.Name);
}
recovered.SaveChanges();
recovered.Compact();
recovered.Storage.GetWalSize().ShouldBe(0);
}
using (var verify = new TestDbContext(dbPath))
{
verify.Users.Count().ShouldBe(expected.Count);
foreach (var item in expected)
{
verify.Users.FindById(item.Id)!.Name.ShouldBe(item.Name);
}
}
}
finally
{
CleanupFiles(dbPath);
}
}
private static string NewDbPath()
=> Path.Combine(Path.GetTempPath(), $"compaction_wal_{Guid.NewGuid():N}.db");
private static void CleanupFiles(string dbPath)
{
var walPath = Path.ChangeExtension(dbPath, ".wal");
var markerPath = $"{dbPath}.compact.state";
if (File.Exists(dbPath)) File.Delete(dbPath);
if (File.Exists(walPath)) File.Delete(walPath);
if (File.Exists(markerPath)) File.Delete(markerPath);
}
}