文档:更新和优化项目文档
- 更新 DESIGN.md: - 强调强制 Schema(21 种类型) - 更新核心代码行数为 ~5,400 行 - 优化 ROW1 格式说明(英文) - 完善性能指标和项目成果 - 精简 DOCS.md 和 README.md - 统一文档风格和术语
This commit is contained in:
169
DESIGN.md
169
DESIGN.md
@@ -8,9 +8,9 @@
|
||||
1. **极简架构** - 放弃复杂的 LSM Tree 多层设计,使用简单的两层结构
|
||||
2. **高并发写入** - WAL + MemTable 保证 200,000+ writes/s
|
||||
3. **快速查询** - mmap B+Tree 索引 + 二级索引,1-5 ms 查询性能
|
||||
4. **低内存占用** - mmap 零拷贝,应用层内存 < 200 MB
|
||||
5. **功能完善** - 支持 Schema、索引、条件查询等高级特性
|
||||
6. **生产可用** - 核心代码 5399 行,包含完善的错误处理和数据一致性保证
|
||||
4. **低内存占用** - mmap 零拷贝,应用层内存 < 150 MB
|
||||
5. **功能完善** - 强制 Schema(21 种类型)、索引、条件查询等高级特性
|
||||
6. **生产可用** - 核心代码 ~5,400 行,包含完善的错误处理和数据一致性保证
|
||||
|
||||
## 🏗️ 核心架构
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
│ SRDB Architecture │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Application Layer │
|
||||
│ ┌───────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ Database │->│ Table │ │
|
||||
│ │ (Multi-Table) │ │ (Schema + Storage) │ │
|
||||
│ └───────────────┘ └──────────────────────────┘ │
|
||||
│ ┌───────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ Database │->│ Table │ │
|
||||
│ │ (Multi-Table) │ │ (Schema + Storage) │ │
|
||||
│ └───────────────┘ └──────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Write Path (High Concurrency) │
|
||||
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
@@ -50,8 +50,10 @@
|
||||
│ │ │ - Leaf Nodes → Data Offset │ │ │
|
||||
│ │ ├─────────────────────────────────────────┤ │ │
|
||||
│ │ │ Data Blocks (Binary Format) │ │ │
|
||||
│ │ │ - 有 Schema: 二进制编码 │ │ │
|
||||
│ │ │ - 无 Schema: JSON 格式 │ │ │
|
||||
│ │ │ - ROW1 Format: Binary Encoding │ │ │
|
||||
│ │ │ [Magic:4B][Seq:8B][Time:8B] │ │ │
|
||||
│ │ │ [Fields:2B][OffsetTable][Data] │ │ │
|
||||
│ │ │ - Supports zero-copy & partial reads │ │ │
|
||||
│ │ └─────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ Secondary Indexes (Optional) │ │
|
||||
@@ -85,38 +87,6 @@
|
||||
|
||||
## 📁 文件组织结构
|
||||
|
||||
### 代码目录结构
|
||||
|
||||
```
|
||||
srdb/ ← 项目根目录
|
||||
├── go.mod ← 模块定义: code.tczkiot.com/wlw/srdb
|
||||
├── DESIGN.md ← 本设计文档
|
||||
├── CLAUDE.md ← Claude Code 指导文档
|
||||
│
|
||||
├── database.go ← 数据库管理 (多表)
|
||||
├── table.go ← 表管理 (带 Schema)
|
||||
├── errors.go ← 错误定义和处理
|
||||
│
|
||||
├── wal.go ← WAL 实现 (Write-Ahead Log)
|
||||
├── memtable.go ← MemTable 实现 (map + sorted slice)
|
||||
├── sstable.go ← SSTable 文件 (读写器、管理器、编码)
|
||||
├── btree.go ← B+Tree 索引 (构建器、读取器)
|
||||
├── version.go ← 版本控制 (MANIFEST 管理)
|
||||
├── compaction.go ← Compaction 压缩合并
|
||||
│
|
||||
├── schema.go ← Schema 定义与验证
|
||||
├── index.go ← 二级索引管理器
|
||||
├── index_btree.go ← 索引 B+Tree 实现
|
||||
├── query.go ← 查询构建器和表达式求值
|
||||
│
|
||||
├── examples/ ← 示例程序目录
|
||||
│ ├── webui/ ← Web UI 管理工具
|
||||
│ └── ... (其他示例)
|
||||
│
|
||||
└── webui/ ← Web UI 静态资源
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 运行时数据目录结构
|
||||
|
||||
```
|
||||
@@ -152,16 +122,16 @@ database_dir/ ← 数据库目录
|
||||
- 崩溃恢复支持
|
||||
|
||||
文件格式:
|
||||
┌─────────────────────────────────────┐
|
||||
│ WAL Entry │
|
||||
├─────────────────────────────────────┤
|
||||
│ CRC32 (4 bytes) │
|
||||
│ Length (4 bytes) │
|
||||
│ Type (1 byte): Put │
|
||||
│ Key (8 bytes): _seq │
|
||||
│ Value Length (4 bytes) │
|
||||
│ Value (N bytes): 序列化的行数据 │
|
||||
└─────────────────────────────────────┘
|
||||
┌───────────────────────────────────────┐
|
||||
│ WAL Entry │
|
||||
├───────────────────────────────────────┤
|
||||
│ CRC32 (4 bytes) │
|
||||
│ Length (4 bytes) │
|
||||
│ Type (1 byte): Put │
|
||||
│ Key (8 bytes): _seq │
|
||||
│ Value Length (4 bytes) │
|
||||
│ Value (N bytes): Serialized row data │
|
||||
└───────────────────────────────────────┘
|
||||
|
||||
性能:
|
||||
- 顺序写入: 极快
|
||||
@@ -334,49 +304,65 @@ func (s *MmapSST) readNode(offset int64) *BTreeNode {
|
||||
- 零拷贝: 无内存分配
|
||||
```
|
||||
|
||||
### 5. Schema 系统 (新增功能)
|
||||
### 5. Schema 系统
|
||||
|
||||
```
|
||||
设计:
|
||||
- 类型定义和验证
|
||||
- 必填字段检查
|
||||
- 唯一性约束
|
||||
- 默认值支持
|
||||
- 强制 Schema(所有表必须定义)
|
||||
- 21 种精确类型映射
|
||||
- Nullable 字段支持
|
||||
- 类型验证和转换
|
||||
- 索引标记(Indexed: true)
|
||||
|
||||
支持的类型(21 种):
|
||||
1. 有符号整数(5种): Int, Int8, Int16, Int32, Int64
|
||||
2. 无符号整数(5种): Uint, Uint8, Uint16, Uint32, Uint64
|
||||
3. 浮点数(2种): Float32, Float64
|
||||
4. 字符串(1种): String
|
||||
5. 布尔(1种): Bool
|
||||
6. 特殊类型(5种): Byte, Rune, Decimal, Time, Duration
|
||||
7. 复杂类型(2种): Object (JSON), Array (JSON)
|
||||
|
||||
实现:
|
||||
type Schema struct {
|
||||
Fields []FieldDefinition
|
||||
TableName string
|
||||
Fields []Field
|
||||
}
|
||||
|
||||
type FieldDefinition struct {
|
||||
type Field struct {
|
||||
Name string
|
||||
Type string // "string", "int", "float", "bool"
|
||||
Required bool // 是否必填
|
||||
Unique bool // 是否唯一
|
||||
Default interface{} // 默认值
|
||||
Type FieldType // 21 种类型之一
|
||||
Indexed bool // 是否创建索引
|
||||
Nullable bool // 是否允许 NULL
|
||||
Comment string // 字段注释
|
||||
}
|
||||
|
||||
func (s *Schema) Validate(data map[string]interface{}) error {
|
||||
for _, field := range s.Fields {
|
||||
// 检查必填字段
|
||||
// 检查类型匹配
|
||||
// 应用默认值
|
||||
}
|
||||
// 1. 检查必填字段
|
||||
// 2. 类型验证和转换
|
||||
// 3. Nullable 检查
|
||||
// 4. 返回验证后的数据
|
||||
}
|
||||
|
||||
使用示例:
|
||||
schema := &schema.Schema{
|
||||
Fields: []schema.FieldDefinition{
|
||||
{Name: "name", Type: "string", Required: true},
|
||||
{Name: "age", Type: "int", Required: false},
|
||||
{Name: "email", Type: "string", Unique: true},
|
||||
},
|
||||
}
|
||||
schema, _ := NewSchema("users", []Field{
|
||||
{Name: "name", Type: String, Indexed: false},
|
||||
{Name: "age", Type: Int32, Indexed: false},
|
||||
{Name: "email", Type: String, Indexed: true},
|
||||
{Name: "balance", Type: Decimal, Nullable: true},
|
||||
})
|
||||
|
||||
table, _ := db.CreateTable("users", schema)
|
||||
|
||||
类型转换规则:
|
||||
- 相同类型:直接接受
|
||||
- 兼容类型:自动转换(有符号 ↔ 无符号,需非负)
|
||||
- 类型提升:整数 → 浮点
|
||||
- JSON 兼容:float64 → 整数(需为整数值)
|
||||
- 负数 → 无符号:拒绝
|
||||
```
|
||||
|
||||
### 6. 二级索引 (新增功能)
|
||||
### 6. 二级索引
|
||||
|
||||
```
|
||||
设计:
|
||||
@@ -472,7 +458,7 @@ qb.Where("email", query.EndsWith, "@gmail.com")
|
||||
4. 返回匹配的行
|
||||
```
|
||||
|
||||
### 8. 数据库和表管理 (新增功能)
|
||||
### 8. 数据库和表管理
|
||||
|
||||
```
|
||||
设计:
|
||||
@@ -607,27 +593,6 @@ Flush 流程 (后台):
|
||||
|
||||
## 📊 性能指标
|
||||
|
||||
### 代码规模
|
||||
```
|
||||
核心代码: ~13,000 行 (不含测试和示例)
|
||||
├── table.go: 表管理和存储引擎
|
||||
├── wal.go: WAL 实现
|
||||
├── memtable.go: MemTable 实现
|
||||
├── sstable.go: SSTable 文件读写
|
||||
├── btree.go: B+Tree 索引
|
||||
├── version.go: 版本控制 (MANIFEST)
|
||||
├── compaction.go: Compaction 压缩
|
||||
├── index.go: 二级索引
|
||||
├── query.go: 查询构建器
|
||||
├── schema.go: Schema 验证
|
||||
├── errors.go: 错误处理
|
||||
└── database.go: 数据库管理
|
||||
|
||||
测试代码: ~2000+ 行
|
||||
示例代码: ~1000+ 行
|
||||
总计: 16,000+ 行
|
||||
```
|
||||
|
||||
### 写入性能
|
||||
```
|
||||
单线程: 50,000 writes/s
|
||||
@@ -884,8 +849,8 @@ SRDB 是一个功能完善的高性能 Append-Only 数据库引擎:
|
||||
- ✅ **高并发写入**: WAL + MemTable,200K+ w/s
|
||||
- ✅ **快速查询**: mmap B+Tree + 二级索引,1-5 ms
|
||||
- ✅ **低内存占用**: mmap 零拷贝,< 150 MB
|
||||
- ✅ **功能完善**: Schema、索引、条件查询、多表管理
|
||||
- ✅ **生产可用**: 5399 行核心代码,完善的错误处理和数据一致性
|
||||
- ✅ **功能完善**: 强制 Schema(21 种类型)、索引、条件查询、多表管理
|
||||
- ✅ **生产可用**: ~5,400 行核心代码,完善的错误处理和数据一致性
|
||||
- ✅ **简单可靠**: Append-Only,无更新/删除的复杂性
|
||||
|
||||
**技术亮点:**
|
||||
@@ -912,8 +877,8 @@ SRDB 是一个功能完善的高性能 Append-Only 数据库引擎:
|
||||
- ❌ 传统 OLTP 系统
|
||||
|
||||
**项目成果:**
|
||||
- 核心代码: ~13,000 行
|
||||
- 核心代码: ~5,400 行(精简高效)
|
||||
- 测试代码: ~2,000+ 行
|
||||
- 示例程序: 13+ 个完整示例
|
||||
- 文档: 完善的设计和使用文档
|
||||
- 性能: 达到设计目标
|
||||
- 文档: 完善的设计和使用文档(DESIGN.md、CLAUDE.md、DOCS.md、README.md)
|
||||
- 性能: 达到设计目标(200K+ w/s 写入,1-5 ms 查询)
|
||||
|
||||
66
DOCS.md
66
DOCS.md
@@ -12,7 +12,7 @@
|
||||
- [Scan 方法](#scan-方法)
|
||||
- [Object 和 Array 类型](#object-和-array-类型)
|
||||
- [索引](#索引)
|
||||
- [事务和并发](#事务和并发)
|
||||
- [并发控制](#并发控制)
|
||||
- [性能优化](#性能优化)
|
||||
- [错误处理](#错误处理)
|
||||
- [最佳实践](#最佳实践)
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
## 概述
|
||||
|
||||
SRDB (Simple Row Database) 是一个用 Go 编写的高性能嵌入式数据库,采用 LSM-Tree 架构,专为时序数据和高并发写入场景设计。
|
||||
SRDB (Simple Row Database) 是一个用 Go 编写的高性能嵌入式数据库,采用 Append-Only 架构(参考 LSM-Tree 设计理念),专为时序数据和高并发写入场景设计。
|
||||
|
||||
### 核心特性
|
||||
|
||||
@@ -996,9 +996,7 @@ rows, _ := table.Query().Contains("name", "Alice").Rows()
|
||||
|
||||
---
|
||||
|
||||
## 事务和并发
|
||||
|
||||
### 并发控制
|
||||
## 并发控制
|
||||
|
||||
SRDB 使用 **MVCC (多版本并发控制)** 实现无锁并发读写:
|
||||
|
||||
@@ -1036,18 +1034,6 @@ for i := 0; i < 100; i++ {
|
||||
wg.Wait()
|
||||
```
|
||||
|
||||
### 事务支持
|
||||
|
||||
⚠️ **当前版本不支持显式事务**,但保证:
|
||||
- 单条写入的原子性(通过 WAL)
|
||||
- 数据持久性(WAL fsync)
|
||||
- 崩溃恢复(WAL 重放)
|
||||
|
||||
未来版本计划支持:
|
||||
- [ ] 显式事务 API
|
||||
- [ ] 批量操作的原子性
|
||||
- [ ] ACID 保证
|
||||
|
||||
---
|
||||
|
||||
## 性能优化
|
||||
@@ -1310,34 +1296,52 @@ table.Insert(data) // 错误未处理
|
||||
|
||||
## 架构细节
|
||||
|
||||
### LSM-Tree 结构
|
||||
### Append-Only 架构
|
||||
|
||||
SRDB 采用 Append-Only 架构(参考 LSM-Tree 设计理念),分为两层:
|
||||
|
||||
1. **内存层** - WAL + MemTable (Active + Immutable)
|
||||
2. **磁盘层** - 带 B+Tree 索引的 SST 文件,分层存储(L0-L3)
|
||||
|
||||
```
|
||||
写入流程:
|
||||
数据 → WAL(持久化)→ MemTable → Immutable MemTable → Level 0 SST → Compaction → Level 1-6
|
||||
数据 → WAL(持久化)→ MemTable → Flush → SST L0 → Compaction → SST L1-L3
|
||||
|
||||
读取流程:
|
||||
查询 → MemTable(O(1))→ Immutable MemTables → SST Files(B+Tree)
|
||||
```
|
||||
|
||||
### 文件组织
|
||||
|
||||
```
|
||||
database_dir/
|
||||
├── database.meta # 数据库元数据
|
||||
├── MANIFEST # 版本控制
|
||||
└── table_name/
|
||||
├── schema.json # 表 Schema
|
||||
├── MANIFEST # 表级版本控制
|
||||
├── 000001.wal # WAL 文件
|
||||
├── 000001.sst # SST 文件
|
||||
├── 000002.sst
|
||||
└── idx_email.sst # 索引文件
|
||||
├── database.meta # 数据库元数据
|
||||
└── table_name/ # 每表一个目录
|
||||
├── schema.json # 表 Schema 定义
|
||||
├── MANIFEST-000001 # 表级版本控制
|
||||
├── CURRENT # 当前 MANIFEST 指针
|
||||
├── wal/ # WAL 子目录
|
||||
│ ├── 000001.wal # WAL 文件
|
||||
│ └── CURRENT # 当前 WAL 指针
|
||||
├── sst/ # SST 子目录(L0-L3 层级文件)
|
||||
│ └── 000001.sst # SST 文件(B+Tree + 数据)
|
||||
└── idx/ # 索引子目录
|
||||
└── idx_email.sst # 二级索引文件
|
||||
```
|
||||
|
||||
### 设计特点
|
||||
|
||||
- **Append-Only** - 无原地更新,简化并发控制
|
||||
- **MemTable** - `map[int64][]byte + sorted slice`,O(1) 读写
|
||||
- **SST 文件** - 4KB 节点的 B+Tree,mmap 零拷贝访问
|
||||
- **二进制编码** - ROW1 格式,无压缩,优先查询性能
|
||||
- **Compaction** - 后台异步合并,按层级管理文件大小
|
||||
|
||||
### Compaction 策略
|
||||
|
||||
- **Level 0**: 文件数量 ≥ 4 触发
|
||||
- **Level 1-6**: 总大小超过阈值触发
|
||||
- **Level 0-3**: 文件数量或总大小超过阈值时触发
|
||||
- **Score 计算**: `size / max_size` 或 `file_count / max_files`
|
||||
- **文件大小**: L0=2MB, L1=10MB, L2=50MB, L3=100MB, L4+=200MB
|
||||
- **文件大小**: L0=2MB, L1=10MB, L2=50MB, L3=100MB
|
||||
|
||||
### 性能指标
|
||||
|
||||
|
||||
655
README.md
655
README.md
@@ -1,48 +1,28 @@
|
||||
# SRDB - Simple Row Database
|
||||
|
||||
[](https://golang.org/)
|
||||
[](https://golang.org/)
|
||||
[](LICENSE)
|
||||
|
||||
一个基于 LSM-Tree 的高性能嵌入式数据库,专为时序数据和日志存储设计。
|
||||
一个用 Go 编写的高性能 Append-Only 时序数据库引擎,专为高并发写入和快速查询设计。
|
||||
|
||||
## 🎯 特性
|
||||
## 🎯 核心特性
|
||||
|
||||
### 核心功能
|
||||
- **LSM-Tree 架构** - 高效的写入性能和空间利用率
|
||||
- **MVCC 并发控制** - 支持多版本并发读写
|
||||
- **WAL 持久化** - 写前日志保证数据安全
|
||||
- **自动 Compaction** - 智能的多层级数据合并策略
|
||||
- **索引支持** - 快速的字段查询能力
|
||||
- **Schema 管理** - 灵活的表结构定义,支持 21 种类型
|
||||
- **复杂类型** - 原生支持 Object(map)和 Array(slice)
|
||||
|
||||
### 查询能力
|
||||
- **链式查询 API** - 流畅的查询构建器
|
||||
- **丰富的操作符** - 支持 `=`, `!=`, `<`, `>`, `IN`, `BETWEEN`, `CONTAINS` 等
|
||||
- **复合条件** - `AND`, `OR`, `NOT` 逻辑组合
|
||||
- **字段选择** - 按需加载指定字段,优化性能
|
||||
- **游标模式** - 惰性加载,支持大数据集遍历
|
||||
- **Append-Only 架构** - WAL + MemTable + mmap B+Tree SST,简化并发控制
|
||||
- **强类型 Schema** - 21 种数据类型,包括 Object(map)和 Array(slice)
|
||||
- **高性能写入** - 200K+ 写/秒(多线程),<1ms 延迟(p99)
|
||||
- **快速查询** - <0.1ms(内存),1-5ms(磁盘),支持二级索引
|
||||
- **智能 Scan** - 自动扫描到结构体,完整支持复杂类型
|
||||
|
||||
### 管理工具
|
||||
- **Web UI** - 现代化的数据库管理界面
|
||||
- **命令行工具** - 丰富的诊断和维护工具
|
||||
- **实时监控** - LSM-Tree 结构和 Compaction 状态可视化
|
||||
|
||||
---
|
||||
- **链式查询 API** - 18 种操作符,支持复合条件
|
||||
- **自动 Compaction** - 后台异步合并,优化存储空间
|
||||
- **零拷贝读取** - mmap 访问 SST 文件,内存占用 <150MB
|
||||
- **Web 管理界面** - 现代化的数据浏览和监控工具
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [快速开始](#快速开始)
|
||||
- [基本用法](#基本用法)
|
||||
- [查询 API](#查询-api)
|
||||
- [Scan 方法](#scan-方法---扫描到结构体)
|
||||
- [Object 和 Array 类型](#object-和-array-类型)
|
||||
- [Web UI](#web-ui)
|
||||
- [架构设计](#架构设计)
|
||||
- [性能特点](#性能特点)
|
||||
- [开发指南](#开发指南)
|
||||
- [核心概念](#核心概念)
|
||||
- [文档](#文档)
|
||||
- [开发](#开发)
|
||||
|
||||
---
|
||||
|
||||
@@ -54,6 +34,8 @@
|
||||
go get code.tczkiot.com/wlw/srdb
|
||||
```
|
||||
|
||||
**要求**:Go 1.21+
|
||||
|
||||
### 基本示例
|
||||
|
||||
```go
|
||||
@@ -73,12 +55,14 @@ func main() {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// 2. 定义 Schema
|
||||
// 2. 定义 Schema(强类型,21 种类型)
|
||||
schema, err := srdb.NewSchema("users", []srdb.Field{
|
||||
{Name: "id", Type: srdb.Int64, Indexed: true, Comment: "用户ID"},
|
||||
{Name: "name", Type: srdb.String, Indexed: false, Comment: "用户名"},
|
||||
{Name: "id", Type: srdb.Uint32, Indexed: true, Comment: "用户ID"},
|
||||
{Name: "name", Type: srdb.String, Comment: "用户名"},
|
||||
{Name: "email", Type: srdb.String, Indexed: true, Comment: "邮箱"},
|
||||
{Name: "age", Type: srdb.Int32, Indexed: false, Comment: "年龄"},
|
||||
{Name: "age", Type: srdb.Int32, Comment: "年龄"},
|
||||
{Name: "tags", Type: srdb.Array, Comment: "标签"}, // Array 类型
|
||||
{Name: "settings", Type: srdb.Object, Comment: "设置"}, // Object 类型
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -92,555 +76,131 @@ func main() {
|
||||
|
||||
// 4. 插入数据
|
||||
err = table.Insert(map[string]any{
|
||||
"id": 1,
|
||||
"id": uint32(1),
|
||||
"name": "Alice",
|
||||
"email": "alice@example.com",
|
||||
"age": 25,
|
||||
"age": int32(25),
|
||||
"tags": []any{"golang", "database"},
|
||||
"settings": map[string]any{
|
||||
"theme": "dark",
|
||||
"lang": "zh-CN",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 5. 查询数据
|
||||
rows, err := table.Query().
|
||||
// 5. 查询并扫描到结构体
|
||||
type User struct {
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Age int32 `json:"age"`
|
||||
Tags []string `json:"tags"`
|
||||
Settings map[string]string `json:"settings"`
|
||||
}
|
||||
|
||||
var users []User
|
||||
err = table.Query().
|
||||
Eq("name", "Alice").
|
||||
Gte("age", 18).
|
||||
Rows()
|
||||
Scan(&users)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// 6. 遍历结果
|
||||
for rows.Next() {
|
||||
row := rows.Row()
|
||||
fmt.Printf("User: %v\n", row.Data())
|
||||
}
|
||||
fmt.Printf("Found %d users\n", len(users))
|
||||
fmt.Printf("Tags: %v\n", users[0].Tags)
|
||||
fmt.Printf("Settings: %v\n", users[0].Settings)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 基本用法
|
||||
## 💡 核心概念
|
||||
|
||||
### 数据库操作
|
||||
### 架构
|
||||
|
||||
```go
|
||||
// 打开数据库
|
||||
db, err := srdb.Open("./data")
|
||||
SRDB 使用 **Append-Only 架构**,分为两层:
|
||||
|
||||
// 列出所有表
|
||||
tables := db.ListTables()
|
||||
|
||||
// 获取表
|
||||
table, err := db.GetTable("users")
|
||||
|
||||
// 删除表
|
||||
err = db.DropTable("users")
|
||||
|
||||
// 关闭数据库
|
||||
db.Close()
|
||||
```
|
||||
|
||||
### 表操作
|
||||
|
||||
```go
|
||||
// 插入数据
|
||||
err := table.Insert(map[string]any{
|
||||
"name": "Bob",
|
||||
"age": 30,
|
||||
})
|
||||
|
||||
// 获取单条数据(通过序列号)
|
||||
row, err := table.Get(seq)
|
||||
|
||||
// 删除数据
|
||||
err := table.Delete(seq)
|
||||
|
||||
// 更新数据
|
||||
err := table.Update(seq, map[string]any{
|
||||
"age": 31,
|
||||
})
|
||||
```
|
||||
|
||||
### Schema 定义
|
||||
|
||||
```go
|
||||
schema, err := srdb.NewSchema("logs", []srdb.Field{
|
||||
{
|
||||
Name: "level",
|
||||
Type: srdb.String,
|
||||
Indexed: true,
|
||||
Comment: "日志级别",
|
||||
},
|
||||
{
|
||||
Name: "message",
|
||||
Type: srdb.String,
|
||||
Indexed: false,
|
||||
Comment: "日志内容",
|
||||
},
|
||||
{
|
||||
Name: "timestamp",
|
||||
Type: srdb.Int64,
|
||||
Indexed: true,
|
||||
Comment: "时间戳",
|
||||
},
|
||||
{
|
||||
Name: "metadata",
|
||||
Type: srdb.Object,
|
||||
Indexed: false,
|
||||
Comment: "元数据(map)",
|
||||
},
|
||||
{
|
||||
Name: "tags",
|
||||
Type: srdb.Array,
|
||||
Indexed: false,
|
||||
Comment: "标签(slice)",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
**支持的字段类型**(21 种):
|
||||
|
||||
**有符号整数**:
|
||||
- `Int`, `Int8`, `Int16`, `Int32`, `Int64`
|
||||
|
||||
**无符号整数**:
|
||||
- `Uint`, `Uint8`, `Uint16`, `Uint32`, `Uint64`
|
||||
|
||||
**浮点数**:
|
||||
- `Float32`, `Float64`
|
||||
|
||||
**基础类型**:
|
||||
- `String` - 字符串
|
||||
- `Bool` - 布尔值
|
||||
- `Byte` - 字节(uint8)
|
||||
- `Rune` - 字符(int32)
|
||||
|
||||
**特殊类型**:
|
||||
- `Decimal` - 高精度十进制(需要 shopspring/decimal)
|
||||
- `Time` - 时间戳(time.Time)
|
||||
|
||||
**复杂类型**:
|
||||
- `Object` - 对象(map[string]xxx、struct{}、*struct{})
|
||||
- `Array` - 数组([]xxx 切片)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 查询 API
|
||||
|
||||
### 基本查询
|
||||
|
||||
```go
|
||||
// 等值查询
|
||||
rows, err := table.Query().Eq("name", "Alice").Rows()
|
||||
|
||||
// 范围查询
|
||||
rows, err := table.Query().
|
||||
Gte("age", 18).
|
||||
Lt("age", 60).
|
||||
Rows()
|
||||
|
||||
// IN 查询
|
||||
rows, err := table.Query().
|
||||
In("status", []any{"active", "pending"}).
|
||||
Rows()
|
||||
|
||||
// BETWEEN 查询
|
||||
rows, err := table.Query().
|
||||
Between("age", 18, 60).
|
||||
Rows()
|
||||
```
|
||||
|
||||
### 字符串查询
|
||||
|
||||
```go
|
||||
// 包含
|
||||
rows, err := table.Query().Contains("message", "error").Rows()
|
||||
|
||||
// 前缀匹配
|
||||
rows, err := table.Query().StartsWith("email", "admin@").Rows()
|
||||
|
||||
// 后缀匹配
|
||||
rows, err := table.Query().EndsWith("filename", ".log").Rows()
|
||||
```
|
||||
|
||||
### 复合条件
|
||||
|
||||
```go
|
||||
// AND 条件
|
||||
rows, err := table.Query().
|
||||
Eq("status", "active").
|
||||
Gte("age", 18).
|
||||
Rows()
|
||||
|
||||
// OR 条件
|
||||
rows, err := table.Query().
|
||||
Where(srdb.Or(
|
||||
srdb.Eq("role", "admin"),
|
||||
srdb.Eq("role", "moderator"),
|
||||
)).
|
||||
Rows()
|
||||
|
||||
// 复杂组合
|
||||
rows, err := table.Query().
|
||||
Where(srdb.And(
|
||||
srdb.Eq("status", "active"),
|
||||
srdb.Or(
|
||||
srdb.Gte("age", 18),
|
||||
srdb.Eq("verified", true),
|
||||
),
|
||||
)).
|
||||
Rows()
|
||||
```
|
||||
|
||||
### 字段选择
|
||||
|
||||
```go
|
||||
// 只查询指定字段(性能优化)
|
||||
rows, err := table.Query().
|
||||
Select("id", "name", "email").
|
||||
Eq("status", "active").
|
||||
Rows()
|
||||
```
|
||||
|
||||
### 结果处理
|
||||
|
||||
```go
|
||||
// 游标模式(惰性加载)
|
||||
rows, err := table.Query().Rows()
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
row := rows.Row()
|
||||
fmt.Println(row.Data())
|
||||
}
|
||||
|
||||
// 获取第一条
|
||||
row, err := table.Query().First()
|
||||
|
||||
// 获取最后一条
|
||||
row, err := table.Query().Last()
|
||||
|
||||
// 收集所有结果
|
||||
data := rows.Collect()
|
||||
|
||||
// 获取总数
|
||||
count := rows.Count()
|
||||
```
|
||||
|
||||
### Scan 方法 - 扫描到结构体
|
||||
|
||||
SRDB 提供智能的 Scan 方法,完整支持 Object 和 Array 类型:
|
||||
|
||||
```go
|
||||
// 定义结构体
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Settings map[string]string `json:"settings"` // Object 类型
|
||||
Tags []string `json:"tags"` // Array 类型
|
||||
}
|
||||
|
||||
// 扫描多行到切片
|
||||
var users []User
|
||||
table.Query().Scan(&users)
|
||||
|
||||
// 扫描单行到结构体(智能判断)
|
||||
var user User
|
||||
table.Query().Eq("name", "Alice").Scan(&user)
|
||||
|
||||
// Row.Scan - 扫描当前行
|
||||
row, _ := table.Query().First()
|
||||
var user User
|
||||
row.Scan(&user)
|
||||
|
||||
// 部分字段扫描(性能优化)
|
||||
type UserBrief struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
var briefs []UserBrief
|
||||
table.Query().Select("name", "email").Scan(&briefs)
|
||||
```
|
||||
|
||||
**Scan 特性**:
|
||||
- ✅ 智能判断目标类型(切片 vs 结构体)
|
||||
- ✅ 完整支持 Object(map)和 Array(slice)类型
|
||||
- ✅ 支持嵌套结构
|
||||
- ✅ 结合 Select() 优化性能
|
||||
|
||||
详细示例:[examples/scan_demo](examples/scan_demo/README.md)
|
||||
|
||||
### 完整的操作符列表
|
||||
|
||||
| 操作符 | 方法 | 说明 |
|
||||
|--------|------|------|
|
||||
| `=` | `Eq(field, value)` | 等于 |
|
||||
| `!=` | `NotEq(field, value)` | 不等于 |
|
||||
| `<` | `Lt(field, value)` | 小于 |
|
||||
| `>` | `Gt(field, value)` | 大于 |
|
||||
| `<=` | `Lte(field, value)` | 小于等于 |
|
||||
| `>=` | `Gte(field, value)` | 大于等于 |
|
||||
| `IN` | `In(field, values)` | 在列表中 |
|
||||
| `NOT IN` | `NotIn(field, values)` | 不在列表中 |
|
||||
| `BETWEEN` | `Between(field, min, max)` | 在范围内 |
|
||||
| `NOT BETWEEN` | `NotBetween(field, min, max)` | 不在范围内 |
|
||||
| `CONTAINS` | `Contains(field, pattern)` | 包含子串 |
|
||||
| `NOT CONTAINS` | `NotContains(field, pattern)` | 不包含子串 |
|
||||
| `STARTS WITH` | `StartsWith(field, prefix)` | 以...开头 |
|
||||
| `NOT STARTS WITH` | `NotStartsWith(field, prefix)` | 不以...开头 |
|
||||
| `ENDS WITH` | `EndsWith(field, suffix)` | 以...结尾 |
|
||||
| `NOT ENDS WITH` | `NotEndsWith(field, suffix)` | 不以...结尾 |
|
||||
| `IS NULL` | `IsNull(field)` | 为空 |
|
||||
| `IS NOT NULL` | `NotNull(field)` | 不为空 |
|
||||
|
||||
### Object 和 Array 类型
|
||||
|
||||
SRDB 支持复杂的数据类型,可以存储 JSON 风格的对象和数组:
|
||||
|
||||
```go
|
||||
// 定义包含复杂类型的表
|
||||
type Article struct {
|
||||
Title string `srdb:"field:title"`
|
||||
Content string `srdb:"field:content"`
|
||||
Tags []string `srdb:"field:tags"` // Array 类型
|
||||
Metadata map[string]any `srdb:"field:metadata"` // Object 类型
|
||||
Authors []string `srdb:"field:authors"` // Array 类型
|
||||
}
|
||||
|
||||
// 使用 StructToFields 自动生成 Schema
|
||||
fields, _ := srdb.StructToFields(Article{})
|
||||
schema, _ := srdb.NewSchema("articles", fields)
|
||||
table, _ := db.CreateTable("articles", schema)
|
||||
|
||||
// 插入数据
|
||||
table.Insert(map[string]any{
|
||||
"title": "SRDB 使用指南",
|
||||
"content": "...",
|
||||
"tags": []any{"database", "golang", "lsm-tree"},
|
||||
"metadata": map[string]any{
|
||||
"category": "tech",
|
||||
"views": 1250,
|
||||
"featured": true,
|
||||
},
|
||||
"authors": []any{"Alice", "Bob"},
|
||||
})
|
||||
|
||||
// 查询和扫描
|
||||
var article Article
|
||||
table.Query().Eq("title", "SRDB 使用指南").Scan(&article)
|
||||
|
||||
fmt.Println(article.Tags) // ["database", "golang", "lsm-tree"]
|
||||
fmt.Println(article.Metadata["category"]) // "tech"
|
||||
fmt.Println(article.Metadata["views"]) // 1250
|
||||
```
|
||||
|
||||
**支持的场景**:
|
||||
- ✅ `map[string]xxx` - 任意键值对
|
||||
- ✅ `struct{}` - 结构体(自动转换为 Object)
|
||||
- ✅ `*struct{}` - 结构体指针
|
||||
- ✅ `[]xxx` - 任意类型的切片
|
||||
- ✅ 嵌套的 Object 和 Array
|
||||
- ✅ 空对象 `{}` 和空数组 `[]`
|
||||
|
||||
**存储细节**:
|
||||
- Object 和 Array 使用 JSON 编码存储
|
||||
- 存储格式:`[length: uint32][JSON data]`
|
||||
- 零值:Object 为 `{}`,Array 为 `[]`
|
||||
- 支持任意嵌套深度
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Web UI
|
||||
|
||||
SRDB 提供了一个功能强大的 Web 管理界面。
|
||||
|
||||
### 启动 Web UI
|
||||
|
||||
```bash
|
||||
cd examples/webui
|
||||
|
||||
# 基本启动
|
||||
go run main.go serve
|
||||
|
||||
# 自定义配置
|
||||
go run main.go serve --db /path/to/database --port 3000
|
||||
|
||||
# 启用自动数据插入(演示模式)
|
||||
go run main.go serve --auto-insert
|
||||
```
|
||||
|
||||
访问:http://localhost:8080
|
||||
|
||||
### 功能特性
|
||||
|
||||
- **表管理** - 查看所有表及其 Schema
|
||||
- **数据浏览** - 分页浏览表数据,支持列选择
|
||||
- **Manifest 查看** - 可视化 LSM-Tree 结构
|
||||
- **实时监控** - Compaction 状态和统计
|
||||
- **主题切换** - 深色/浅色主题
|
||||
- **响应式设计** - 完美适配移动设备
|
||||
|
||||
详细文档:[examples/webui/README.md](examples/webui/README.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构设计
|
||||
|
||||
### LSM-Tree 结构
|
||||
1. **内存层** - WAL(Write-Ahead Log)+ MemTable(Active + Immutable)
|
||||
2. **磁盘层** - SST 文件(带 B+Tree 索引),分层存储(L0-L3)
|
||||
|
||||
```
|
||||
写入流程:
|
||||
数据
|
||||
↓
|
||||
WAL(持久化)
|
||||
↓
|
||||
MemTable(内存)
|
||||
↓
|
||||
Immutable MemTable
|
||||
↓
|
||||
Level 0 SST(磁盘)
|
||||
↓
|
||||
Level 1-6 SST(Compaction)
|
||||
数据 → WAL(持久化)→ MemTable → Flush → SST L0 → Compaction → SST L1-L3
|
||||
|
||||
读取流程:
|
||||
查询 → MemTable(O(1))→ Immutable MemTables → SST Files(B+Tree)
|
||||
```
|
||||
|
||||
### 组件架构
|
||||
### 数据文件
|
||||
|
||||
```
|
||||
Database
|
||||
├── Table (Schema + Storage)
|
||||
│ ├── MemTable Manager
|
||||
│ │ ├── Active MemTable
|
||||
│ │ └── Immutable MemTables
|
||||
│ ├── SSTable Manager
|
||||
│ │ └── SST Files (Level 0-6)
|
||||
│ ├── WAL Manager
|
||||
│ │ └── Write-Ahead Log
|
||||
│ ├── Version Manager
|
||||
│ │ └── MVCC Versions
|
||||
│ └── Compaction Manager
|
||||
│ ├── Picker(选择策略)
|
||||
│ └── Worker(执行合并)
|
||||
└── Query Builder
|
||||
└── Expression Engine
|
||||
database_dir/
|
||||
├── database.meta # 数据库元数据
|
||||
└── table_name/ # 每表一个目录
|
||||
├── schema.json # 表 Schema 定义
|
||||
├── MANIFEST-000001 # 表级版本控制
|
||||
├── CURRENT # 当前 MANIFEST 指针
|
||||
├── wal/ # WAL 子目录
|
||||
│ ├── 000001.wal # WAL 文件
|
||||
│ └── CURRENT # 当前 WAL 指针
|
||||
├── sst/ # SST 子目录(L0-L3 层级文件)
|
||||
│ └── 000001.sst # SST 文件(B+Tree + 数据)
|
||||
└── idx/ # 索引子目录
|
||||
└── idx_email.sst # 二级索引文件
|
||||
```
|
||||
|
||||
### 数据流
|
||||
### 设计特点
|
||||
|
||||
**写入路径**:
|
||||
```
|
||||
Insert → WAL → MemTable → Flush → SST Level 0 → Compaction → SST Level 1-6
|
||||
```
|
||||
|
||||
**读取路径**:
|
||||
```
|
||||
Query → MemTable → Immutable MemTables → SST Files (Level 0-6)
|
||||
```
|
||||
|
||||
**Compaction 触发**:
|
||||
- Level 0:文件数量 ≥ 4
|
||||
- Level 1-6:总大小超过阈值
|
||||
- Score 计算:`size / max_size` 或 `file_count / max_files`
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 性能特点
|
||||
|
||||
### 写入性能
|
||||
- **顺序写入** - WAL 和 MemTable 顺序写入,性能极高
|
||||
- **批量刷盘** - MemTable 达到阈值后批量刷盘
|
||||
- **异步 Compaction** - 后台异步执行,不阻塞写入
|
||||
|
||||
### 读取性能
|
||||
- **内存优先** - 优先从 MemTable 读取
|
||||
- **Bloom Filter** - 快速判断 key 是否存在(TODO)
|
||||
- **索引加速** - 索引字段快速定位
|
||||
- **按需加载** - 游标模式惰性加载,节省内存
|
||||
|
||||
### 空间优化
|
||||
- **Snappy 压缩** - SST 文件自动压缩
|
||||
- **增量合并** - Compaction 只合并必要的文件
|
||||
- **垃圾回收** - 自动清理过期版本
|
||||
|
||||
### 性能指标(参考)
|
||||
|
||||
| 操作 | 性能 |
|
||||
|------|------|
|
||||
| 顺序写入 | ~100K ops/s |
|
||||
| 随机写入 | ~50K ops/s |
|
||||
| 点查询 | ~10K ops/s |
|
||||
| 范围扫描 | ~1M rows/s |
|
||||
|
||||
*注:实际性能取决于硬件配置和数据特征*
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 开发指南
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
srdb/
|
||||
├── btree.go # B-Tree 索引实现
|
||||
├── compaction.go # Compaction 管理器
|
||||
├── database.go # 数据库管理
|
||||
├── errors.go # 错误定义和处理
|
||||
├── index.go # 索引管理
|
||||
├── index_btree.go # 索引 B+Tree
|
||||
├── memtable.go # 内存表
|
||||
├── query.go # 查询构建器
|
||||
├── schema.go # Schema 定义
|
||||
├── sstable.go # SSTable 文件
|
||||
├── table.go # 表管理(含存储引擎)
|
||||
├── version.go # 版本管理(MVCC)
|
||||
├── wal.go # Write-Ahead Log
|
||||
├── webui/ # Web UI
|
||||
│ ├── webui.go # HTTP 服务器
|
||||
│ └── static/ # 前端资源
|
||||
└── examples/ # 示例程序
|
||||
└── webui/ # Web UI 工具
|
||||
```
|
||||
|
||||
### 运行测试
|
||||
|
||||
```bash
|
||||
# 运行所有测试
|
||||
go test ./...
|
||||
|
||||
# 运行特定测试
|
||||
go test -v -run TestTable
|
||||
|
||||
# 性能测试
|
||||
go test -bench=. -benchmem
|
||||
```
|
||||
|
||||
### 构建示例
|
||||
|
||||
```bash
|
||||
# 构建 WebUI
|
||||
cd examples/webui
|
||||
go build -o webui main.go
|
||||
|
||||
# 运行
|
||||
./webui serve --db ./data
|
||||
```
|
||||
- **Append-Only** - 无原地更新,简化并发控制
|
||||
- **MemTable** - `map[int64][]byte + sorted slice`,O(1) 读写
|
||||
- **SST 文件** - 4KB 节点的 B+Tree,mmap 零拷贝访问
|
||||
- **二进制编码** - ROW1 格式,无压缩,优先查询性能
|
||||
- **Compaction** - 后台异步合并,按层级管理文件大小
|
||||
|
||||
---
|
||||
|
||||
## 📚 文档
|
||||
|
||||
### 核心文档
|
||||
- [设计文档](DESIGN.md) - 详细的架构设计和实现原理
|
||||
- [CLAUDE.md](CLAUDE.md) - 完整的开发者指南
|
||||
- [Nullable 指南](NULLABLE_GUIDE.md) - Nullable 字段使用说明
|
||||
- [API 文档](https://pkg.go.dev/code.tczkiot.com/wlw/srdb) - Go API 参考
|
||||
|
||||
### 示例和教程
|
||||
- [DOCS.md](DOCS.md) - 完整 API 文档和使用指南
|
||||
- [CLAUDE.md](CLAUDE.md) - 开发者指南和架构详解
|
||||
- [NULLABLE_GUIDE.md](NULLABLE_GUIDE.md) - Nullable 字段使用说明
|
||||
|
||||
### 示例教程
|
||||
|
||||
- [Scan 方法指南](examples/scan_demo/README.md) - 扫描到结构体,支持 Object 和 Array
|
||||
- [WebUI 工具](examples/webui/README.md) - Web 管理界面使用指南
|
||||
- [所有类型示例](examples/all_types/) - 21 种类型的完整示例
|
||||
- [Nullable 示例](examples/nullable/) - Nullable 字段的使用
|
||||
- [WebUI 工具](examples/webui/README.md) - Web 管理界面
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 开发
|
||||
|
||||
### 运行测试
|
||||
|
||||
```bash
|
||||
# 所有测试
|
||||
go test -v ./...
|
||||
|
||||
# 单个测试
|
||||
go test -v -run TestTable
|
||||
|
||||
# 性能测试
|
||||
go test -bench=. -benchmem
|
||||
```
|
||||
|
||||
### 构建 WebUI
|
||||
|
||||
```bash
|
||||
cd examples/webui
|
||||
go build -o webui main.go
|
||||
./webui serve --db ./data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -673,13 +233,12 @@ MIT License - 详见 [LICENSE](LICENSE) 文件
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
- [LevelDB](https://github.com/google/leveldb) - LSM-Tree 设计灵感
|
||||
- [LevelDB](https://github.com/google/leveldb) - 架构设计参考
|
||||
- [RocksDB](https://github.com/facebook/rocksdb) - Compaction 策略参考
|
||||
- [Lit](https://lit.dev/) - Web Components 框架
|
||||
|
||||
---
|
||||
|
||||
## 📧 联系方式
|
||||
## 📧 联系
|
||||
|
||||
- 项目主页:https://code.tczkiot.com/wlw/srdb
|
||||
- Issue 跟踪:https://code.tczkiot.com/wlw/srdb/issues
|
||||
|
||||
Reference in New Issue
Block a user