Files
srdb/manifest/version_set.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

252 lines
4.8 KiB
Go

package manifest
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"
)
// VersionSet 版本集合管理器
type VersionSet struct {
// 当前版本
current *Version
// MANIFEST 文件
manifestFile *os.File
manifestWriter *Writer
manifestNumber int64
// 下一个文件编号
nextFileNumber atomic.Int64
// 最后序列号
lastSequence atomic.Int64
// 目录
dir string
// 锁
mu sync.RWMutex
}
// NewVersionSet 创建版本集合
func NewVersionSet(dir string) (*VersionSet, error) {
vs := &VersionSet{
dir: dir,
}
// 确保目录存在
err := os.MkdirAll(dir, 0755)
if err != nil {
return nil, err
}
// 读取 CURRENT 文件
currentFile := filepath.Join(dir, "CURRENT")
data, err := os.ReadFile(currentFile)
if err != nil {
// CURRENT 不存在,创建新的 MANIFEST
return vs, vs.createNewManifest()
}
// 读取 MANIFEST 文件
manifestName := strings.TrimSpace(string(data))
manifestPath := filepath.Join(dir, manifestName)
// 恢复版本信息
version, err := vs.recoverFromManifest(manifestPath)
if err != nil {
return nil, err
}
vs.current = version
vs.nextFileNumber.Store(version.NextFileNumber)
vs.lastSequence.Store(version.LastSequence)
// 解析 MANIFEST 编号
fmt.Sscanf(manifestName, "MANIFEST-%d", &vs.manifestNumber)
// 打开 MANIFEST 用于追加
file, err := os.OpenFile(manifestPath, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
vs.manifestFile = file
vs.manifestWriter = NewWriter(file)
return vs, nil
}
// createNewManifest 创建新的 MANIFEST
func (vs *VersionSet) createNewManifest() error {
// 生成新的 MANIFEST 文件名
vs.manifestNumber = vs.nextFileNumber.Add(1)
manifestName := fmt.Sprintf("MANIFEST-%06d", vs.manifestNumber)
manifestPath := filepath.Join(vs.dir, manifestName)
// 创建 MANIFEST 文件
file, err := os.Create(manifestPath)
if err != nil {
return err
}
vs.manifestFile = file
vs.manifestWriter = NewWriter(file)
// 创建初始版本
vs.current = NewVersion()
// 写入初始版本
edit := NewVersionEdit()
nextFile := vs.manifestNumber
edit.SetNextFileNumber(nextFile)
lastSeq := int64(0)
edit.SetLastSequence(lastSeq)
err = vs.manifestWriter.WriteEdit(edit)
if err != nil {
return err
}
// 同步到磁盘
err = vs.manifestFile.Sync()
if err != nil {
return err
}
// 更新 CURRENT 文件
return vs.updateCurrent(manifestName)
}
// recoverFromManifest 从 MANIFEST 恢复版本
func (vs *VersionSet) recoverFromManifest(manifestPath string) (*Version, error) {
// 打开 MANIFEST 文件
file, err := os.Open(manifestPath)
if err != nil {
return nil, err
}
defer file.Close()
reader := NewReader(file)
// 创建初始版本
version := NewVersion()
// 读取所有 VersionEdit
for {
edit, err := reader.ReadEdit()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
// 应用变更
version.Apply(edit)
}
return version, nil
}
// updateCurrent 更新 CURRENT 文件
func (vs *VersionSet) updateCurrent(manifestName string) error {
currentPath := filepath.Join(vs.dir, "CURRENT")
tmpPath := currentPath + ".tmp"
// 1. 写入临时文件
err := os.WriteFile(tmpPath, []byte(manifestName+"\n"), 0644)
if err != nil {
return err
}
// 2. 原子性重命名
err = os.Rename(tmpPath, currentPath)
if err != nil {
os.Remove(tmpPath)
return err
}
return nil
}
// LogAndApply 记录并应用版本变更
func (vs *VersionSet) LogAndApply(edit *VersionEdit) error {
vs.mu.Lock()
defer vs.mu.Unlock()
// 1. 创建新版本
newVersion := vs.current.Clone()
// 2. 应用变更
newVersion.Apply(edit)
// 3. 写入 MANIFEST
err := vs.manifestWriter.WriteEdit(edit)
if err != nil {
return err
}
// 4. 同步到磁盘
err = vs.manifestFile.Sync()
if err != nil {
return err
}
// 5. 更新当前版本
vs.current = newVersion
// 6. 更新原子变量
if edit.NextFileNumber != nil {
vs.nextFileNumber.Store(*edit.NextFileNumber)
}
if edit.LastSequence != nil {
vs.lastSequence.Store(*edit.LastSequence)
}
return nil
}
// GetCurrent 获取当前版本
func (vs *VersionSet) GetCurrent() *Version {
vs.mu.RLock()
defer vs.mu.RUnlock()
return vs.current
}
// GetNextFileNumber 获取下一个文件编号
func (vs *VersionSet) GetNextFileNumber() int64 {
return vs.nextFileNumber.Load()
}
// AllocateFileNumber 分配文件编号
func (vs *VersionSet) AllocateFileNumber() int64 {
return vs.nextFileNumber.Add(1)
}
// GetLastSequence 获取最后序列号
func (vs *VersionSet) GetLastSequence() int64 {
return vs.lastSequence.Load()
}
// SetLastSequence 设置最后序列号
func (vs *VersionSet) SetLastSequence(seq int64) {
vs.lastSequence.Store(seq)
}
// Close 关闭 VersionSet
func (vs *VersionSet) Close() error {
vs.mu.Lock()
defer vs.mu.Unlock()
if vs.manifestFile != nil {
return vs.manifestFile.Close()
}
return nil
}