feat(streaming): enforce typed completion queues
Replace the flat deferred list, priority scan, unload bypass, and count-only execution cap with exact destination/control/unload/Near/Far FIFOs behind one typed frame meter. Price worker results before adoption, retain exact retry identity, reject stale generations without payload retention, and publish queue pressure through lifecycle diagnostics. Tests: dotnet build AcDream.slnx -c Release --no-restore; dotnet test AcDream.slnx -c Release --no-restore (8138 passed, 5 skipped)
This commit is contained in:
parent
ac45cb1bd7
commit
b8f6317fe1
15 changed files with 1261 additions and 336 deletions
|
|
@ -0,0 +1,207 @@
|
|||
using System.Diagnostics;
|
||||
using AcDream.App.Streaming;
|
||||
|
||||
namespace AcDream.App.Tests.Streaming;
|
||||
|
||||
public sealed class StreamingCompletionQueueTests
|
||||
{
|
||||
[Fact]
|
||||
public void PrioritySelectionIsStableFifoAndSkipsOnlyBlockedHead()
|
||||
{
|
||||
var queue = new StreamingCompletionQueue();
|
||||
StreamingQueuedCompletion farFirst = Completion(
|
||||
new LandblockStreamResult.Failed(1, "far-first"),
|
||||
StreamingCompletionPriority.Far,
|
||||
sequence: 1);
|
||||
StreamingQueuedCompletion nearBlocked = Completion(
|
||||
new LandblockStreamResult.Failed(2, "near-blocked"),
|
||||
StreamingCompletionPriority.Near,
|
||||
sequence: 2);
|
||||
StreamingQueuedCompletion nearTail = Completion(
|
||||
new LandblockStreamResult.Failed(3, "near-tail"),
|
||||
StreamingCompletionPriority.Near,
|
||||
sequence: 3);
|
||||
StreamingQueuedCompletion destinationFirst = Completion(
|
||||
new LandblockStreamResult.Failed(4, "destination-first"),
|
||||
StreamingCompletionPriority.Destination,
|
||||
sequence: 4);
|
||||
StreamingQueuedCompletion destinationTail = Completion(
|
||||
new LandblockStreamResult.Failed(5, "destination-tail"),
|
||||
StreamingCompletionPriority.Destination,
|
||||
sequence: 5);
|
||||
|
||||
queue.Enqueue(farFirst);
|
||||
queue.Enqueue(nearBlocked);
|
||||
queue.Enqueue(nearTail);
|
||||
queue.Enqueue(destinationFirst);
|
||||
queue.Enqueue(destinationTail);
|
||||
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out StreamingQueuedCompletion? selected));
|
||||
Assert.Equal(destinationFirst.Sequence, selected?.Sequence);
|
||||
Assert.Same(destinationFirst.Result, selected?.Result);
|
||||
queue.RemoveHead(destinationFirst);
|
||||
|
||||
Assert.True(queue.TryPeekNext(
|
||||
result => ReferenceEquals(result, destinationTail.Result)
|
||||
|| ReferenceEquals(result, nearBlocked.Result),
|
||||
out selected));
|
||||
Assert.Equal(farFirst.Sequence, selected?.Sequence);
|
||||
Assert.Same(farFirst.Result, selected?.Result);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
queue.RemoveHead(nearTail));
|
||||
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out selected));
|
||||
Assert.Equal(destinationTail.Sequence, selected?.Sequence);
|
||||
Assert.Same(destinationTail.Result, selected?.Result);
|
||||
queue.RemoveHead(destinationTail);
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out selected));
|
||||
Assert.Equal(nearBlocked.Sequence, selected?.Sequence);
|
||||
Assert.Same(nearBlocked.Result, selected?.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetainedBytesAndPriorityFactsTrackExactQueueLifetime()
|
||||
{
|
||||
var queue = new StreamingCompletionQueue();
|
||||
StreamingQueuedCompletion destination = Completion(
|
||||
new LandblockStreamResult.Failed(10, "destination"),
|
||||
StreamingCompletionPriority.Destination,
|
||||
sequence: 1,
|
||||
adoptedBytes: 12);
|
||||
StreamingQueuedCompletion unload = Completion(
|
||||
new LandblockStreamResult.Unloaded(11),
|
||||
StreamingCompletionPriority.Unload,
|
||||
sequence: 2,
|
||||
adoptedBytes: 20);
|
||||
StreamingQueuedCompletion near = Completion(
|
||||
new LandblockStreamResult.Failed(12, "near"),
|
||||
StreamingCompletionPriority.Near,
|
||||
sequence: 3,
|
||||
adoptedBytes: 30);
|
||||
|
||||
queue.Enqueue(destination);
|
||||
queue.Enqueue(unload);
|
||||
queue.Enqueue(near);
|
||||
|
||||
StreamingCompletionQueueSnapshot snapshot = queue.CaptureSnapshot();
|
||||
Assert.Equal(3, snapshot.Count);
|
||||
Assert.Equal(62, snapshot.RetainedCpuBytes);
|
||||
Assert.Equal(1, snapshot.Destination);
|
||||
Assert.Equal(1, snapshot.Unload);
|
||||
Assert.Equal(1, snapshot.Near);
|
||||
Assert.True(snapshot.OldestAgeMilliseconds >= 0);
|
||||
|
||||
queue.RemoveHead(destination);
|
||||
snapshot = queue.CaptureSnapshot();
|
||||
Assert.Equal(2, snapshot.Count);
|
||||
Assert.Equal(50, snapshot.RetainedCpuBytes);
|
||||
|
||||
queue.Clear();
|
||||
snapshot = queue.CaptureSnapshot();
|
||||
Assert.Equal(0, snapshot.Count);
|
||||
Assert.Equal(0, snapshot.RetainedCpuBytes);
|
||||
Assert.Equal(0, snapshot.OldestAgeMilliseconds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExactReferenceRemovalDoesNotConflateEqualRecords()
|
||||
{
|
||||
var queue = new StreamingCompletionQueue();
|
||||
var firstResult =
|
||||
new LandblockStreamResult.Failed(20, "same", Generation: 7);
|
||||
var equalButDistinctResult =
|
||||
new LandblockStreamResult.Failed(20, "same", Generation: 7);
|
||||
StreamingQueuedCompletion first = Completion(
|
||||
firstResult,
|
||||
StreamingCompletionPriority.Control,
|
||||
sequence: 1,
|
||||
adoptedBytes: 11);
|
||||
StreamingQueuedCompletion second = Completion(
|
||||
equalButDistinctResult,
|
||||
StreamingCompletionPriority.Control,
|
||||
sequence: 2,
|
||||
adoptedBytes: 13);
|
||||
queue.Enqueue(first);
|
||||
queue.Enqueue(second);
|
||||
|
||||
int removed = queue.RemoveResults(
|
||||
[equalButDistinctResult],
|
||||
static _ => true);
|
||||
|
||||
Assert.Equal(1, removed);
|
||||
Assert.Equal(1, queue.Count);
|
||||
Assert.Equal(11, queue.RetainedCpuBytes);
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out StreamingQueuedCompletion? selected));
|
||||
Assert.Equal(first.Sequence, selected?.Sequence);
|
||||
Assert.Same(first.Result, selected?.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CallbackAppendNeverInvalidatesActiveHead()
|
||||
{
|
||||
var queue = new StreamingCompletionQueue();
|
||||
StreamingQueuedCompletion active = Completion(
|
||||
new LandblockStreamResult.Failed(30, "active"),
|
||||
StreamingCompletionPriority.Near,
|
||||
sequence: 1);
|
||||
StreamingQueuedCompletion appended = Completion(
|
||||
new LandblockStreamResult.Failed(31, "appended"),
|
||||
StreamingCompletionPriority.Near,
|
||||
sequence: 2);
|
||||
queue.Enqueue(active);
|
||||
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out StreamingQueuedCompletion? selected));
|
||||
Assert.Equal(active.Sequence, selected?.Sequence);
|
||||
Assert.Same(active.Result, selected?.Result);
|
||||
|
||||
queue.Enqueue(appended);
|
||||
queue.RemoveHead(active);
|
||||
|
||||
Assert.True(queue.TryPeekNext(
|
||||
static _ => false,
|
||||
out selected));
|
||||
Assert.Equal(appended.Sequence, selected?.Sequence);
|
||||
Assert.Same(appended.Result, selected?.Result);
|
||||
}
|
||||
|
||||
private static StreamingQueuedCompletion Completion(
|
||||
LandblockStreamResult result,
|
||||
StreamingCompletionPriority priority,
|
||||
long sequence,
|
||||
long adoptedBytes = 0)
|
||||
{
|
||||
var estimate = new LandblockStreamCostEstimate(
|
||||
Work: new StreamingWorkCost(
|
||||
CompletionAdmissions: 1,
|
||||
AdoptedCpuBytes: adoptedBytes),
|
||||
TerrainPayloadBytes: 0,
|
||||
Entities: 0,
|
||||
MeshReferences: 0,
|
||||
VisibilityCells: 0,
|
||||
EnvCellShells: 0,
|
||||
PortalConnections: 0,
|
||||
PortalPolygonVertices: 0,
|
||||
PhysicsEnvCells: 0,
|
||||
PhysicsEnvironments: 0,
|
||||
PhysicsSetups: 0,
|
||||
PhysicsGfxObjects: 0);
|
||||
return new StreamingQueuedCompletion(
|
||||
result,
|
||||
estimate,
|
||||
priority,
|
||||
result.Generation,
|
||||
sequence,
|
||||
Stopwatch.GetTimestamp());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue