mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-14 18:18:35 +02:00
feat: protocol-aware execution wave — phase gate for live WAL shipping
Add host-side protocol state seam that derives per-replica execution state from V2 sender/session snapshots and blocks live-tail WAL shipping while an active recovery session is in progress. New file: weed/server/block_protocol_state.go - replicaProtocolExecutionState derived from engine snapshots - LiveEligible=false during active catch-up/rebuild sessions - bindProtocolExecutionPolicy wires policy into BlockVol - syncProtocolExecutionState called after assignments + core events Data plane changes: - WALShipper.Ship() checks liveShippingPolicy before dial/send - BlockVol.SetLiveShippingPolicy persists across shipper group rebuilds - ShipperGroup propagates policy to all shippers Design contract: sw-block/design/v2-protocol-aware-execution.md Scope: WAL-first rollout only. Prevents illegal live-tail delivery during active recovery. Does not change snapshot/build behavior or move backlog. Next wave: bounded WAL catch-up under same contract. Tests: 4 unit/component tests for phase gate behavior, plus bootstrap seam tests that confirmed the two pre-existing bugs locally. 13 files changed, 900 insertions, 69 deletions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f8e8c2c4d1
commit
d1a16fac03
17 files changed
+1631
-69
No files matched your search
@@ -187,6 +187,47 @@ func TestQueue_ConfirmFromHeartbeat_SameEpochRefreshWaitsForReplicaTransport(t *
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueue_ConfirmFromHeartbeat_PrimaryRefreshWaitsForCoreProjectionTransition(t *testing.T) {
|
||||
q := NewBlockAssignmentQueue()
|
||||
refresh := mkAssign("/a.blk", 5, 1)
|
||||
refresh.ReplicaAddrs = []blockvol.ReplicaAddr{{
|
||||
DataAddr: "10.0.0.2:14260",
|
||||
CtrlAddr: "10.0.0.2:14261",
|
||||
ServerID: "vs2",
|
||||
}}
|
||||
refresh.ReplicaDataAddr = "10.0.0.2:14260"
|
||||
refresh.ReplicaCtrlAddr = "10.0.0.2:14261"
|
||||
refresh.ReplicaServerID = "vs2"
|
||||
q.Enqueue("s1", refresh)
|
||||
|
||||
// Legacy transport fields alone are not enough for a primary refresh if the
|
||||
// local core still projects allocated_only. Otherwise the refresh can be
|
||||
// dropped before the VS actually re-applies replica membership to the core.
|
||||
q.ConfirmFromHeartbeat("s1", []blockvol.BlockVolumeInfoMessage{{
|
||||
Path: "/a.blk",
|
||||
Epoch: 5,
|
||||
ReplicaDataAddr: "10.0.0.2:14260",
|
||||
ReplicaCtrlAddr: "10.0.0.2:14261",
|
||||
EngineProjectionMode: "allocated_only",
|
||||
}})
|
||||
if q.Pending("s1") != 1 {
|
||||
t.Fatalf("allocated_only primary should not confirm refresh early, pending=%d", q.Pending("s1"))
|
||||
}
|
||||
|
||||
// Once the local core leaves allocated_only, the same heartbeat transport
|
||||
// now proves the refresh reached the V2 projection layer.
|
||||
q.ConfirmFromHeartbeat("s1", []blockvol.BlockVolumeInfoMessage{{
|
||||
Path: "/a.blk",
|
||||
Epoch: 5,
|
||||
ReplicaDataAddr: "10.0.0.2:14260",
|
||||
ReplicaCtrlAddr: "10.0.0.2:14261",
|
||||
EngineProjectionMode: "bootstrap_pending",
|
||||
}})
|
||||
if q.Pending("s1") != 0 {
|
||||
t.Fatalf("expected refresh assignment to confirm after projection transition, pending=%d", q.Pending("s1"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueue_PeekPrunesStaleEpochs(t *testing.T) {
|
||||
q := NewBlockAssignmentQueue()
|
||||
q.Enqueue("s1", mkAssign("/a.blk", 1, 1)) // stale
|
||||
|
||||
Reference in new issue
Block a user