mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-10 00:07:44 +02:00
Batch 7: Command dispatch binding extraction - New weed/server/blockcmd package: CommandHandler interface + DispatchCommands - volume_server_block.go applyCoreCommandsWithAssignment delegates to dispatcher - weed/server still owns RecordCommand, EmitCoreEvent, PublishProjection - v2bridge NOT given command-switch or event-emission semantics Phase 16C: Rebuilding assignment enters core command path Phase 16D: Rebuild recovery-task startup is command-driven Phase 16E: Catch-up recovery-task startup is command-driven Engine refinements: - RecoveryTarget on AssignmentDelivered event - shouldStartRecoveryTask / shouldStartReceiver guards - bootstrapReason: awaiting_rebuild_start Bridge/contract updates: - control_adapter.go: refined translation helpers - contract.go: executor port alignment Migration design docs (Batch 1-3 delivered, design artifacts): - v2-first/second/third-migration-batch.md + task-pack.md - v2-assignment-translation-unification.md - v2-execution-muscles-inventory.md - v2-separation-port-layer-audit.md - v2-legacy-runtime-exit-criteria.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
309 lines
8.1 KiB
Markdown
309 lines
8.1 KiB
Markdown
# V2 First Migration Task Pack
|
|
|
|
Date: 2026-04-04
|
|
Status: delivered
|
|
|
|
## Purpose
|
|
|
|
This note turns the first separation batch into validate-able engineering tasks.
|
|
|
|
Each task must name:
|
|
|
|
1. source
|
|
2. destination
|
|
3. authority rule
|
|
4. adapter boundary
|
|
5. acceptance criteria
|
|
6. validation proof
|
|
|
|
The goal is to make separation work parallelizable without letting `V1`
|
|
runtime-owner behavior silently leak back in.
|
|
|
|
## Shared Rules
|
|
|
|
All tasks in this pack inherit these rules:
|
|
|
|
1. `sw-block` must not directly import `weed/storage/blockvol`
|
|
2. `weed/` may implement ports, but must not redefine semantic truth
|
|
3. each task must move one boundary, not redesign the whole runtime
|
|
4. compatibility guards may stay, but must not be treated as semantic-authority
|
|
proof
|
|
|
|
Existing landing zones already exist:
|
|
|
|
1. `sw-block/bridge/blockvol`
|
|
2. `sw-block/bridge/blockvol/control_adapter.go`
|
|
3. `sw-block/bridge/blockvol/contract.go`
|
|
|
|
So Task A does not begin with package creation. It begins with canonical-rule
|
|
consolidation into the existing `sw-block` bridge layer.
|
|
|
|
## Task A: Canonical Assignment Translation
|
|
|
|
### Goal
|
|
|
|
Make `sw-block` own the canonical helper rules for:
|
|
|
|
1. replica identity
|
|
2. recovery-target mapping
|
|
3. engine replica-assignment packaging
|
|
|
|
### Source
|
|
|
|
1. `weed/storage/blockvol/v2bridge/control.go`
|
|
2. `weed/server/volume_server_block.go`
|
|
|
|
### Destination
|
|
|
|
1. `sw-block/bridge/blockvol/control_adapter.go`
|
|
|
|
### Authority Rule
|
|
|
|
This is semantic translation logic, so the canonical rule belongs in
|
|
`sw-block`, not in product adapters.
|
|
|
|
### Adapter Boundary
|
|
|
|
`weed/` may still:
|
|
|
|
1. parse `BlockVolumeAssignment`
|
|
2. decide which source fields exist on the wire/runtime side
|
|
|
|
`weed/` must not separately redefine:
|
|
|
|
1. `ReplicaID = <volume>/<server>`
|
|
2. `replica -> catchup`
|
|
3. `rebuilding -> rebuild`
|
|
|
|
### Acceptance
|
|
|
|
1. `sw-block` exports canonical helpers for identity and recovery-target mapping
|
|
2. `weed/storage/blockvol/v2bridge/control.go` and
|
|
`weed/server/volume_server_block.go` both use those helpers
|
|
3. no direct address-derived identity logic remains in adapter code
|
|
|
|
### Validation
|
|
|
|
1. `go test ./sw-block/bridge/blockvol`
|
|
2. `go test ./weed/storage/blockvol/v2bridge -run "TestControl_|TestBridge_"`
|
|
3. focused server path still passes:
|
|
- `go test ./weed/server -run "TestBlockService_ApplyAssignments_(PrimaryRole_UsesCoreStartRecoveryTaskForCatchUp|RebuildingRole_UsesCoreRecoveryPathWithoutLegacyDirectStart)"`
|
|
|
|
### Current proof anchors
|
|
|
|
1. `TestControlAdapter_StableIdentity`
|
|
2. `TestControlAdapter_RebuildRoleMapping`
|
|
3. `TestControl_PrimaryAssignment_StableServerID`
|
|
4. `TestControl_RebuildAssignment`
|
|
|
|
## Task B: Reader Port Separation
|
|
|
|
### Goal
|
|
|
|
Separate retained-history state reading as a pure execution muscle behind a
|
|
stable `sw-block` port.
|
|
|
|
### Source
|
|
|
|
1. `weed/storage/blockvol/v2bridge/reader.go`
|
|
|
|
### Destination
|
|
|
|
1. contract remains in `sw-block/bridge/blockvol/contract.go`
|
|
2. implementation stays thin in `weed/storage/blockvol/v2bridge/reader.go`
|
|
3. future code landing zone, if needed:
|
|
- `sw-block/bridge/blockvol/runtime`
|
|
- or equivalent execution package under `sw-block`
|
|
|
|
### Authority Rule
|
|
|
|
Reader logic is not semantic authority. It must only read backend facts and
|
|
project them into the engine-facing retained-history shape.
|
|
|
|
### Adapter Boundary
|
|
|
|
`weed/` may:
|
|
|
|
1. read `BlockVol.StatusSnapshot()`
|
|
2. map backend fields into the contract shape
|
|
|
|
`weed/` must not:
|
|
|
|
1. reinterpret durability meaning
|
|
2. patch semantic fallbacks into the reader
|
|
|
|
### Acceptance
|
|
|
|
1. `BlockVolReader` contract stays complete and stable in `sw-block`
|
|
2. `Reader` remains a thin adapter over real `BlockVol`
|
|
3. `StorageAdapter.GetRetainedHistory()` depends only on the contract, not on
|
|
weed internals
|
|
|
|
### Validation
|
|
|
|
1. `go test ./sw-block/bridge/blockvol`
|
|
2. `go test ./weed/storage/blockvol/v2bridge -run "TestReader_"`
|
|
|
|
### Current proof anchors
|
|
|
|
1. `TestStorageAdapter_RetainedHistoryFromReader`
|
|
2. `TestReader_RealBlockVol_StatusSnapshot`
|
|
3. `TestReader_RealBlockVol_HeadAdvancesWithWrites`
|
|
|
|
## Task C: Pinner Port Separation
|
|
|
|
### Goal
|
|
|
|
Separate WAL/snapshot/full-base hold mechanics as execution muscles behind a
|
|
stable `sw-block` pinning port.
|
|
|
|
### Source
|
|
|
|
1. `weed/storage/blockvol/v2bridge/pinner.go`
|
|
|
|
### Destination
|
|
|
|
1. contract remains in `sw-block/bridge/blockvol/contract.go`
|
|
2. implementation stays thin in `weed/storage/blockvol/v2bridge/pinner.go`
|
|
3. future migration target is a `sw-block`-owned execution-muscle package, with
|
|
weed-side `BlockVol` binding left thin
|
|
|
|
### Authority Rule
|
|
|
|
Hold/release mechanics are execution detail. Recovery policy decides *when* to
|
|
hold; pinner only decides *how* to pin in the backend.
|
|
|
|
### Adapter Boundary
|
|
|
|
`weed/` may:
|
|
|
|
1. wire retention floor into `BlockVol`
|
|
2. validate concrete hold positions against backend state
|
|
|
|
`weed/` must not:
|
|
|
|
1. decide recovery target
|
|
2. redefine which boundary is authoritative
|
|
|
|
### Acceptance
|
|
|
|
1. `BlockVolPinner` is the sole engine-facing pin contract
|
|
2. pinner implementation remains backend-thin and side-effect-local
|
|
3. pin lifecycle symmetry is covered in `sw-block` contract tests
|
|
|
|
### Validation
|
|
|
|
1. `go test ./sw-block/bridge/blockvol`
|
|
2. `go test ./weed/storage/blockvol/v2bridge -run "TestPinner_|TestBridge_"`
|
|
|
|
### Current proof anchors
|
|
|
|
1. `TestStorageAdapter_WALPinRejectsRecycled`
|
|
2. `TestStorageAdapter_SnapshotPinRejectsUntrusted`
|
|
3. `TestStorageAdapter_PinReleaseSymmetry`
|
|
4. `TestPinner_RealBlockVol_HoldWALRetention`
|
|
5. `TestPinner_RealBlockVol_HoldRejectsRecycled`
|
|
|
|
## Task D: Executor Muscle Separation
|
|
|
|
### Goal
|
|
|
|
Separate catch-up / rebuild execution mechanics from `weed/` runtime ownership
|
|
so that executor behavior is treated as a reusable muscle behind
|
|
`sw-block`-owned ports.
|
|
|
|
### Source
|
|
|
|
1. `weed/storage/blockvol/v2bridge/executor.go`
|
|
2. related tests in `weed/storage/blockvol/v2bridge/*transfer*`
|
|
3. related tests in `weed/storage/blockvol/v2bridge/*snapshot*`
|
|
4. related tests in `weed/storage/blockvol/v2bridge/*truncate*`
|
|
|
|
### Destination
|
|
|
|
1. contract shape in `sw-block/bridge/blockvol/contract.go`
|
|
2. engine-facing use through:
|
|
- `engine.CatchUpIO`
|
|
- `engine.RebuildIO`
|
|
3. implementation remains thin in `weed/` until backend-binding interfaces are
|
|
fully extracted
|
|
|
|
### Authority Rule
|
|
|
|
Executor code is allowed to:
|
|
|
|
1. transfer bytes
|
|
2. apply WAL entries
|
|
3. install snapshots/full base
|
|
4. truncate local WAL
|
|
|
|
Executor code is not allowed to:
|
|
|
|
1. classify recovery outcome
|
|
2. decide whether rebuild vs catch-up is needed
|
|
3. own publication or health meaning
|
|
|
|
### Adapter Boundary
|
|
|
|
`weed/` may:
|
|
|
|
1. call real `BlockVol` APIs
|
|
2. speak TCP rebuild/catch-up protocol
|
|
3. update local backend runtime state during execution
|
|
|
|
`weed/` must not:
|
|
|
|
1. redefine engine recovery phases
|
|
2. redefine target/achieved boundary meaning
|
|
|
|
### Acceptance
|
|
|
|
1. `BlockVolExecutor` aligns exactly with engine execution port expectations
|
|
2. engine/executor integration is possible without `sw-block` importing weed
|
|
3. executor logic is documented as reusable execution muscle, not semantic
|
|
authority
|
|
|
|
### Validation
|
|
|
|
1. `go test ./sw-block/bridge/blockvol`
|
|
2. `go test ./weed/storage/blockvol/v2bridge -run "TestExecutor_|TestBridge_"`
|
|
3. focused integrated runtime tests remain green:
|
|
- `go test ./weed/server -run "TestBlockService_ApplyAssignments_(PrimaryRole_UsesCoreStartRecoveryTaskForCatchUp|RebuildingRole_UsesCoreRecoveryPathWithoutLegacyDirectStart)"`
|
|
|
|
### Current proof anchors
|
|
|
|
1. `TestContract_BlockVolReaderInterface`
|
|
2. `TestExecutor_RealBlockVol_StreamWALEntries`
|
|
3. `TestExecutor_RealBlockVol_StreamPartialRange`
|
|
4. `TestExecutor_ErrorPaths`
|
|
|
|
## Parallel Execution Recommendation
|
|
|
|
These four tasks are safe to run in parallel if ownership stays clear:
|
|
|
|
1. Task A: canonical translation rules
|
|
2. Task B: reader port hardening
|
|
3. Task C: pinner port hardening
|
|
4. Task D: executor contract alignment
|
|
|
|
Recommended order for merge:
|
|
|
|
1. Task A
|
|
2. Task B
|
|
3. Task C
|
|
4. Task D
|
|
|
|
Reason:
|
|
|
|
1. Task A removes semantic drift first
|
|
2. Tasks B/C/D then migrate pure muscles behind that stable rule layer
|
|
|
|
## Delivery Note
|
|
|
|
Final outcome:
|
|
|
|
1. Task A required code change and is now delivered
|
|
2. Tasks B/C/D were reviewed and confirmed already at the acceptance bar
|
|
3. the next migration frontier is backend-binding extraction, not more contract
|
|
cleanup
|