文档:更新 DESIGN.md,使用英文注释和调整项目结构说明

This commit is contained in:
2025-10-09 01:33:22 +08:00
parent 6499464f1c
commit 8019f2d794
38 changed files with 4297 additions and 2750 deletions

View File

@@ -3,7 +3,6 @@ package srdb
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"os"
"path/filepath"
@@ -12,7 +11,6 @@ import (
"sync"
"github.com/edsrzf/mmap-go"
"github.com/golang/snappy"
)
const (
@@ -22,13 +20,9 @@ const (
SSTableHeaderSize = 256 // 文件头大小
SSTableBlockSize = 64 * 1024 // 数据块大小 (64 KB)
// 压缩类型
SSTableCompressionNone = 0
SSTableCompressionSnappy = 1
// 二进制编码格式:
// [Magic: 4 bytes][Seq: 8 bytes][Time: 8 bytes][DataLen: 4 bytes][Data: variable]
SSTableRowMagic = 0x524F5733 // "ROW3"
SSTableRowMagic = 0x524F5731 // "ROW1"
)
// SSTableHeader SST 文件头 (256 bytes)
@@ -36,7 +30,7 @@ type SSTableHeader struct {
// 基础信息 (32 bytes)
Magic uint32 // Magic Number: 0x53535433
Version uint32 // 版本号
Compression uint8 // 压缩类型
Compression uint8 // 压缩类型(保留字段用于向后兼容)
Reserved1 [3]byte
Flags uint32 // 标志位
Reserved2 [16]byte
@@ -175,14 +169,9 @@ func encodeSSTableRowBinary(row *SSTableRow, schema *Schema) ([]byte, error) {
return nil, err
}
// 如果没有 Schema,回退到 JSON 编码(只编码 Data 部分Seq/Time 已经写入)
// 强制要求 Schema
if schema == nil {
dataJSON, err := json.Marshal(row.Data)
if err != nil {
return nil, err
}
buf.Write(dataJSON)
return buf.Bytes(), nil
return nil, fmt.Errorf("schema is required for encoding SSTable rows")
}
// 按字段分别编码和压缩
@@ -191,8 +180,8 @@ func encodeSSTableRowBinary(row *SSTableRow, schema *Schema) ([]byte, error) {
return nil, err
}
// 1. 先编码所有字段到各自的 buffer
compressedFields := make([][]byte, len(schema.Fields))
// 1. 先编码所有字段到各自的 buffer(无压缩)
fieldData := make([][]byte, len(schema.Fields))
for i, field := range schema.Fields {
fieldBuf := new(bytes.Buffer)
@@ -209,28 +198,28 @@ func encodeSSTableRowBinary(row *SSTableRow, schema *Schema) ([]byte, error) {
}
}
// 压缩每个字段
compressedFields[i] = snappy.Encode(nil, fieldBuf.Bytes())
// 直接使用二进制数据(无压缩)
fieldData[i] = fieldBuf.Bytes()
}
// 2. 写入字段偏移表(相对于数据区起始位置)
currentOffset := 0
for _, compressed := range compressedFields {
for _, data := range fieldData {
// 写入字段偏移(相对于数据区)
if err := binary.Write(buf, binary.LittleEndian, uint32(currentOffset)); err != nil {
return nil, err
}
// 写入压缩后大小
if err := binary.Write(buf, binary.LittleEndian, uint32(len(compressed))); err != nil {
// 写入数据大小
if err := binary.Write(buf, binary.LittleEndian, uint32(len(data))); err != nil {
return nil, err
}
currentOffset += len(compressed)
currentOffset += len(data)
}
// 3. 写入压缩后的字段数据
for _, compressed := range compressedFields {
if _, err := buf.Write(compressed); err != nil {
// 3. 写入字段数据
for _, data := range fieldData {
if _, err := buf.Write(data); err != nil {
return nil, err
}
}
@@ -341,14 +330,9 @@ func decodeSSTableRowBinaryPartial(data []byte, schema *Schema, fields []string)
return nil, err
}
// 如果没有 Schema,回退到 JSON 解码(读取剩余的 JSON 数据)
// 强制要求 Schema
if schema == nil {
remainingData := data[16:] // Skip Seq (8 bytes) + Time (8 bytes)
row.Data = make(map[string]any)
if err := json.Unmarshal(remainingData, &row.Data); err != nil {
return nil, err
}
return row, nil
return nil, fmt.Errorf("schema is required for decoding SSTable rows")
}
// 读取字段数量
@@ -400,28 +384,22 @@ func decodeSSTableRowBinaryPartial(data []byte, schema *Schema, fields []string)
continue
}
// 读取压缩的字段数据
// 读取字段数据(无压缩)
info := fieldInfos[i]
compressedPos := dataStart + int64(info.offset)
fieldPos := dataStart + int64(info.offset)
// Seek 到字段位置
if _, err := buf.Seek(compressedPos, 0); err != nil {
if _, err := buf.Seek(fieldPos, 0); err != nil {
return nil, fmt.Errorf("seek to field %s: %w", field.Name, err)
}
compressedData := make([]byte, info.size)
if _, err := buf.Read(compressedData); err != nil {
fieldData := make([]byte, info.size)
if _, err := buf.Read(fieldData); err != nil {
return nil, fmt.Errorf("read field %s: %w", field.Name, err)
}
// 解字段数据
decompressed, err := snappy.Decode(nil, compressedData)
if err != nil {
return nil, fmt.Errorf("decompress field %s: %w", field.Name, err)
}
// 解析字段值
fieldBuf := bytes.NewReader(decompressed)
// 解字段值(直接从二进制数据
fieldBuf := bytes.NewReader(fieldData)
value, err := readFieldBinaryValue(fieldBuf, field.Type, true)
if err != nil {
return nil, fmt.Errorf("parse field %s: %w", field.Name, err)
@@ -489,31 +467,29 @@ func readFieldBinaryValue(buf *bytes.Reader, typ FieldType, keep bool) (any, err
// SSTableWriter SST 文件写入器
type SSTableWriter struct {
file *os.File
builder *BTreeBuilder
dataOffset int64
dataStart int64 // 数据起始位置
rowCount int64
minKey int64
maxKey int64
minTime int64
maxTime int64
compression uint8
schema *Schema // Schema 用于优化编码
file *os.File
builder *BTreeBuilder
dataOffset int64
dataStart int64 // 数据起始位置
rowCount int64
minKey int64
maxKey int64
minTime int64
maxTime int64
schema *Schema // Schema 用于优化编码
}
// NewSSTableWriter 创建 SST 写入器
func NewSSTableWriter(file *os.File, schema *Schema) *SSTableWriter {
return &SSTableWriter{
file: file,
builder: NewBTreeBuilder(file, SSTableHeaderSize),
dataOffset: 0, // 先写数据,后面会更新
compression: SSTableCompressionSnappy,
minKey: -1,
maxKey: -1,
minTime: -1,
maxTime: -1,
schema: schema,
file: file,
builder: NewBTreeBuilder(file, SSTableHeaderSize),
dataOffset: 0, // 先写数据,后面会更新
minKey: -1,
maxKey: -1,
minTime: -1,
maxTime: -1,
schema: schema,
}
}
@@ -541,18 +517,13 @@ func (w *SSTableWriter) Add(row *SSTableRow) error {
}
w.rowCount++
// 序列化数据(使用 Schema 优化的二进制格式)
data := encodeSSTableRow(row, w.schema)
// 压缩数据
var compressed []byte
if w.compression == SSTableCompressionSnappy {
compressed = snappy.Encode(nil, data)
} else {
compressed = data
// 序列化数据(使用 Schema 优化的二进制格式,无压缩
data, err := encodeSSTableRow(row, w.schema)
if err != nil {
return fmt.Errorf("encode row: %w", err)
}
// 写入数据块
// 写入数据块(不压缩)
// 第一次写入时,确定数据起始位置
if w.dataStart == 0 {
// 预留足够空间给 B+Tree 索引
@@ -563,19 +534,19 @@ func (w *SSTableWriter) Add(row *SSTableRow) error {
}
offset := w.dataOffset
_, err := w.file.WriteAt(compressed, offset)
_, err = w.file.WriteAt(data, offset)
if err != nil {
return err
}
// 添加到 B+Tree
err = w.builder.Add(row.Seq, offset, int32(len(compressed)))
err = w.builder.Add(row.Seq, offset, int32(len(data)))
if err != nil {
return err
}
// 更新数据偏移
w.dataOffset += int64(len(compressed))
w.dataOffset += int64(len(data))
return nil
}
@@ -595,7 +566,7 @@ func (w *SSTableWriter) Finish() error {
header := &SSTableHeader{
Magic: SSTableMagicNumber,
Version: SSTableVersion,
Compression: w.compression,
Compression: 0, // 不使用压缩(保留字段用于向后兼容)
IndexOffset: SSTableHeaderSize,
IndexSize: indexSize,
RootOffset: rootOffset,
@@ -620,19 +591,13 @@ func (w *SSTableWriter) Finish() error {
}
// encodeSSTableRow 编码行数据 (使用二进制格式)
func encodeSSTableRow(row *SSTableRow, schema *Schema) []byte {
func encodeSSTableRow(row *SSTableRow, schema *Schema) ([]byte, error) {
// 使用二进制格式编码
encoded, err := encodeSSTableRowBinary(row, schema)
if err != nil {
// 降级到 JSON (不应该发生)
data := map[string]any{
"_seq": row.Seq,
"_time": row.Time,
"data": row.Data,
}
encoded, _ = json.Marshal(data)
return nil, fmt.Errorf("failed to encode row: %w", err)
}
return encoded
return encoded, nil
}
// SSTableReader SST 文件读取器
@@ -704,21 +669,9 @@ func (r *SSTableReader) Get(key int64) (*SSTableRow, error) {
return nil, fmt.Errorf("invalid data offset")
}
compressed := r.mmap[dataOffset : dataOffset+int64(dataSize)]
data := r.mmap[dataOffset : dataOffset+int64(dataSize)]
// 4. 压缩
var data []byte
var err error
if r.header.Compression == SSTableCompressionSnappy {
data, err = snappy.Decode(nil, compressed)
if err != nil {
return nil, err
}
} else {
data = compressed
}
// 5. 反序列化
// 4. 反序列化(无压缩
row, err := decodeSSTableRow(data, r.schema)
if err != nil {
return nil, err
@@ -745,21 +698,9 @@ func (r *SSTableReader) GetPartial(key int64, fields []string) (*SSTableRow, err
return nil, fmt.Errorf("invalid data offset")
}
compressed := r.mmap[dataOffset : dataOffset+int64(dataSize)]
data := r.mmap[dataOffset : dataOffset+int64(dataSize)]
// 4. 压缩
var data []byte
var err error
if r.header.Compression == SSTableCompressionSnappy {
data, err = snappy.Decode(nil, compressed)
if err != nil {
return nil, err
}
} else {
data = compressed
}
// 5. 按需反序列化(只解析需要的字段)
// 4. 按需反序列化(只解析需要的字段,无压缩
row, err := decodeSSTableRowBinaryPartial(data, r.schema, fields)
if err != nil {
return nil, err
@@ -799,27 +740,13 @@ func (r *SSTableReader) Close() error {
return nil
}
// decodeSSTableRow 解码行数据
// decodeSSTableRow 解码行数据(只支持二进制格式)
func decodeSSTableRow(data []byte, schema *Schema) (*SSTableRow, error) {
// 尝试使用二进制格式解码
// 使用二进制格式解码
row, err := decodeSSTableRowBinary(data, schema)
if err == nil {
return row, nil
}
// 降级到 JSON (兼容旧数据)
var decoded map[string]any
err = json.Unmarshal(data, &decoded)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to decode row: %w", err)
}
row = &SSTableRow{
Seq: int64(decoded["_seq"].(float64)),
Time: int64(decoded["_time"].(float64)),
Data: decoded["data"].(map[string]any),
}
return row, nil
}