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
This commit is contained in:
284
sst/manager.go
Normal file
284
sst/manager.go
Normal file
@@ -0,0 +1,284 @@
|
||||
package sst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Manager SST 文件管理器
|
||||
type Manager struct {
|
||||
dir string
|
||||
readers []*Reader
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewManager 创建 SST 管理器
|
||||
func NewManager(dir string) (*Manager, error) {
|
||||
// 确保目录存在
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mgr := &Manager{
|
||||
dir: dir,
|
||||
readers: make([]*Reader, 0),
|
||||
}
|
||||
|
||||
// 恢复现有的 SST 文件
|
||||
err = mgr.recover()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mgr, nil
|
||||
}
|
||||
|
||||
// recover 恢复现有的 SST 文件
|
||||
func (m *Manager) recover() error {
|
||||
// 查找所有 SST 文件
|
||||
files, err := filepath.Glob(filepath.Join(m.dir, "*.sst"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
// 跳过索引文件
|
||||
filename := filepath.Base(file)
|
||||
if strings.HasPrefix(filename, "idx_") {
|
||||
continue
|
||||
}
|
||||
|
||||
// 打开 SST Reader
|
||||
reader, err := NewReader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.readers = append(m.readers, reader)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSST 创建新的 SST 文件
|
||||
// fileNumber: 文件编号(由 VersionSet 分配)
|
||||
func (m *Manager) CreateSST(fileNumber int64, rows []*Row) (*Reader, error) {
|
||||
return m.CreateSSTWithLevel(fileNumber, rows, 0) // 默认创建到 L0
|
||||
}
|
||||
|
||||
// CreateSSTWithLevel 创建新的 SST 文件到指定层级
|
||||
// fileNumber: 文件编号(由 VersionSet 分配)
|
||||
func (m *Manager) CreateSSTWithLevel(fileNumber int64, rows []*Row, level int) (*Reader, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
sstPath := filepath.Join(m.dir, fmt.Sprintf("%06d.sst", fileNumber))
|
||||
|
||||
// 创建文件
|
||||
file, err := os.Create(sstPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
writer := NewWriter(file)
|
||||
|
||||
// 写入所有行
|
||||
for _, row := range rows {
|
||||
err = writer.Add(row)
|
||||
if err != nil {
|
||||
file.Close()
|
||||
os.Remove(sstPath)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 完成写入
|
||||
err = writer.Finish()
|
||||
if err != nil {
|
||||
file.Close()
|
||||
os.Remove(sstPath)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// 打开 SST Reader
|
||||
reader, err := NewReader(sstPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 添加到 readers 列表
|
||||
m.readers = append(m.readers, reader)
|
||||
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
// Get 从所有 SST 文件中查找数据
|
||||
func (m *Manager) Get(seq int64) (*Row, error) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
// 从后往前查找(新的文件优先)
|
||||
for i := len(m.readers) - 1; i >= 0; i-- {
|
||||
reader := m.readers[i]
|
||||
row, err := reader.Get(seq)
|
||||
if err == nil {
|
||||
return row, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("key not found: %d", seq)
|
||||
}
|
||||
|
||||
// GetReaders 获取所有 Readers(用于扫描)
|
||||
func (m *Manager) GetReaders() []*Reader {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
// 返回副本
|
||||
readers := make([]*Reader, len(m.readers))
|
||||
copy(readers, m.readers)
|
||||
return readers
|
||||
}
|
||||
|
||||
// GetMaxSeq 获取所有 SST 中的最大 seq
|
||||
func (m *Manager) GetMaxSeq() int64 {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
maxSeq := int64(0)
|
||||
for _, reader := range m.readers {
|
||||
header := reader.GetHeader()
|
||||
if header.MaxKey > maxSeq {
|
||||
maxSeq = header.MaxKey
|
||||
}
|
||||
}
|
||||
|
||||
return maxSeq
|
||||
}
|
||||
|
||||
// Count 获取 SST 文件数量
|
||||
func (m *Manager) Count() int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
return len(m.readers)
|
||||
}
|
||||
|
||||
// ListFiles 列出所有 SST 文件
|
||||
func (m *Manager) ListFiles() []string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
files := make([]string, 0, len(m.readers))
|
||||
for _, reader := range m.readers {
|
||||
files = append(files, reader.path)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
// CompactionConfig Compaction 配置
|
||||
// 已废弃:请使用 compaction 包中的 Manager
|
||||
type CompactionConfig struct {
|
||||
Threshold int // 触发阈值(SST 文件数量)
|
||||
BatchSize int // 每次合并的文件数量
|
||||
}
|
||||
|
||||
// DefaultCompactionConfig 默认配置
|
||||
// 已废弃:请使用 compaction 包中的 Manager
|
||||
var DefaultCompactionConfig = CompactionConfig{
|
||||
Threshold: 10,
|
||||
BatchSize: 10,
|
||||
}
|
||||
|
||||
// ShouldCompact 检查是否需要 Compaction
|
||||
// 已废弃:请使用 compaction 包中的 Manager
|
||||
func (m *Manager) ShouldCompact(config CompactionConfig) bool {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
return len(m.readers) > config.Threshold
|
||||
}
|
||||
|
||||
// Compact 执行 Compaction
|
||||
// 已废弃:请使用 compaction 包中的 Manager
|
||||
// 注意:此方法已不再维护,不应在新代码中使用
|
||||
func (m *Manager) Compact(config CompactionConfig) error {
|
||||
// 此方法已废弃,不再实现
|
||||
return fmt.Errorf("Compact is deprecated, please use compaction.Manager")
|
||||
}
|
||||
|
||||
// sortRows 按 seq 排序
|
||||
func sortRows(rows []*Row) {
|
||||
sort.Slice(rows, func(i, j int) bool {
|
||||
return rows[i].Seq < rows[j].Seq
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除指定的 SST 文件(预留接口)
|
||||
func (m *Manager) Delete(fileNumber int64) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
sstPath := filepath.Join(m.dir, fmt.Sprintf("%06d.sst", fileNumber))
|
||||
return os.Remove(sstPath)
|
||||
}
|
||||
|
||||
// Close 关闭所有 SST Readers
|
||||
func (m *Manager) Close() error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
for _, reader := range m.readers {
|
||||
reader.Close()
|
||||
}
|
||||
|
||||
m.readers = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stats 统计信息
|
||||
type Stats struct {
|
||||
FileCount int
|
||||
TotalSize int64
|
||||
MinSeq int64
|
||||
MaxSeq int64
|
||||
}
|
||||
|
||||
// GetStats 获取统计信息
|
||||
func (m *Manager) GetStats() *Stats {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
stats := &Stats{
|
||||
FileCount: len(m.readers),
|
||||
MinSeq: -1,
|
||||
MaxSeq: -1,
|
||||
}
|
||||
|
||||
for _, reader := range m.readers {
|
||||
header := reader.GetHeader()
|
||||
|
||||
if stats.MinSeq == -1 || header.MinKey < stats.MinSeq {
|
||||
stats.MinSeq = header.MinKey
|
||||
}
|
||||
|
||||
if stats.MaxSeq == -1 || header.MaxKey > stats.MaxSeq {
|
||||
stats.MaxSeq = header.MaxKey
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
if stat, err := os.Stat(reader.path); err == nil {
|
||||
stats.TotalSize += stat.Size()
|
||||
}
|
||||
}
|
||||
|
||||
return stats
|
||||
}
|
||||
Reference in New Issue
Block a user