Files
srdb/sst/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

285 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}