mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
Rebuild session protocol implementation for v2-rebuild-mvp-session-protocol.md. New files: - rebuild_bitmap.go: RebuildBitmap — session-scoped dense bitset for WAL-applied LBA tracking. MarkApplied on local WAL write (not receive). ShouldApplyBase returns false for WAL-covered LBAs (WAL always wins). - rebuild_session.go: RebuildSession — replica-side two-line rebuild. WAL lane (ApplyWALEntry) + base lane (ApplyBaseBlock) with bitmap conflict resolution. TryComplete requires BOTH base_complete AND wal_applied_lsn >= target_lsn. Volume-level control surface: StartRebuildSession, ApplyRebuildSessionWALEntry/BaseBlock, MarkRebuildSessionBaseComplete, TryCompleteRebuildSession, CancelRebuildSession, ActiveRebuildSession. - rebuild_mvp_test.go: 4 correctness tests — base+WAL converge, WAL-applied never overwritten by base, bitmap set on applied not received, control surface start/supersede/complete. - rebuild_transport_test.go: 2 transport-level tests — two-line with real WAL shipping, live writes during base copy with bitmap conflict. Design docs: - v2-rebuild-mvp-session-protocol.md: MVP spec with message set, apply rules, completion/failure/crash rules, test matrix - v2-sync-recovery-protocol.md: full protocol context (keepup/catchup/ rebuild unified design, primary decision logic, two-line model) - v2-session-protocol-shape.md: protocol shape overview Protocol engine (reference, not production): - sw-block/protocol/: 7-event engine with ~300 lines, 13 tests 6 rebuild tests pass, all existing component tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85 lines
2.7 KiB
Go
85 lines
2.7 KiB
Go
package blockvol
|
|
|
|
// RebuildBitmap is a session-scoped dense bitset tracking which LBAs have
|
|
// been covered by applied WAL entries during a rebuild session. It is the
|
|
// overwrite protection for the two-line rebuild model:
|
|
//
|
|
// - Line 1 (base lane): snapshot/extent blocks copied to replica
|
|
// - Line 2 (WAL lane): live WAL entries applied to replica local WAL
|
|
//
|
|
// When a base chunk targets an LBA:
|
|
// - bitmap clear → write base data (no conflict)
|
|
// - bitmap set → skip (WAL-applied data is newer, WAL always wins)
|
|
//
|
|
// The bit is set when a WAL entry is APPLIED to the replica's local WAL
|
|
// (replayable after crash), NOT when it is merely received on the network.
|
|
//
|
|
// This bitmap is session-local volatile state. After crash, the rebuild
|
|
// session must restart from scratch with a fresh bitmap. Durable WAL
|
|
// entries survive crash and protect correctness via WAL replay.
|
|
//
|
|
// Implementation is a dense bitset modeled on SnapshotBitmap. No internal
|
|
// locking — callers must serialize access if needed.
|
|
type RebuildBitmap struct {
|
|
data []byte
|
|
totalLBAs uint64 // total number of LBAs (= volumeSize / blockSize)
|
|
blockSize uint32
|
|
appliedCount uint64 // number of LBAs marked as WAL-applied
|
|
}
|
|
|
|
// NewRebuildBitmap creates a zero-initialized rebuild bitmap.
|
|
// totalLBAs = volumeSize / blockSize.
|
|
func NewRebuildBitmap(totalLBAs uint64, blockSize uint32) *RebuildBitmap {
|
|
byteLen := (totalLBAs + 7) / 8
|
|
return &RebuildBitmap{
|
|
data: make([]byte, byteLen),
|
|
totalLBAs: totalLBAs,
|
|
blockSize: blockSize,
|
|
}
|
|
}
|
|
|
|
// MarkApplied sets the bit for the given LBA, indicating that a WAL entry
|
|
// covering this LBA has been applied to the replica's local WAL.
|
|
func (b *RebuildBitmap) MarkApplied(lba uint64) {
|
|
if lba >= b.totalLBAs {
|
|
return
|
|
}
|
|
if !b.IsApplied(lba) {
|
|
b.appliedCount++
|
|
}
|
|
b.data[lba/8] |= 1 << (lba % 8)
|
|
}
|
|
|
|
// IsApplied returns true if the LBA has been covered by an applied WAL entry.
|
|
// When true, base lane data for this LBA must be skipped.
|
|
func (b *RebuildBitmap) IsApplied(lba uint64) bool {
|
|
if lba >= b.totalLBAs {
|
|
return false
|
|
}
|
|
return b.data[lba/8]&(1<<(lba%8)) != 0
|
|
}
|
|
|
|
// ShouldApplyBase returns true if the base lane may write data at this LBA.
|
|
// This is the conflict resolution rule: WAL-applied wins over base.
|
|
func (b *RebuildBitmap) ShouldApplyBase(lba uint64) bool {
|
|
return !b.IsApplied(lba)
|
|
}
|
|
|
|
// AppliedCount returns the number of LBAs marked as WAL-applied.
|
|
func (b *RebuildBitmap) AppliedCount() uint64 {
|
|
return b.appliedCount
|
|
}
|
|
|
|
// TotalLBAs returns the total number of trackable LBAs.
|
|
func (b *RebuildBitmap) TotalLBAs() uint64 {
|
|
return b.totalLBAs
|
|
}
|
|
|
|
// Clear resets the bitmap to all-zero (no LBAs applied).
|
|
func (b *RebuildBitmap) Clear() {
|
|
for i := range b.data {
|
|
b.data[i] = 0
|
|
}
|
|
b.appliedCount = 0
|
|
}
|