feat(batch14): complete filestore write lifecycle features and tests

This commit is contained in:
Joseph Doherty
2026-02-28 16:41:31 -05:00
parent 045faf7423
commit 5367c3f34d
9 changed files with 1596 additions and 39 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
using Shouldly;
using ZB.MOM.NatsNet.Server;
@@ -122,6 +123,74 @@ public sealed partial class ConcurrencyTests2
}, cfg);
}
[Fact] // T:2494
public void NoRaceFileStoreWriteFullStateUniqueSubjects_ShouldSucceed()
{
var cfg = new StreamConfig
{
Name = "TEST",
Storage = StorageType.FileStorage,
Subjects = ["records.>"],
MaxMsgs = -1,
MaxBytes = 15L * 1024 * 1024 * 1024,
MaxAge = TimeSpan.Zero,
MaxMsgsPer = 1,
Discard = DiscardPolicy.DiscardOld,
Retention = RetentionPolicy.LimitsPolicy,
};
WithStore((fs, root) =>
{
var payload = Enumerable.Repeat((byte)'Z', 128).ToArray();
var errors = new ConcurrentQueue<Exception>();
using var cts = new CancellationTokenSource();
var writer = Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
try
{
var err = InvokePrivate<Exception?>(fs, "WriteFullState");
if (err != null)
errors.Enqueue(err);
}
catch (Exception ex)
{
errors.Enqueue(ex);
}
try
{
await Task.Delay(10, cts.Token);
}
catch (OperationCanceledException)
{
break;
}
}
});
for (var i = 0; i < 2_000; i++)
{
var subject = $"records.{Guid.NewGuid():N}.{i % 5}";
var sw = Stopwatch.StartNew();
fs.StoreMsg(subject, null, payload, 0).Seq.ShouldBeGreaterThan(0UL);
sw.Stop();
sw.Elapsed.ShouldBeLessThan(TimeSpan.FromMilliseconds(500));
}
cts.Cancel();
Should.NotThrow(() => writer.Wait(TimeSpan.FromSeconds(2)));
errors.ShouldBeEmpty();
fs.Stop();
var stateFile = Path.Combine(root, FileStoreDefaults.MsgDir, FileStoreDefaults.StreamStateFile);
File.Exists(stateFile).ShouldBeTrue();
new FileInfo(stateFile).Length.ShouldBeGreaterThan(0L);
}, cfg);
}
private static void WithStore(Action<JetStreamFileStore, string> action, StreamConfig? cfg = null)
{
var root = NewRoot();