Files
seqlog/example/index_example.go

150 lines
3.6 KiB
Go
Raw Normal View History

重构:统一使用索引(Index)替代位置(Position)进行状态判断 ## 主要变更 ### 架构改进 - 明确索引(Index)与偏移(Offset)的职责分离 - Index: 记录序号(逻辑概念),用于状态判断 - Offset: 文件字节位置(物理概念),仅用于 I/O 操作 ### API 变更 - 删除所有 Position 相关方法: - `LogCursor.StartPos()/EndPos()` - `LogTailer.GetStartPos()/GetEndPos()` - `TopicProcessor.GetProcessingPosition()/GetReadPosition()` - `Seqlog.GetProcessingPosition()/GetReadPosition()` - 新增索引方法: - `LogCursor.StartIndex()/EndIndex()` - `LogTailer.GetStartIndex()/GetEndIndex()` - `TopicProcessor.GetProcessingIndex()/GetReadIndex()` - `Seqlog.GetProcessingIndex()/GetReadIndex()` - `Seqlog.GetProcessor()` - 获取 processor 实例以访问 Index ### 查询接口变更 - `RecordQuery.QueryOldest(startIndex, count, startIdx, endIdx)` - 使用索引参数 - `RecordQuery.QueryNewest(endIndex, count, startIdx, endIdx)` - 使用索引参数 - `RecordQuery.QueryAt(position, direction, count, startIdx, endIdx)` - startIdx/endIdx 用于状态判断 ### 性能优化 - 状态判断改用整数比较,不再需要计算偏移量 - 减少不必要的索引到偏移的转换 - 只在实际文件 I/O 时才获取 offset ### 测试更新 - 更新所有测试用例使用新的 Index API - 更新示例代码(topic_processor_example.go, webapp/main.go) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 23:48:21 +08:00
package main
import (
"fmt"
"log"
"code.tczkiot.com/seqlog"
)
func main() {
logPath := "test_seqlog/app.log"
// ===== 示例 1使用带索引的写入器 =====
fmt.Println("=== 示例 1带索引的写入器 ===")
// 创建索引
index, err := seqlog.NewRecordIndex(logPath)
if err != nil {
log.Fatal(err)
}
defer index.Close()
// 创建写入器(使用共享索引)
writer, err := seqlog.NewLogWriter(logPath, index)
if err != nil {
log.Fatal(err)
}
// 写入日志时,索引会自动更新
for i := 1; i <= 10; i++ {
data := fmt.Sprintf("日志记录 #%d", i)
offset, err := writer.Append([]byte(data))
if err != nil {
log.Fatal(err)
}
fmt.Printf("写入: offset=%d, data=%s\n", offset, data)
}
writer.Close()
fmt.Printf("索引文件已创建: %s.idx\n\n", logPath)
// ===== 示例 2使用索引进行快速查询 =====
fmt.Println("=== 示例 2带索引的查询器 ===")
// 先获取索引(由 writer 创建)
index2, err := seqlog.NewRecordIndex(logPath)
if err != nil {
log.Fatal(err)
}
defer index2.Close()
// 创建查询器(使用外部索引)
query, err := seqlog.NewRecordQuery(logPath, index2)
if err != nil {
log.Fatal(err)
}
defer query.Close()
// 获取记录总数直接从索引读取O(1)
count, err := query.GetRecordCount()
if err != nil {
log.Fatal(err)
}
fmt.Printf("记录总数: %d\n", count)
// 可以直接使用共享的索引获取偏移量
offset, err := index.GetOffset(5)
if err != nil {
log.Fatal(err)
}
fmt.Printf("第 5 条记录的偏移: %d\n", offset)
// 向后查询(使用索引,高效)
backward, err := query.QueryAt(offset, -1, 3, 0, offset)
if err != nil {
log.Fatal(err)
}
fmt.Printf("向后查询 3 条记录:\n")
for i, rws := range backward {
fmt.Printf(" [%d] 状态=%s, 数据=%s\n", i, rws.Status, string(rws.Record.Data))
}
// 向前查询(顺序读取)
forward, err := query.QueryAt(offset, 1, 3, 0, offset)
if err != nil {
log.Fatal(err)
}
fmt.Printf("向前查询 3 条记录:\n")
for i, rws := range forward {
fmt.Printf(" [%d] 状态=%s, 数据=%s\n", i, rws.Status, string(rws.Record.Data))
}
fmt.Println()
// ===== 示例 3索引的自动恢复和重建 =====
fmt.Println("=== 示例 3索引恢复 ===")
// 如果索引文件存在,会自动加载
// 如果索引文件不存在或损坏,会自动重建
index3, err := seqlog.NewRecordIndex(logPath)
if err != nil {
log.Fatal(err)
}
fmt.Printf("索引已加载: %d 条记录\n", index3.Count())
fmt.Printf("最后一条记录偏移: %d\n", index3.LastOffset())
// 二分查找:根据偏移量查找索引位置
idx := index3.FindIndex(offset)
fmt.Printf("偏移量 %d 对应的索引位置: %d\n\n", offset, idx)
index3.Close()
// ===== 示例 4追加写入索引自动更新=====
fmt.Println("=== 示例 4追加写入 ===")
// 重新打开索引和写入器,追加新数据
index5, err := seqlog.NewRecordIndex(logPath)
if err != nil {
log.Fatal(err)
}
defer index5.Close()
writer, err = seqlog.NewLogWriter(logPath, index5)
if err != nil {
log.Fatal(err)
}
for i := 11; i <= 15; i++ {
data := fmt.Sprintf("追加记录 #%d", i)
offset, err := writer.Append([]byte(data))
if err != nil {
log.Fatal(err)
}
fmt.Printf("追加: offset=%d, data=%s\n", offset, data)
}
writer.Close()
// 验证索引已更新
index4, err := seqlog.NewRecordIndex(logPath)
if err != nil {
log.Fatal(err)
}
defer index4.Close()
fmt.Printf("索引已更新: 现有 %d 条记录\n", index4.Count())
fmt.Println("\n=== 所有示例完成 ===")
}