6 Commits
Author SHA1 Message Date
dailz 408138b3c8 fix: prevent send-on-closed-channel panic in concurrent Put/Delete + Close (C7)
Put/Delete checked writeStopped then called queue.Submit (which sends on
a channel). Close set writeStopped then closed the channel. With no
synchronization between the check and Submit, a concurrent Close could
close the channel during the window, causing "send on closed channel"
panic in Put/Delete.

The CommitQueue.Close comment said "Callers must stop submitting before
Close" but Put/Delete didn't enforce this.

Changes:
- wal/writer.go: add submitMu sync.RWMutex. Put/Delete construct entry
  outside the lock, then hold RLock during writeStopped check + Submit;
  release before <-req.Result. Close holds write lock during
  writeStopped.Store + queue.Close, guaranteeing no Submit is in progress
  when the channel is closed.
- wal/writer_test.go: add TestConcurrentPutCloseNoPanic and
  TestConcurrentDeleteCloseNoPanic. 100 goroutines + 1 closer, recover
  panics. Run with -count=50 for regression detection.

Verified: all existing tests pass. New concurrent tests pass with
-count=50 (0 panics). go test -race ./... green.

Audit context: docs/audit-3.2.md C7.
2026-06-18 13:25:30 +08:00
dailz 108059146d fix: write correct startSequence on segment rotation (C8)
SegmentManager.AppendBatch was passing sm.active.CurrentOffset() (byte
offset from file header) as the new segment's startSequence on rotation.
The result: segment-N+1's header.startSequence was a byte count (e.g.
50000), not the actual sequence number. Recovery's continuity check at
recovery.go:181-184 (segment.StartSequence != expectedSequence) failed,
making Phase 1 multi-segment recovery completely broken.

Oracle bg_ef425776 noted: "C8 是隐藏炸弹:单 segment 时一切正常,
第一次轮转后就坏".

Changes:
- wal/segment_manager.go: AppendBatch now takes batchStartSequence uint64
  parameter. On rotation, passes it to rotate (which writes it to the new
  segment's header.startSequence). The previous byte-offset argument is
  replaced by the actual sequence number.
- wal/writer.go: processBatch passes baseSequence (already allocated by
  seqManager.AllocateBatch) to AppendBatch.
- wal/segment_manager_test.go: 6 existing AppendBatch call sites updated
  to pass batchStartSequence (tracked via local currentSeq variable).
  Added 2 new tests:
  - TestSegmentManagerRotationWritesCorrectStartSequence: verifies new
    segment's header.startSequence matches the first rotated batch's
    sequence (and explicitly != old byte offset, catching C8 regression).
  - TestSegmentManagerMultiSegmentRecoveryRoundTrip: end-to-end test that
    writes across multiple segments, closes, recovers, and verifies all
    batches replay. Before C8 fix, recovery failed at continuity check.

Verified: each new test fails on pre-fix code (segment-1 startSequence
is byte offset, recovery fails) and passes after the fix. Full suite
green including go test -race ./... .

Audit context: docs/audit-3.2.md C8 (Oracle-discovered bg_2e86d33b).
2026-06-17 16:34:28 +08:00
dailz e34de4acc9 fix: implement group commit collection window (500µs or 32KB)
Replace polling loop (Collect + Sleep) with proper batch collection:
- Block on first request via channel receive
- Start 500µs timer for collection window
- Accumulate requests until timer fires or batch reaches 32KB
- Shutdown handling at all blocking points

Design doc §3.2.5: '等待组提交触发(500µs 或 32KB,先到者触发)'

Add GroupCommitDelay config field (default 500µs, must be > 0 and < 10ms).
2026-06-12 16:15:08 +08:00
dailz b833a21848 fix: address Final Verification Wave findings
- Sync() now flushes BlockWriter before fd.Sync() for durability
- Pre-validate encoding before sequence allocation (design doc compliance)
- Remove dead _ = rec assignment in recover.go
- Remove unused maxPayload field from SegmentWriter
- Handle Put error in MemTable.Publish with panic on invariant violation
2026-06-12 14:29:53 +08:00
dailz 0fe1530e25 feat: integrate DB with Open/Close/Put/Delete/Get
- Add db.go with DB struct: Open/Close/Put/Delete/Get/GetDurableSequence/IsWriteStopped
- Add db_test.go with lifecycle, put/get, delete, recovery, and corruption tests
- Extract sentinel errors to errkit/ leaf package to break import cycle (wal -> go_kv)
- Update wal/sequence.go, wal/writer.go to import errkit instead of root package
- Root errors.go re-exports from errkit for backward compatibility

Phase 1 Wave 4d complete (T19).
2026-06-12 14:10:56 +08:00
dailz fe2d4fc5f0 feat(wal): implement WAL writer with group commit and recovery batch replay
- wal/commit_queue.go: bounded buffered channel for write requests
- wal/writer.go: single-goroutine main loop implementing 11-step write flow
  with group commit, sequence allocation, MemTable publish/abort, write-stopped
- wal/recovery.go: BatchReplayer interface, ReplayBatch, ReplaySegmentFile,
  RecoverFromSegments with fragment reassembly and tail corruption handling
- Comprehensive tests for all modules, all pass with -race
2026-06-12 13:57:31 +08:00