主要改动: - 重构目录结构:合并子目录到根目录,简化项目结构 - 添加完整的查询 API:支持复杂条件查询、字段选择、游标模式 - 实现 LSM-Tree Compaction:7层结构、Score-based策略、后台异步合并 - 添加 Web UI:基于 Lit 的现代化管理界面,支持数据浏览和 Manifest 查看 - 完善文档:添加 README.md 和 examples/webui/README.md 新增功能: - Query Builder:链式查询 API,支持 Eq/Lt/Gt/In/Between/Contains 等操作符 - Web UI 组件:srdb-app、srdb-table-list、srdb-data-view、srdb-manifest-view 等 - 列选择持久化:自动保存到 localStorage - 刷新按钮:一键刷新当前视图 - 主题切换:深色/浅色主题支持 代码优化: - 使用 Go 1.24 新特性:range 7、min()、maps.Copy()、slices.Sort() - 统一组件命名:所有 Web Components 使用 srdb-* 前缀 - CSS 优化:提取共享样式,减少重复代码 - 清理遗留代码:删除未使用的方法和样式
130 lines
2.1 KiB
Go
130 lines
2.1 KiB
Go
package srdb
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestWAL(t *testing.T) {
|
|
// 1. 创建 WAL
|
|
wal, err := OpenWAL("test.wal")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove("test.wal")
|
|
|
|
// 2. 写入数据
|
|
for i := int64(1); i <= 100; i++ {
|
|
entry := &WALEntry{
|
|
Type: WALEntryTypePut,
|
|
Seq: i,
|
|
Data: []byte("value_" + string(rune(i))),
|
|
}
|
|
err := wal.Append(entry)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// 3. Sync
|
|
err = wal.Sync()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
wal.Close()
|
|
|
|
t.Log("Written 100 entries")
|
|
|
|
// 4. 读取数据
|
|
reader, err := NewWALReader("test.wal")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer reader.Close()
|
|
|
|
entries, err := reader.Read()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(entries) != 100 {
|
|
t.Errorf("Expected 100 entries, got %d", len(entries))
|
|
}
|
|
|
|
// 验证数据
|
|
for i, entry := range entries {
|
|
expectedSeq := int64(i + 1)
|
|
if entry.Seq != expectedSeq {
|
|
t.Errorf("Entry %d: expected Seq=%d, got %d", i, expectedSeq, entry.Seq)
|
|
}
|
|
if entry.Type != WALEntryTypePut {
|
|
t.Errorf("Entry %d: expected Type=%d, got %d", i, WALEntryTypePut, entry.Type)
|
|
}
|
|
}
|
|
|
|
t.Log("All tests passed!")
|
|
}
|
|
|
|
func TestWALTruncate(t *testing.T) {
|
|
// 创建 WAL
|
|
wal, err := OpenWAL("test_truncate.wal")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove("test_truncate.wal")
|
|
|
|
// 写入数据
|
|
for i := int64(1); i <= 10; i++ {
|
|
entry := &WALEntry{
|
|
Type: WALEntryTypePut,
|
|
Seq: i,
|
|
Data: []byte("value"),
|
|
}
|
|
wal.Append(entry)
|
|
}
|
|
|
|
// Truncate
|
|
err = wal.Truncate()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
wal.Close()
|
|
|
|
// 验证文件为空
|
|
reader, err := NewWALReader("test_truncate.wal")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer reader.Close()
|
|
|
|
entries, err := reader.Read()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(entries) != 0 {
|
|
t.Errorf("Expected 0 entries after truncate, got %d", len(entries))
|
|
}
|
|
|
|
t.Log("Truncate test passed!")
|
|
}
|
|
|
|
func BenchmarkWALAppend(b *testing.B) {
|
|
wal, _ := OpenWAL("bench.wal")
|
|
defer os.Remove("bench.wal")
|
|
defer wal.Close()
|
|
|
|
entry := &WALEntry{
|
|
Type: WALEntryTypePut,
|
|
Seq: 1,
|
|
Data: make([]byte, 100),
|
|
}
|
|
|
|
for i := 0; b.Loop(); i++ {
|
|
entry.Seq = int64(i)
|
|
wal.Append(entry)
|
|
}
|
|
}
|