285 lines
5.6 KiB
Go
285 lines
5.6 KiB
Go
|
|
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
|
|||
|
|
}
|