# RaftDB 存储引擎文档

RaftDB 内置了一个专为 Raft 状态机设计的高性能、线程安全的嵌入式键值（KV）存储引擎。它采用了 **扁平有序数组 (Flat Sorted Array)** 作为核心内存索引，结合 **倒排索引 (Inverted Index)** 支持全文检索，并使用 **追加写日志 (Append-Only Log)** 保证数据的持久化。

## 1. 核心特性

*   **极致性能 (High Performance)**:
    *   **内存索引**: 使用基于有序数组的二分查找，读取性能极高，无指针开销。
    *   **追加写入**: 所有写操作（Put/Delete）均追加到文件末尾，充分利用磁盘顺序写带宽。
*   **高级查询能力 (Advanced Querying)**:
    *   **前缀扫描**: 得益于有序索引，支持高效的 `key like "prefix*"` 前缀范围扫描。
    *   **全文检索**: 内置倒排索引，支持 `value like "*token*"` 的模糊查询，无需全表扫描。
    *   **SQL-Like 语法**: 支持 `LIMIT`, `OFFSET` 以及复杂的组合过滤条件（例如 `key="k1" AND value like "v*"`）。
*   **数据安全与一致性 (Safety & Consistency)**:
    *   **CRC32 校验**: 每条记录都包含 CRC32 校验和，防止磁盘静默错误导致的数据损坏。
    *   **快照隔离**: 支持生成全量的一致性快照，用于 Raft 日志压缩。

## 2. 架构设计

### 2.1 核心索引：扁平有序数组 (Memory - Primary Index)

不同于传统的 B-Tree 或 Hash Map，本引擎采用了 **Flat Sorted Array** 结构：

*   **数据结构**:
    *   `keyBuf`: 一个巨大的单一 `[]byte` 缓冲，紧凑存储所有 Key 的字符串数据。
    *   `items`: 一个切片，存储轻量级的元数据结构（包含 Key 的偏移量、长度，以及 Value 在磁盘上的偏移量、CommitIndex）。
*   **优势**:
    *   **极度紧凑**: 极大地减少了内存碎片和每个 Key 的额外开销。
    *   **缓存友好**: 连续的内存布局使得 CPU 缓存命中率极高。
    *   **GC 友好**: 几乎不产生指针，大幅降低了 Go GC 的扫描压力。

### 2.2 辅助索引：全文倒排索引 (Memory - Secondary Index)

为了支持 `value like` 查询，引擎维护了一个倒排索引：
*   **映射关系**: Token (词) -> Key Set (包含该词的 Key 集合)。
*   **分词策略**: 简单的按非字母数字字符分割。
*   **查询优化**: 当查询包含 `value like` 时，查询优化器会自动通过倒排索引筛选 Key，避免昂贵的全表 Value 读取。

### 2.3 存储层 (Disk Storage)

*   **Append-Only Log**: 数据存储在 `values.data` 文件中。
    *   **写入 (Put)**: 追加 `[Header][Key][Value]`。
    *   **删除 (Delete)**: 追加一个墓碑（Tombstone）记录。
*   **元数据 (Metadata)**: `meta.state` 文件独立存储 `LastCommitIndex`，允许系统快速启动而无需重放整个日志。
*   **缓存 (Caching)**: 内置简单的 LRU 策略缓存，缓存最近读取的 Value，减少热点数据的磁盘 IO。

## 3. 一致性与持久化

### 3.1 持久性 (Durability)
*   **Sync 机制**: 引擎提供 `Sync()` 方法，调用系统调用 `fsync` 强制将 OS 页缓存刷入磁盘。
*   **Raft 集成**: Raft 在执行快照（Snapshot）前会强制调用 `Sync()`，确保在删除 Raft Log 之前，数据已经物理持久化。

### 3.2 数据完整性 (Integrity)
*   **校验和**: 每条记录写入时计算 CRC32，读取时验证。
*   **故障恢复**: 启动扫描时，如果发现文件尾部有损坏或写入不完整的记录（常见于断电崩溃），引擎会自动截断尾部脏数据，保证数据库状态的一致性。

### 3.3 快照与恢复 (Snapshot & Restore)
这是 Raft Log Compaction 的核心机制：
*   **Snapshot (快照)**: 锁定内存索引，将当前所有有效的 Key-Value 对序列化为一个紧凑的二进制流。这个流代表了某一时刻（CommitIndex）的完整状态机状态。
*   **Restore (恢复)**:
    1.  关闭当前数据库。
    2.  **Truncate (清空)** 数据文件。
    3.  从快照流中重建数据文件和内存索引。
    4.  强制刷盘。
    此过程通常用于落后太多的 Follower 节点快速追赶 Leader。

## 4. 查询语言 (Query Language)

引擎支持一种简化的 SQL 风格查询语法，用于调试和数据检查：

```sql
-- 精确查找 (Point Lookup)
key = "user:1001"

-- 前缀范围查询 (Prefix Search)
key like "user:*"

-- 全文模糊查询 (Full-Text Search, 需要开启 ValueIndex)
value like "error"

-- 组合过滤 (Complex Filtering)
key like "log:*" AND value like "*critical*"

-- 分页 (Pagination)
key like "user:*" LIMIT 10 OFFSET 20

-- 基于 Raft Index 过滤
CommitIndex > 1000
```

## 5. 配置说明

```go
// 初始化引擎时可以配置选项
// 例如：开启全文索引（会消耗更多内存）
engine, err := db.NewEngine(path, db.WithValueIndex(true))
```

## 6. 性能特征

*   **写入**: **O(1)** 磁盘追加 + **O(N)** 内存插入（数组移动）。
    *   *注*: 由于使用有序数组，插入涉及内存移动，因此该引擎更适合**读多写少**或**批量写入**的场景。
*   **读取**: **O(log N)** 内存二分查找 + **1次** 磁盘 Seek。
*   **扫描**: **O(log N)** 定位起点 + **O(M)** 顺序扫描 M 个元素。
*   **全文搜索**: **O(1)** 倒排索引查找 + **O(K)** 结果集过滤。

## 7. 局限性

*   **内存限制**: 虽然 Value 存储在磁盘，但所有 Key 和索引元数据必须能放入内存。
*   **空间回收**: 由于采用 Append-Only 模式，删除操作不会立即释放磁盘空间。空间回收依赖于 Raft 的 Snapshot/Restore 机制（Restore 会重写数据文件，从而清理垃圾数据）。
