Skip to content

Commit 8065302

Browse files
committed
Verify exact storage state after joined read-cut shutdown
1 parent 8844c29 commit 8065302

4 files changed

Lines changed: 112 additions & 16 deletions

File tree

‎docs/Features/StorageRecovery/NativeReadCuts.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ normal/scalar/recovery evidence. No format, dependency, public API or RF3 contra
3939
change; rollback removes only this stronger oracle. This does not qualify the
4040
helper-only aggregate-exception test as a product-operation contributor.
4141

42+
The strengthened five-case lifetime class passes the original local native TUnit
43+
normal and scalar runs,5/5 in each with zero skipped/failed cases or source and
44+
UnitTests/CrashHost DLL/PDB drift. The shutdown case now proves the original
45+
committed bytes, position and all identity fields after joined reopen, then an
46+
independent healthy record write/read and exact second reopen. The full Release
47+
build and native formatter pass. Exact report/source hashes are retained under
48+
KL-008 in `docs/implementation/status.json`; current-source Linux identity and
49+
recovery qualification and the remaining KL-008 maintainer/pool criteria stay open.
50+
4251
Capture is synchronous and native snapshot freeze/rotation and `Next` have no
4352
cancellation API. Elapsed checks detect and reject overruns after those calls;
4453
they do not interrupt a blocked native call or promise a hard wall-time bound.

