# RaftDB Storage Engine Documentation

RaftDB 内置了一个高性能、线程安全的嵌入式键值存储引擎。该引擎专为 Raft 状态机设计，支持高并发读写、倒排索引查询以及磁盘空间复用。

## 1. 核心特性

*   **高并发 (High Concurrency)**: 采用分片锁 (Striped Locking) 和原子操作，支持数万 QPS 的并行读写。
*   **数据安全 (Data Safety)**: Key 级锁确保同一 Key 的读写操作原子性，避免脏读和写冲突。
*   **磁盘复用 (Disk Reuse)**: 内置 Best-Fit 策略的 FreeList，自动回收并重用被删除或更新产生的空闲磁盘空间。
*   **倒排索引 (Inverted Index)**: 支持对 Key 和 Value 的自动分词索引，支持复杂的 SQL 风格查询。
*   **崩溃一致性 (Crash Consistency)**: 优化的写入顺序（Write New -> Update Index -> Mark Old Deleted），确保数据不丢失。

## 2. 架构设计

### 2.1 存储布局 (Storage Layout)

数据存储在单个 append-only 文件中 (`values.data`)，但支持空间复用。

**物理格式:**
```
[Header][Data]
```
*   **Header (9 bytes)**:
    *   `Flag` (1 byte): `0x01` (Valid) 或 `0x00` (Deleted)
    *   `Capacity` (4 bytes): 该槽位分配的总大小（包含 Data），用于复用。
    *   `Length` (4 bytes): 实际数据长度。
*   **Data**: 实际存储的 Key/Value 数据。

### 2.2 内存索引 (In-Memory Index)

为了减少锁竞争，核心数据结构均采用了分片设计 (Sharding)。

1.  **IndexShards (16 Shards)**:
    *   存储 `KeyID -> {FileOffset, CommitIndex}` 的映射。
    *   读写请求根据 KeyHash 分发到不同分片，互不干扰。

2.  **KeyMap (16 Shards)**:
    *   维护 `String Key <-> uint32 KeyID` 的双向映射。
    *   减少内存占用（索引中使用 uint32 替代 string），并加速比较。

3.  **InvertedIndex (16 Shards)**:
    *   维护 `Token -> []KeyID` 的倒排表。
    *   支持 `LIKE` 和全文匹配查询。

### 2.3 锁机制 (Locking Strategy)

*   **Key Locks (1024 Striped Locks)**:
    *   针对特定 Key 的操作（Get/Set）必须先获取该 Key 对应的 Hash 锁。
    *   保证了同一 Key 的强一致性。
*   **Shard Locks**:
    *   仅在访问 Index 映射表时短暂持有，IO 操作在 Index 锁之外进行。
*   **Atomic Offset**:
    *   文件追加写操作使用 `atomic.AddInt64`，无需全局锁。

## 3. 性能测试报告 (Benchmark Report)

测试环境: macOS, 10 并发 Workers, 本地磁盘 IO。

### 3.1 吞吐量 (Throughput)

| 操作类型 | 数量 | 耗时 | QPS (Ops/sec) | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| **Insert** | 100,000 | ~2.07s | **~48,300** | 批量写入，完全并行 |
| **Update** | 10,000 | ~0.09s | **~106,000** | 混合原地更新与追加写 |
| **Insert (Reuse)** | 5,000 | ~0.27s | **~18,200** | 复用旧空间，无需文件增长 |
| **Delete** | 10,000 | ~0.02s | **~403,800** | 标记删除，极快 |

### 3.2 磁盘空间复用验证

*   **初始写入 (100k items)**: DB Size **3.91 MB**
*   **更新后 (10k updates)**: DB Size **4.33 MB** (仅少量增长，部分原地更新)
*   **删除后 (10k deletes)**: DB Size **4.61 MB** (文件大小不变，产生空洞)
*   **复用写入 (5k reuse)**: DB Size **4.61 MB** (完全复用空洞，**文件大小零增长**)

**结论**: FreeList 机制有效工作，长时间运行后数据库文件大小将趋于稳定，不会无限膨胀。

### 3.3 数据完整性验证

*   **并发写安全**: 100% 通过。多线程更新同一 Key 也是安全的。
*   **数据一致性**: 100% 通过。全量扫描验证所有 Key 的值均为预期最新值。

## 4. 使用说明

### 4.1 初始化

```go
import "db"

// 初始化引擎，指定数据目录
e, err := db.NewEngine("./my_data")
if err != nil {
    panic(err)
}
defer e.Close()
```

### 4.2 基本读写

```go
// 写入数据 (Key, Value, CommitIndex)
err := e.Set("user.1001", "{\"name\":\"Alice\"}", 1)

// 读取数据
val, found := e.Get("user.1001")
if found {
    fmt.Println("Value:", val)
}
```

### 4.3 高级查询 (SQL-like)

支持对 Key、Value 和 CommitIndex 进行查询。

```go
// 查询所有 name 包含 "Alice" 且 CommitIndex > 0 的记录
results, err := e.Query(`value like "*Alice*" commit_index > 0`)

for _, row := range results {
    fmt.Printf("Key: %s, Val: %s\n", row.Key, row.Value)
}
```

## 5. 改进与优化历史

1.  **初始版本**: 全局互斥锁，性能瓶颈明显 (~15k QPS)。
2.  **V1 优化**: 引入 `KeyMap` 和 `Index` 分片，去除文件 IO 全局锁，使用 `pwrite`/`pread`。QPS 提升至 ~49k。
3.  **V2 安全加固**: 引入 `StripedLock` (Key级锁) 解决并发写冲突和脏读问题。在保证安全的前提下，Update/Delete 性能进一步提升至 100k+ QPS。

