Files
srdb/wal/manager.go
bourdon ae87c38776 Initial commit: SRDB - High-performance LSM-Tree database
- Core engine with MemTable, SST, WAL
- B+Tree indexing for SST files  
- Leveled compaction strategy
- Multi-table database management
- Schema validation and secondary indexes
- Query builder with complex conditions
- Web UI with HTMX for data visualization
- Command-line tools for diagnostics
2025-10-08 06:38:28 +08:00

207 lines
3.8 KiB
Go

package wal
import (
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
)
// Manager WAL 管理器,管理多个 WAL 文件
type Manager struct {
dir string
currentWAL *WAL
currentNumber int64
mu sync.Mutex
}
// NewManager 创建 WAL 管理器
func NewManager(dir string) (*Manager, error) {
// 确保目录存在
err := os.MkdirAll(dir, 0755)
if err != nil {
return nil, err
}
// 读取当前 WAL 编号
number, err := readCurrentNumber(dir)
if err != nil {
// 如果读取失败,从 1 开始
number = 1
}
// 打开当前 WAL
walPath := filepath.Join(dir, fmt.Sprintf("%06d.wal", number))
wal, err := Open(walPath)
if err != nil {
return nil, err
}
// 保存当前编号
err = saveCurrentNumber(dir, number)
if err != nil {
wal.Close()
return nil, err
}
return &Manager{
dir: dir,
currentWAL: wal,
currentNumber: number,
}, nil
}
// Append 追加记录到当前 WAL
func (m *Manager) Append(entry *Entry) error {
m.mu.Lock()
defer m.mu.Unlock()
return m.currentWAL.Append(entry)
}
// Sync 同步当前 WAL 到磁盘
func (m *Manager) Sync() error {
m.mu.Lock()
defer m.mu.Unlock()
return m.currentWAL.Sync()
}
// Rotate 切换到新的 WAL 文件
func (m *Manager) Rotate() (int64, error) {
m.mu.Lock()
defer m.mu.Unlock()
// 记录旧的 WAL 编号
oldNumber := m.currentNumber
// 关闭当前 WAL
err := m.currentWAL.Close()
if err != nil {
return 0, err
}
// 创建新 WAL
m.currentNumber++
walPath := filepath.Join(m.dir, fmt.Sprintf("%06d.wal", m.currentNumber))
wal, err := Open(walPath)
if err != nil {
return 0, err
}
m.currentWAL = wal
// 更新 CURRENT 文件
err = saveCurrentNumber(m.dir, m.currentNumber)
if err != nil {
return 0, err
}
return oldNumber, nil
}
// Delete 删除指定的 WAL 文件
func (m *Manager) Delete(number int64) error {
m.mu.Lock()
defer m.mu.Unlock()
walPath := filepath.Join(m.dir, fmt.Sprintf("%06d.wal", number))
return os.Remove(walPath)
}
// GetCurrentNumber 获取当前 WAL 编号
func (m *Manager) GetCurrentNumber() int64 {
m.mu.Lock()
defer m.mu.Unlock()
return m.currentNumber
}
// RecoverAll 恢复所有 WAL 文件
func (m *Manager) RecoverAll() ([]*Entry, error) {
// 查找所有 WAL 文件
pattern := filepath.Join(m.dir, "*.wal")
files, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
if len(files) == 0 {
return nil, nil
}
// 按文件名排序(确保按时间顺序)
sort.Strings(files)
var allEntries []*Entry
// 依次读取每个 WAL
for _, file := range files {
reader, err := NewReader(file)
if err != nil {
continue
}
entries, err := reader.Read()
reader.Close()
if err != nil {
continue
}
allEntries = append(allEntries, entries...)
}
return allEntries, nil
}
// ListWALFiles 列出所有 WAL 文件
func (m *Manager) ListWALFiles() ([]string, error) {
pattern := filepath.Join(m.dir, "*.wal")
files, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
sort.Strings(files)
return files, nil
}
// Close 关闭 WAL 管理器
func (m *Manager) Close() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.currentWAL != nil {
return m.currentWAL.Close()
}
return nil
}
// readCurrentNumber 读取当前 WAL 编号
func readCurrentNumber(dir string) (int64, error) {
currentPath := filepath.Join(dir, "CURRENT")
data, err := os.ReadFile(currentPath)
if err != nil {
return 0, err
}
number, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64)
if err != nil {
return 0, err
}
return number, nil
}
// saveCurrentNumber 保存当前 WAL 编号
func saveCurrentNumber(dir string, number int64) error {
currentPath := filepath.Join(dir, "CURRENT")
data := []byte(fmt.Sprintf("%d\n", number))
return os.WriteFile(currentPath, data, 0644)
}