重构:优化记录格式并修复核心功能

- 修改记录存储格式为 [4B len][8B offset][4B CRC][16B UUID][data]
- 修复 TopicProcessor 中 WaitGroup 使用错误导致 handler 不执行的问题
- 修复写入保护逻辑,避免 dirtyOffset=-1 时误判为写入中
- 添加统计信息定期持久化功能
- 改进 UTF-8 字符截断处理,防止 CJK 字符乱码
- 优化 Web UI:显示人类可读的文件大小,支持点击外部关闭弹窗
- 重构示例代码,添加 webui 和 webui_integration 示例

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-04 17:54:49 +08:00
parent 955a467248
commit 810664eb12
18 changed files with 1810 additions and 1170 deletions

View File

@@ -44,7 +44,7 @@ func TestBasicWriteAndRead(t *testing.T) {
}
// 读取数据(使用共享的 index
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
@@ -90,7 +90,7 @@ func TestCursorNextRange(t *testing.T) {
writer.Close()
// 测试范围读取
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatal(err)
}
@@ -176,7 +176,7 @@ func TestCursorWindow(t *testing.T) {
writer.Close()
// 测试窗口模式
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatal(err)
}
@@ -280,19 +280,19 @@ func TestCursorPersistence(t *testing.T) {
}
// 读取前两条记录
cursor1, err := NewCursor(tmpFile, index)
cursor1, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
cursor1.Next() // 读取第一条
cursor1.Next() // 读取第一条
cursor1.Commit() // 提交
cursor1.Next() // 读取第二条
cursor1.Next() // 读取第二条
cursor1.Commit() // 提交
cursor1.Close()
// 重新打开 cursor应该从第三条开始读取
cursor2, err := NewCursor(tmpFile, index)
cursor2, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("重新创建 cursor 失败: %v", err)
}
@@ -337,7 +337,7 @@ func TestTailer(t *testing.T) {
}
// 创建 cursor
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
@@ -407,7 +407,7 @@ func TestTailerStop(t *testing.T) {
return nil
}
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
@@ -650,7 +650,7 @@ func TestUUIDUniqueness(t *testing.T) {
}
// 读取并验证 UUID 唯一性
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
@@ -705,7 +705,7 @@ func TestUUIDValidation(t *testing.T) {
}
// 读取并验证 UUID
cursor, err := NewCursor(tmpFile, index)
cursor, err := NewCursor(tmpFile, index, nil)
if err != nil {
t.Fatalf("创建 cursor 失败: %v", err)
}
@@ -1208,7 +1208,7 @@ func TestRecordQuery(t *testing.T) {
}
offsets[i] = offset
}
writer.Close()
defer writer.Close()
// 模拟处理到第 5 条记录
// 窗口范围:[索引 5, 索引 6)
@@ -1223,7 +1223,7 @@ func TestRecordQuery(t *testing.T) {
defer index.Close()
// 创建查询器
query, err := NewRecordQuery(tmpFile, index)
query, err := NewRecordQuery(tmpFile, index, writer)
if err != nil {
t.Fatalf("failed to create query: %v", err)
}
@@ -1821,7 +1821,7 @@ func TestQueryOldestNewest(t *testing.T) {
t.Fatal(err)
}
defer processor.Close()
// 写入测试数据
for i := 0; i < 10; i++ {
data := fmt.Sprintf("message %d", i)
@@ -1829,7 +1829,7 @@ func TestQueryOldestNewest(t *testing.T) {
t.Fatal(err)
}
}
// 测试 QueryNewest - 查询索引 0, 1, 2向索引递增方向
// QueryNewest(-1, 3) 从 -1 向后查询,得到索引 0, 1, 2
oldest, err := processor.QueryNewest(-1, 3)