test(localdb): review fixes — index assertion, AUTOINCREMENT rationale, ReadMeta guard, concurrent HLC test

This commit is contained in:
Joseph Doherty
2026-07-17 21:05:10 -04:00
parent 83f384247c
commit 827bf44684
3 changed files with 25 additions and 1 deletions
@@ -14,6 +14,8 @@ internal static class LocalDbSchema
hlc_high_water INTEGER NOT NULL DEFAULT 0, hlc_high_water INTEGER NOT NULL DEFAULT 0,
schema_version INTEGER NOT NULL schema_version INTEGER NOT NULL
); );
-- AUTOINCREMENT: seq must never be reused after row pruning, or peer watermarks/acks would
-- silently skip/misattribute rows sharing a reused seq value.
CREATE TABLE IF NOT EXISTS __localdb_oplog ( CREATE TABLE IF NOT EXISTS __localdb_oplog (
seq INTEGER PRIMARY KEY AUTOINCREMENT, seq INTEGER PRIMARY KEY AUTOINCREMENT,
table_name TEXT NOT NULL, table_name TEXT NOT NULL,
@@ -91,7 +93,9 @@ internal static class LocalDbSchema
using var cmd = connection.CreateCommand(); using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT node_id, hlc_high_water FROM __localdb_meta WHERE id = 1"; cmd.CommandText = "SELECT node_id, hlc_high_water FROM __localdb_meta WHERE id = 1";
using var reader = cmd.ExecuteReader(); using var reader = cmd.ExecuteReader();
reader.Read(); if (!reader.Read())
throw new InvalidOperationException(
"LocalDb schema not initialized: __localdb_meta is empty. Call EnsureCreated first.");
return (reader.GetString(0), reader.GetInt64(1)); return (reader.GetString(0), reader.GetInt64(1));
} }
@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using ZB.MOM.WW.LocalDb.Hlc; using ZB.MOM.WW.LocalDb.Hlc;
namespace ZB.MOM.WW.LocalDb.Tests; namespace ZB.MOM.WW.LocalDb.Tests;
@@ -87,4 +88,20 @@ public sealed class HybridLogicalClockTests
Assert.Equal(ms + 1, HybridLogicalClock.PhysicalMs(next)); Assert.Equal(ms + 1, HybridLogicalClock.PhysicalMs(next));
Assert.Equal(0, HybridLogicalClock.Counter(next)); Assert.Equal(0, HybridLogicalClock.Counter(next));
} }
[Fact]
public void Next_ConcurrentCallers_NoDuplicates_StrictlyIncreasing()
{
var clock = new HybridLogicalClock();
var results = new ConcurrentBag<long>();
Parallel.For(0, 8, _ =>
{
for (var i = 0; i < 1000; i++)
results.Add(clock.Next());
});
Assert.Equal(8000, results.Count);
Assert.Equal(8000, results.Distinct().Count());
}
} }
@@ -54,6 +54,9 @@ public sealed class LocalDbSchemaTests : IDisposable
"__localdb_row_version", "__localdb_applying", "__localdb_dead_letter" "__localdb_row_version", "__localdb_applying", "__localdb_dead_letter"
}) })
Assert.Contains(expected, tables); Assert.Contains(expected, tables);
Assert.Equal(1, ScalarLong(conn,
"SELECT count(*) FROM sqlite_master WHERE type='index' AND name='__localdb_oplog_hlc'"));
} }
[Fact] [Fact]