‎docs/implementation/status.json‎

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"localMovedContractTestsPassed": 27,
1818
"compiledUnitBenchmarkTypes": 0,
1919
"compiledComparisonBenchmarkTypes": 588,
20-
"verificationStage": "R122 full Release build passed with zero drift/warnings/errors; current codec19 normal/scalar passed locally; original876c Linux full unit/scalar/recovery passed and RF3 failed15/155; fresh current-source complete Linux gates remain open",
20+
"verificationStage": "R130 full Release and R133 native formatter passed with 4,113 compile inputs and zero drift; strengthened read-cut lifetime class5/5 normal/scalar; original922 Linux full normal/scalar2764/2764 and recovery235/235 plus same-job native identity passed; RF3 terminal cancelled, original failure artifacts pending review; current complete Linux gates remain open",
2121
"remaining": [
2222
"Complete current-source Linux native unit/scalar/recovery with same-job compiled image identity and RF3 public SDK/MCP acceptance",
2323
"Resolve actual RF3 failures; local focused diagnostics did not deploy because the intended server image setting was absent",
@@ -40,16 +40,16 @@
4040
"receipt": "https://github.com/managedcode/KeyLoad/actions/runs/37546085722"
4141
},
4242
"currentBuild": {
43-
"compileInputs": 4112,
43+
"compileInputs": 4113,
4444
"inputDrift": 0,
4545
"warnings": 0,
4646
"errors": 0,
47-
"logSha256": "fe030e4f12333033052093ddb025a37640d2ffebf058dc9b7f5d159f1ffa0bbb",
47+
"logSha256": "caeb8fb61f61da1c018ad71606a7fcc59c73ee520a7904a3d184c343725b5cbf",
4848
"passed": true,
49-
"qualification": "native local full Release build; runtime and Linux task acceptance remain open"
49+
"qualification": "native local full Release build; Linux task acceptance remains open"
5050
},
5151
"currentFormatter": {
52-
"compileInputs": 4112,
52+
"compileInputs": 4113,
5353
"inputDrift": 0,
5454
"nativeExitCode": 0,
5555
"logSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
@@ -67,7 +67,7 @@
6767
"failed": 0,
6868
"skipped": 0,
6969
"sameJobSourceImageIdentityPassed": true,
70-
"rf3": "pending_at_original_verify_artifact_capture",
70+
"rf3": "cancelled; original terminal artifacts pending review, no RF3 pass inferred",
7171
"qualification": "original completed Linux verify job; current added codec/owner tests need their own source-bound original outcomes",
7272
"receipt": "https://github.com/managedcode/KeyLoad/actions/runs/37550611380"
7373
}
@@ -1075,10 +1075,12 @@
10751075
"src/KeyLoad.Storage.ZoneTree/ZoneTreeStore.cs",
10761076
"tests/KeyLoad.RecoveryTests/Features/StorageRecovery/Cases/RecoveryTests.cs",
10771077
"docs/implementation/durability-audit.md",
1078-
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Cases/StorageOwnerProcessTests.cs"
1078+
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Cases/StorageOwnerProcessTests.cs",
1079+
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Cases/NativeReadCutLifetimeTests.cs",
1080+
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Assertions/NativeReadCutStoreStateAssertions.cs"
10791081
],
10801082
"qualification": {
1081-
"sourceStage": "TASK-STORAGE-OWNER-PROCESS_real_parent_live_owner_two_denied_children_healthy_write_dispose_child_success_exact_reopen_joined",
1083+
"sourceStage": "TASK-STORAGE-OWNER-PROCESS_and_TASK-CUT-SHUTDOWN-STATE_real_process_and_exact_joined_reopen_state_joined_local_native_normal_scalar_passed",
10821084
"requirements": [
10831085
"REQ-STORAGE-008",
10841086
"REQ-CUT-003",
@@ -1093,16 +1095,16 @@
10931095
"canonicalFormatterPassed": true,
10941096
"runtimeQualified": false,
10951097
"currentBuild": {
1096-
"compileInputs": 4112,
1098+
"compileInputs": 4113,
10971099
"inputDrift": 0,
10981100
"warnings": 0,
10991101
"errors": 0,
1100-
"logSha256": "fe030e4f12333033052093ddb025a37640d2ffebf058dc9b7f5d159f1ffa0bbb",
1102+
"logSha256": "caeb8fb61f61da1c018ad71606a7fcc59c73ee520a7904a3d184c343725b5cbf",
11011103
"passed": true,
1102-
"qualification": "native local full Release build; runtime and Linux task acceptance remain open"
1104+
"qualification": "native local full Release build; Linux task acceptance remains open"
11031105
},
11041106
"currentFormatter": {
1105-
"compileInputs": 4112,
1107+
"compileInputs": 4113,
11061108
"inputDrift": 0,
11071109
"nativeExitCode": 0,
11081110
"logSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
@@ -1133,9 +1135,33 @@
11331135
},
11341136
"remaining": [
11351137
"Current-source Linux normal/scalar real distinct-process ownership and full recovery with native source/test-image identity",
1136-
"Strengthen existing joined read-cut shutdown case with exact bytes/position/full identity and a healthy write/reopen; no duplicate shutdown scenario",
1138+
"Current-source Linux strengthened read-cut shutdown/reopen exact-state case with native source/test-image identity; local normal/scalar five-case class passes",
11371139
"Bind actual native maintainer shutdown ownership and pooled-buffer operation criteria before whole KL-008 acceptance; full StorageRecovery RF3/endurance/power-loss remain separate mandatory gates"
1138-
]
1140+
],
1141+
"localReadCutShutdownStateEvidence": {
1142+
"task": "TASK-CUT-SHUTDOWN-STATE",
1143+
"criterion": "AC-CUT-003",
1144+
"normalPassed": 5,
1145+
"normalTotal": 5,
1146+
"scalarPassed": 5,
1147+
"scalarTotal": 5,
1148+
"failed": 0,
1149+
"skipped": 0,
1150+
"normalTrxSha256": "d5c5351a35183dce60b8fdadb019cece05f5cec97afe4a4982c93fa917b902ca",
1151+
"scalarTrxSha256": "171a448edf979a5ac373e318b044cc6452ded09702ec80d022356b0b50767058",
1152+
"normalLogSha256": "4d5eedf86cf0540252b1f3141212a93f1b639d04f75abff3887495ffa2d6d3e8",
1153+
"scalarLogSha256": "2a22d47b61bd8d72ac93d787bb69091e3ea7e0aa6ddd7c263a58f8de25ee5ec9",
1154+
"sourceInputs": 4114,
1155+
"unitAndCrashHostAssemblyInputs": 541,
1156+
"sourceDrift": 0,
1157+
"assemblyDrift": 0,
1158+
"ownedSourceHashes": {
1159+
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Cases/NativeReadCutLifetimeTests.cs": "079f7d0f671e2837cea8f803b22a4890293a97c0ba8f7ada1480b9412119b15d",
1160+
"tests/KeyLoad.UnitTests/Features/StorageRecovery/Assertions/NativeReadCutStoreStateAssertions.cs": "9135c82ee423989739cd58932b3022f7b1d3559d2e56d68b9f1240c8fe36f547"
1161+
},
1162+
"observedFlow": "actual callback overlap and shutdown cancellation; original traversal/disposal joined; exact bytes/position/all identity fields after reopen; healthy second record write/read and second reopen preserves both records and identity",
1163+
"qualification": "actual local native normal/scalar five-case class; current-source Linux recovery and whole KL-008 criteria remain open"
1164+
}
11391165
}
11401166
},
11411167
"KL-009": {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using KeyLoad.Storage;
2+
using KeyLoad.Storage.ZoneTree;
3+
4+
namespace KeyLoad.UnitTests.Features.StorageRecovery.Assertions;
5+
6+
internal static class NativeReadCutStoreStateAssertions
7+
{
8+
internal static StoreIdentity SnapshotIdentity(ZoneTreeStore store)
9+
{
10+
var identity = store.Identity;
11+
return identity with { SigningKey = identity.SigningKey.ToArray() };
12+
}
13+
14+
internal static async Task AssertIdentityAndPositionAsync(ZoneTreeStore store, StoreIdentity expected, long position)
15+
{
16+
var actual = store.Identity;
17+
await Assert.That(store.Position).IsEqualTo(position);
18+
await Assert.That(actual.FormatVersion).IsEqualTo(expected.FormatVersion);
19+
await Assert.That(actual.KeyCodecVersion).IsEqualTo(expected.KeyCodecVersion);
20+
await Assert.That(actual.NodeId).IsEqualTo(expected.NodeId);
21+
await Assert.That(actual.Incarnation).IsEqualTo(expected.Incarnation);
22+
await Assert.That(actual.SigningKey.Span.SequenceEqual(expected.SigningKey.Span)).IsTrue();
23+
await Assert.That(actual.Durability).IsEqualTo(expected.Durability);
24+
await Assert.That(actual.DispatchPaused).IsEqualTo(expected.DispatchPaused);
25+
await Assert.That(actual.ReadGeneration).IsEqualTo(expected.ReadGeneration);
26+
await Assert.That(actual.MinimumReaderContract).IsEqualTo(expected.MinimumReaderContract);
27+
}
28+
29+
internal static async Task AssertRecordAsync(ZoneTreeStore store, byte[] key, byte[] expectedValue)
30+
{
31+
var actual = store.Read(view => view.ReadOwnedValue(key));
32+
await Assert.That(actual).IsNotNull();
33+
await Assert.That(actual!.SequenceEqual(expectedValue)).IsTrue();
34+
}
35+
}

‎tests/KeyLoad.UnitTests/Features/StorageRecovery/Cases/NativeReadCutLifetimeTests.cs‎

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using KeyLoad.UnitTests.Features.StorageRecovery.Assertions;
2+
13
namespace KeyLoad.UnitTests.Features.StorageRecovery;
24

35
internal sealed class NativeReadCutLifetimeTests
@@ -81,7 +83,13 @@ await KeyLoad.Server.ServerFailureObserver.ObserveAsync(async () =>
8183
public async Task AcCut003ShutdownCancelsAndJoinsTraversalBeforeReopen()
8284
{
8385
using var fixture = new NativeReadCutFixture();
84-
fixture.Store.Commit((tx, _) => { tx.Put(NativeReadCutFixture.Key(RecordId), NativeReadCutFixture.Value(RecordValue)); return true; });
86+
var originalKey = NativeReadCutFixture.Key(RecordId);
87+
var expectedOriginalValue = NativeReadCutFixture.Value(RecordValue);
88+
fixture.Store.Commit((tx, _) => { tx.Put(originalKey, expectedOriginalValue); return true; });
89+
var expectedIdentity = NativeReadCutStoreStateAssertions.SnapshotIdentity(fixture.Store);
90+
var originalPosition = fixture.Store.Position;
91+
var originalValue = fixture.Store.Read(view => view.ReadOwnedValue(originalKey))!.ToArray();
92+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, originalKey, expectedOriginalValue);
8593
var lease = fixture.Capture(NativeReadCutFixture.Limits(4, 128));
8694
using var entered = new ManualResetEventSlim();
8795
var traversal = Task.Run(() => lease.VisitPrefix(NativeReadCutFixture.Key(string.Empty), (_, _) =>
@@ -103,7 +111,25 @@ public async Task AcCut003ShutdownCancelsAndJoinsTraversalBeforeReopen()
103111
await Assert.ThrowsExactlyAsync<OperationCanceledException>(async () => await traversal);
104112
await disposal;
105113
fixture.Reopen();
106-
await Assert.That(fixture.Store.Read(view => view.ReadOwnedValue(NativeReadCutFixture.Key(RecordId)) is not null)).IsTrue();
114+
await NativeReadCutStoreStateAssertions.AssertIdentityAndPositionAsync(fixture.Store, expectedIdentity, originalPosition);
115+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, originalKey, originalValue);
116+
117+
var followUpKey = NativeReadCutFixture.Key("two");
118+
var followUpValue = NativeReadCutFixture.Value("healthy");
119+
var followUpPosition = fixture.Store.Commit((tx, proposedPosition) =>
120+
{
121+
tx.Put(followUpKey, followUpValue);
122+
return proposedPosition;
123+
});
124+
await Assert.That(followUpPosition).IsEqualTo(originalPosition + 1);
125+
await NativeReadCutStoreStateAssertions.AssertIdentityAndPositionAsync(fixture.Store, expectedIdentity, followUpPosition);
126+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, originalKey, originalValue);
127+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, followUpKey, followUpValue);
128+
129+
fixture.Reopen();
130+
await NativeReadCutStoreStateAssertions.AssertIdentityAndPositionAsync(fixture.Store, expectedIdentity, followUpPosition);
131+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, originalKey, originalValue);
132+
await NativeReadCutStoreStateAssertions.AssertRecordAsync(fixture.Store, followUpKey, followUpValue);
107133
lease.Dispose();
108134
}
109135

0 commit comments

Comments
 (0)