重构:简化查询接口
- RecordQuery.QueryOldest 和 QueryNewest 不再接收 startIdx/endIdx 参数 - 查询方法返回纯 Record 列表,状态判断移到调用方 - TopicProcessor 的查询方法负责添加状态信息 - 更新所有测试文件以适配新接口
This commit is contained in:
80
index.go
80
index.go
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -19,16 +21,27 @@ const (
|
||||
|
||||
// IndexEntrySize 每条索引条目大小(字节)
|
||||
IndexEntrySize = 8 // Offset(8)
|
||||
|
||||
// DefaultSyncInterval 默认同步间隔
|
||||
DefaultSyncInterval = 1 * time.Second
|
||||
|
||||
// DefaultSyncBatch 默认同步批次大小(累积多少条记录后同步)
|
||||
DefaultSyncBatch = 100
|
||||
)
|
||||
|
||||
// RecordIndex 记录索引管理器
|
||||
type RecordIndex struct {
|
||||
logPath string // 日志文件路径
|
||||
indexPath string // 索引文件路径
|
||||
offsets []int64 // 内存中的偏移索引
|
||||
magic uint32 // 魔数,用于识别索引文件
|
||||
version uint32 // 版本号
|
||||
indexFile *os.File // 索引文件句柄(用于追加写入)
|
||||
logPath string // 日志文件路径
|
||||
indexPath string // 索引文件路径
|
||||
offsets []int64 // 内存中的偏移索引
|
||||
magic uint32 // 魔数,用于识别索引文件
|
||||
version uint32 // 版本号
|
||||
indexFile *os.File // 索引文件句柄(用于追加写入)
|
||||
syncInterval time.Duration // 同步时间间隔
|
||||
syncBatch int // 同步批次大小
|
||||
lastSync time.Time // 上次同步时间
|
||||
dirtyCount int // 未同步的记录数
|
||||
mu sync.Mutex // 保护并发访问
|
||||
}
|
||||
|
||||
// NewRecordIndex 创建或加载记录索引
|
||||
@@ -37,11 +50,14 @@ func NewRecordIndex(logPath string) (*RecordIndex, error) {
|
||||
indexPath := logPath + ".idx"
|
||||
|
||||
ri := &RecordIndex{
|
||||
logPath: logPath,
|
||||
indexPath: indexPath,
|
||||
offsets: make([]int64, 0, 1024),
|
||||
magic: IndexMagic,
|
||||
version: IndexVersion,
|
||||
logPath: logPath,
|
||||
indexPath: indexPath,
|
||||
offsets: make([]int64, 0, 1024),
|
||||
magic: IndexMagic,
|
||||
version: IndexVersion,
|
||||
syncInterval: DefaultSyncInterval,
|
||||
syncBatch: DefaultSyncBatch,
|
||||
lastSync: time.Now(),
|
||||
}
|
||||
|
||||
// 启动时总是从日志文件重建索引
|
||||
@@ -136,6 +152,9 @@ func (ri *RecordIndex) save() error {
|
||||
|
||||
// Append 追加一条索引(当写入新记录时调用)
|
||||
func (ri *RecordIndex) Append(offset int64) error {
|
||||
ri.mu.Lock()
|
||||
defer ri.mu.Unlock()
|
||||
|
||||
// 追加到索引文件(先写文件,后更新内存)
|
||||
entryBuf := make([]byte, IndexEntrySize)
|
||||
binary.LittleEndian.PutUint64(entryBuf, uint64(offset))
|
||||
@@ -146,11 +165,15 @@ func (ri *RecordIndex) Append(offset int64) error {
|
||||
|
||||
// 更新内存索引
|
||||
ri.offsets = append(ri.offsets, offset)
|
||||
ri.dirtyCount++
|
||||
|
||||
// 同步索引文件
|
||||
// TODO 这里太频繁了
|
||||
if err := ri.indexFile.Sync(); err != nil {
|
||||
return fmt.Errorf("sync index file: %w", err)
|
||||
// 批量同步:达到批次大小或时间间隔后才同步
|
||||
if ri.dirtyCount >= ri.syncBatch || time.Since(ri.lastSync) >= ri.syncInterval {
|
||||
if err := ri.indexFile.Sync(); err != nil {
|
||||
return fmt.Errorf("sync index file: %w", err)
|
||||
}
|
||||
ri.lastSync = time.Now()
|
||||
ri.dirtyCount = 0
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -197,18 +220,35 @@ func (ri *RecordIndex) LastOffset() int64 {
|
||||
return ri.offsets[len(ri.offsets)-1]
|
||||
}
|
||||
|
||||
// Flush 强制同步未写入的数据到磁盘
|
||||
func (ri *RecordIndex) Flush() error {
|
||||
ri.mu.Lock()
|
||||
defer ri.mu.Unlock()
|
||||
|
||||
if ri.indexFile != nil && ri.dirtyCount > 0 {
|
||||
if err := ri.indexFile.Sync(); err != nil {
|
||||
return fmt.Errorf("flush index file: %w", err)
|
||||
}
|
||||
ri.lastSync = time.Now()
|
||||
ri.dirtyCount = 0
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 关闭索引文件
|
||||
func (ri *RecordIndex) Close() error {
|
||||
// 关闭前确保所有数据已同步
|
||||
if err := ri.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ri.indexFile != nil {
|
||||
return ri.indexFile.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sync 同步索引文件到磁盘
|
||||
// Sync 同步索引文件到磁盘(立即同步,不考虑批量策略)
|
||||
func (ri *RecordIndex) Sync() error {
|
||||
if ri.indexFile != nil {
|
||||
return ri.indexFile.Sync()
|
||||
}
|
||||
return nil
|
||||
return ri.Flush()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user