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).
This commit is contained in:
+4
-4
@@ -3,7 +3,7 @@ package wal
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/dailz/go-kv"
|
||||
"github.com/dailz/go-kv/errkit"
|
||||
)
|
||||
|
||||
// SequenceManager manages monotonic sequence number allocation for the WAL.
|
||||
@@ -29,16 +29,16 @@ func NewSequenceManager(recoveredSequence uint64) *SequenceManager {
|
||||
// Returns ErrSequenceExhausted if count is 0 or the allocation would overflow uint64.
|
||||
func (sm *SequenceManager) AllocateBatch(count uint32) (baseSequence uint64, err error) {
|
||||
if count == 0 {
|
||||
return 0, go_kv.ErrSequenceExhausted
|
||||
return 0, errkit.ErrSequenceExhausted
|
||||
}
|
||||
for {
|
||||
if sm.exhausted.Load() {
|
||||
return 0, go_kv.ErrSequenceExhausted
|
||||
return 0, errkit.ErrSequenceExhausted
|
||||
}
|
||||
base := sm.nextSequence.Load()
|
||||
last := base + uint64(count) - 1
|
||||
if last < base {
|
||||
return 0, go_kv.ErrSequenceExhausted
|
||||
return 0, errkit.ErrSequenceExhausted
|
||||
}
|
||||
newNext := last + 1
|
||||
if !sm.nextSequence.CompareAndSwap(base, newNext) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/dailz/go-kv"
|
||||
"github.com/dailz/go-kv/errkit"
|
||||
)
|
||||
|
||||
func TestSequenceAllocation(t *testing.T) {
|
||||
@@ -49,7 +49,7 @@ func TestSequenceOverflow(t *testing.T) {
|
||||
// Remaining: MaxUint64-2, MaxUint64-1, MaxUint64 = 3 slots.
|
||||
// Asking for 5 should overflow.
|
||||
_, err := sm.AllocateBatch(5)
|
||||
if !errors.Is(err, go_kv.ErrSequenceExhausted) {
|
||||
if !errors.Is(err, errkit.ErrSequenceExhausted) {
|
||||
t.Fatalf("expected ErrSequenceExhausted, got %v", err)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestSequenceOverflow(t *testing.T) {
|
||||
|
||||
// Now any further allocation should fail.
|
||||
_, err = sm.AllocateBatch(1)
|
||||
if !errors.Is(err, go_kv.ErrSequenceExhausted) {
|
||||
if !errors.Is(err, errkit.ErrSequenceExhausted) {
|
||||
t.Fatalf("expected ErrSequenceExhausted after exhaustion, got %v", err)
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func TestZeroCountRejected(t *testing.T) {
|
||||
sm := NewSequenceManager(0)
|
||||
|
||||
_, err := sm.AllocateBatch(0)
|
||||
if !errors.Is(err, go_kv.ErrSequenceExhausted) {
|
||||
if !errors.Is(err, errkit.ErrSequenceExhausted) {
|
||||
t.Fatalf("expected ErrSequenceExhausted for count=0, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -6,7 +6,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
go_kv "github.com/dailz/go-kv"
|
||||
"github.com/dailz/go-kv/errkit"
|
||||
"github.com/dailz/go-kv/config"
|
||||
"github.com/dailz/go-kv/memtable"
|
||||
)
|
||||
@@ -131,7 +131,7 @@ func (ww *WalWriter) processRemaining() {
|
||||
|
||||
func (ww *WalWriter) processBatch(requests []*CommitRequest) {
|
||||
if ww.writeStopped.Load() {
|
||||
ww.sendError(requests, go_kv.ErrWriteStopped)
|
||||
ww.sendError(requests, errkit.ErrWriteStopped)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -159,20 +159,20 @@ func (ww *WalWriter) processBatch(requests []*CommitRequest) {
|
||||
}
|
||||
|
||||
if err := ww.segManager.AppendBatch(encoded); err != nil {
|
||||
ww.stopWithError(requests, go_kv.ErrCommitUnknown)
|
||||
ww.stopWithError(requests, errkit.ErrCommitUnknown)
|
||||
return
|
||||
}
|
||||
|
||||
active := ww.memTables.GetActive()
|
||||
if err := writePending(active, entries, baseSequence); err != nil {
|
||||
abortRange(active, baseSequence, lastSequence)
|
||||
ww.stopWithError(requests, go_kv.ErrCommitUnknown)
|
||||
ww.stopWithError(requests, errkit.ErrCommitUnknown)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ww.segManager.Sync(); err != nil {
|
||||
abortRange(active, baseSequence, lastSequence)
|
||||
ww.stopWithError(requests, go_kv.ErrCommitUnknown)
|
||||
ww.stopWithError(requests, errkit.ErrCommitUnknown)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ func (ww *WalWriter) sendSuccess(requests []*CommitRequest, baseSequence uint64,
|
||||
// Put stores key with value.
|
||||
func (ww *WalWriter) Put(key, value []byte) error {
|
||||
if ww.writeStopped.Load() {
|
||||
return go_kv.ErrWriteStopped
|
||||
return errkit.ErrWriteStopped
|
||||
}
|
||||
|
||||
req := ww.queue.Submit([]*WalEntry{{
|
||||
@@ -279,7 +279,7 @@ func (ww *WalWriter) Put(key, value []byte) error {
|
||||
// Delete removes key.
|
||||
func (ww *WalWriter) Delete(key []byte) error {
|
||||
if ww.writeStopped.Load() {
|
||||
return go_kv.ErrWriteStopped
|
||||
return errkit.ErrWriteStopped
|
||||
}
|
||||
|
||||
req := ww.queue.Submit([]*WalEntry{{
|
||||
|
||||
Reference in New Issue
Block a user