重构:重命名核心组件并增强查询功能
主要更改: 1. 核心重命名 - Seqlog -> LogHub (更准确地反映其作为日志中枢的角色) - NewSeqlog() -> NewLogHub() - LogCursor -> ProcessCursor (更准确地反映其用于处理场景) - seqlog_manager.go -> loghub.go (文件名与结构体名对应) 2. TopicProcessor.Reset 增强 - 如果正在运行且没有待处理的日志,会自动停止后重置 - 如果有待处理的日志,返回详细错误(显示已处理/总记录数) - 简化了 LogHub.ResetTopic,移除显式 Stop 调用 3. 新增查询方法 - TopicProcessor.QueryFromFirst(count) - 从第一条记录向索引递增方向查询 - TopicProcessor.QueryFromLast(count) - 从最后一条记录向索引递减方向查询 - LogHub.QueryFromFirst(topic, count) - LogHub.QueryFromLast(topic, count) 4. 测试覆盖 - 添加 query_test.go - QueryFromProcessing 测试 - 添加 TestQueryFromFirstAndLast - TopicProcessor 查询测试 - 添加 TestLogHubQueryFromFirstAndLast - LogHub 查询测试 - 添加 TestTopicResetWithPendingRecords - Reset 增强功能测试 5. 示例代码 - 添加 example/get_record/ - 演示 QueryFromProcessing 用法 - 更新所有示例以使用 LogHub 和新 API 所有测试通过 ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ type TopicProcessor struct {
|
||||
writer *LogWriter // 写入器
|
||||
index *RecordIndex // 索引管理器
|
||||
query *RecordQuery // 查询器
|
||||
cursor *LogCursor // 游标
|
||||
cursor *ProcessCursor // 游标
|
||||
tailer *LogTailer // 持续处理器
|
||||
|
||||
// 配置和状态
|
||||
@@ -339,13 +339,14 @@ func (tp *TopicProcessor) Query() *RecordQuery {
|
||||
return tp.query
|
||||
}
|
||||
|
||||
// QueryOldest 从指定索引向索引递增方向查询记录
|
||||
// startIndex: 查询起始索引
|
||||
// QueryOldest 从参考索引向索引递减方向查询记录(查询更早的记录)
|
||||
// refIndex: 参考索引位置
|
||||
// count: 查询数量
|
||||
// 返回的记录包含状态信息(基于 tailer 的窗口索引),按索引递增方向排序
|
||||
func (tp *TopicProcessor) QueryOldest(startIndex, count int) ([]*RecordWithStatus, error) {
|
||||
// 查询记录
|
||||
records, err := tp.query.QueryOldest(startIndex, count)
|
||||
// 返回的记录包含索引和状态信息,按索引递增方向排序
|
||||
// 例如:QueryOldest(5, 3) 查询索引 2, 3, 4(不包含 5)
|
||||
func (tp *TopicProcessor) QueryOldest(refIndex, count int) ([]*RecordWithStatus, error) {
|
||||
// 查询记录(包含索引信息)
|
||||
records, err := tp.query.QueryOldest(refIndex, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -363,21 +364,23 @@ func (tp *TopicProcessor) QueryOldest(startIndex, count int) ([]*RecordWithStatu
|
||||
results := make([]*RecordWithStatus, len(records))
|
||||
for i, rec := range records {
|
||||
results[i] = &RecordWithStatus{
|
||||
Record: rec,
|
||||
Status: GetRecordStatus(startIndex+i, startIdx, endIdx),
|
||||
Record: rec.Record,
|
||||
Index: rec.Index,
|
||||
Status: GetRecordStatus(rec.Index, startIdx, endIdx),
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// QueryNewest 从指定索引向索引递减方向查询记录
|
||||
// endIndex: 查询的最大索引(向前查询更早的记录)
|
||||
// QueryNewest 从参考索引向索引递增方向查询记录(查询更新的记录)
|
||||
// refIndex: 参考索引位置
|
||||
// count: 查询数量
|
||||
// 返回的记录包含状态信息(基于 tailer 的窗口索引),按索引递增方向排序
|
||||
func (tp *TopicProcessor) QueryNewest(endIndex, count int) ([]*RecordWithStatus, error) {
|
||||
// 查询记录
|
||||
records, err := tp.query.QueryNewest(endIndex, count)
|
||||
// 返回的记录包含索引和状态信息,按索引递增方向排序
|
||||
// 例如:QueryNewest(5, 3) 查询索引 6, 7, 8(不包含 5)
|
||||
func (tp *TopicProcessor) QueryNewest(refIndex, count int) ([]*RecordWithStatus, error) {
|
||||
// 查询记录(包含索引信息)
|
||||
records, err := tp.query.QueryNewest(refIndex, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -391,12 +394,13 @@ func (tp *TopicProcessor) QueryNewest(endIndex, count int) ([]*RecordWithStatus,
|
||||
}
|
||||
tp.mu.RUnlock()
|
||||
|
||||
// 为每条记录添加状态(倒序:endIndex, endIndex-1, ...)
|
||||
// 为每条记录添加状态
|
||||
results := make([]*RecordWithStatus, len(records))
|
||||
for i, rec := range records {
|
||||
results[i] = &RecordWithStatus{
|
||||
Record: rec,
|
||||
Status: GetRecordStatus(endIndex-i, startIdx, endIdx),
|
||||
Record: rec.Record,
|
||||
Index: rec.Index,
|
||||
Status: GetRecordStatus(rec.Index, startIdx, endIdx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,16 +412,43 @@ func (tp *TopicProcessor) GetRecordCount() int {
|
||||
return tp.index.Count()
|
||||
}
|
||||
|
||||
// Cursor 创建一个新的游标实例(使用共享的 index)
|
||||
// 注意:每次调用都会创建新实例,调用者需要负责关闭
|
||||
// Tailer 内部有自己的游标,不会与此冲突
|
||||
func (tp *TopicProcessor) Cursor() (*LogCursor, error) {
|
||||
return NewCursor(tp.logPath, tp.index)
|
||||
// QueryFromProcessing 从当前处理窗口的开始位置向索引递增方向查询记录
|
||||
// count: 查询数量
|
||||
// 返回从处理窗口开始位置(startIndex)向后的记录,包含状态信息
|
||||
func (tp *TopicProcessor) QueryFromProcessing(count int) ([]*RecordWithStatus, error) {
|
||||
// 获取当前处理窗口的开始位置
|
||||
tp.mu.RLock()
|
||||
var startIdx int
|
||||
if tp.tailer != nil {
|
||||
startIdx = tp.tailer.GetStartIndex()
|
||||
}
|
||||
tp.mu.RUnlock()
|
||||
|
||||
// 从 startIdx 开始向索引递增方向查询
|
||||
// QueryNewest(refIndex, count) 查询从 refIndex+1 开始的记录
|
||||
// 所以要从 startIdx 开始,应该调用 QueryNewest(startIdx - 1, count)
|
||||
return tp.QueryNewest(startIdx-1, count)
|
||||
}
|
||||
|
||||
// Index 获取索引管理器
|
||||
func (tp *TopicProcessor) Index() *RecordIndex {
|
||||
return tp.index
|
||||
// QueryFromFirst 从第一条记录向索引递增方向查询
|
||||
// count: 查询数量
|
||||
// 返回从第一条记录(索引 0)开始的记录,包含状态信息
|
||||
// 例如:QueryFromFirst(3) 查询索引 0, 1, 2
|
||||
func (tp *TopicProcessor) QueryFromFirst(count int) ([]*RecordWithStatus, error) {
|
||||
// QueryNewest(-1, count) 会从索引 0 开始向后查询
|
||||
return tp.QueryNewest(-1, count)
|
||||
}
|
||||
|
||||
// QueryFromLast 从最后一条记录向索引递减方向查询
|
||||
// count: 查询数量
|
||||
// 返回从最后一条记录开始向前的记录,包含状态信息,按索引递增方向排序
|
||||
// 例如:如果总共有 10 条记录,QueryFromLast(3) 查询索引 7, 8, 9
|
||||
func (tp *TopicProcessor) QueryFromLast(count int) ([]*RecordWithStatus, error) {
|
||||
// 获取记录总数
|
||||
totalCount := tp.index.Count()
|
||||
|
||||
// QueryOldest(totalCount, count) 会从最后一条记录开始向前查询
|
||||
return tp.QueryOldest(totalCount, count)
|
||||
}
|
||||
|
||||
// GetProcessingIndex 获取当前处理索引(窗口开始索引)
|
||||
@@ -460,13 +491,42 @@ func (tp *TopicProcessor) Unsubscribe(eventType EventType) {
|
||||
}
|
||||
|
||||
// Reset 清空 topic 的所有数据,包括日志文件、位置文件和统计文件
|
||||
// 注意:必须在 Stop 之后调用
|
||||
// 如果 processor 正在运行且没有待处理的日志,会自动停止
|
||||
// 如果有待处理的日志,则返回错误,需要等待处理完成或手动停止
|
||||
func (tp *TopicProcessor) Reset() error {
|
||||
tp.mu.Lock()
|
||||
defer tp.mu.Unlock()
|
||||
|
||||
if tp.running {
|
||||
return fmt.Errorf("cannot reset while processor is running, please stop first")
|
||||
// 检查是否有待处理的日志
|
||||
processingIndex := 0
|
||||
if tp.tailer != nil {
|
||||
processingIndex = tp.tailer.GetStartIndex()
|
||||
}
|
||||
recordCount := tp.index.Count()
|
||||
|
||||
hasPendingRecords := processingIndex < recordCount
|
||||
|
||||
if hasPendingRecords {
|
||||
return fmt.Errorf("cannot reset while processor is running with pending records (%d/%d processed), please stop first or wait for processing to complete", processingIndex, recordCount)
|
||||
}
|
||||
|
||||
// 没有待处理的日志,自动停止
|
||||
tp.logger.Debug("auto-stopping processor before reset (no pending records)")
|
||||
tp.running = false
|
||||
tp.cancel()
|
||||
|
||||
// 释放锁以等待 tailer 停止
|
||||
tp.mu.Unlock()
|
||||
tp.wg.Wait()
|
||||
tp.mu.Lock()
|
||||
|
||||
// 发布停止事件
|
||||
tp.eventBus.Publish(&Event{
|
||||
Type: EventProcessorStop,
|
||||
Topic: tp.topic,
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
tp.logger.Debug("resetting processor")
|
||||
|
||||
Reference in New Issue
Block a user