test(localdb): review fixes — index assertion, AUTOINCREMENT rationale, ReadMeta guard, concurrent HLC test
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user