Files
dailz cf913b1d52 feat: initialize project structure and error types
- go.mod with github.com/dailz/go-kv, Go 1.26.3, testify
- config/config.go with WalConfig, Validate() with checked arithmetic
- errors.go with sentinel errors (ErrCommitUnknown, ErrWriteStopped, etc.)
- wal/constants.go with all WAL format constants and enums
- wal/header.go with WAL File Header encode/decode (CRC32 IEEE)
- wal/record.go with Physical Record codec, block boundary, SplitIntoRecords
- wal/entry.go with WAL Entry codec (varint keys/values, OpType, ValueKind)
- wal/sequence.go with SequenceManager (atomic, CAS, overflow-safe)
- manifest/manifest.go with MANIFEST stub (Load/Save atomic)
- manifest/current.go with CURRENT file (WriteCurrent/ReadCurrent)
- Comprehensive tests for all modules
- .golangci.yml configuration
2026-06-12 13:23:27 +08:00

53 lines
1.5 KiB
Go

package manifest
import (
"fmt"
"os"
"strconv"
"strings"
)
// Manifest holds database metadata used for recovery.
// The MANIFEST file stores the recovery checkpoint so that
// recovery knows which segments are already confirmed durable.
type Manifest struct {
RecoverySegmentID uint64
}
// Load reads the MANIFEST file from dir.
// If the file does not exist, it returns a zero-value Manifest with no error (fresh DB).
func Load(dir string) (*Manifest, error) {
path := dir + "/MANIFEST"
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return &Manifest{RecoverySegmentID: 0}, nil
}
return nil, fmt.Errorf("read manifest: %w", err)
}
line := strings.TrimSpace(string(data))
if !strings.HasPrefix(line, "recovery_segment_id:") {
return nil, fmt.Errorf("manifest: invalid format: %q", line)
}
idStr := strings.TrimPrefix(line, "recovery_segment_id:")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
return nil, fmt.Errorf("manifest: parse recovery_segment_id: %w", err)
}
return &Manifest{RecoverySegmentID: id}, nil
}
// Save atomically writes the MANIFEST file to dir with the given recoverySegmentID.
func Save(dir string, recoverySegmentID uint64) error {
content := fmt.Sprintf("recovery_segment_id:%d\n", recoverySegmentID)
tmpPath := dir + "/MANIFEST.tmp"
if err := os.WriteFile(tmpPath, []byte(content), 0o644); err != nil {
return fmt.Errorf("write manifest tmp: %w", err)
}
if err := os.Rename(tmpPath, dir+"/MANIFEST"); err != nil {
return fmt.Errorf("rename manifest: %w", err)
}
return nil
}