gotidb/pkg/engine/utils.go

237 lines
5.2 KiB
Go

package engine
import (
"context"
"hash/fnv"
"sync"
)
// WriteBuffer 实现写入缓冲区,用于合并小批量写入
type WriteBuffer struct {
points map[string][]DataPoint // 按序列ID分组的数据点
mu sync.Mutex
maxSize int // 缓冲区最大大小
flushCh chan struct{} // 触发刷新的通道
engine Engine // 底层存储引擎
}
// NewWriteBuffer 创建新的写入缓冲区
func NewWriteBuffer(engine Engine, maxSize int) *WriteBuffer {
wb := &WriteBuffer{
points: make(map[string][]DataPoint),
maxSize: maxSize,
flushCh: make(chan struct{}, 1),
engine: engine,
}
return wb
}
// Add 添加数据点到缓冲区
func (wb *WriteBuffer) Add(point DataPoint) error {
wb.mu.Lock()
seriesID := point.SeriesID()
wb.points[seriesID] = append(wb.points[seriesID], point)
size := len(wb.points)
wb.mu.Unlock()
if size >= wb.maxSize {
return wb.Flush()
}
return nil
}
// Flush 将缓冲区数据写入底层引擎
func (wb *WriteBuffer) Flush() error {
wb.mu.Lock()
points := make([]DataPoint, 0, len(wb.points)*10) // 预估大小
for _, seriesPoints := range wb.points {
points = append(points, seriesPoints...)
}
wb.points = make(map[string][]DataPoint)
wb.mu.Unlock()
if len(points) > 0 {
return wb.engine.WriteBatch(context.Background(), points)
}
return nil
}
// Close 关闭写入缓冲区
func (wb *WriteBuffer) Close() error {
return wb.Flush()
}
// ShardedLock 实现分片锁,用于减少锁竞争
type ShardedLock struct {
locks []sync.RWMutex
shardMask uint64
}
// NewShardedLock 创建新的分片锁
func NewShardedLock(shards int) *ShardedLock {
// 确保分片数是2的幂
shards = nextPowerOfTwo(shards)
return &ShardedLock{
locks: make([]sync.RWMutex, shards),
shardMask: uint64(shards - 1),
}
}
// getLockForKey 获取指定键的锁
func (sl *ShardedLock) getLockForKey(key string) *sync.RWMutex {
h := fnv.New64()
h.Write([]byte(key))
hashVal := h.Sum64()
return &sl.locks[hashVal&sl.shardMask]
}
// Lock 对指定键加写锁
func (sl *ShardedLock) Lock(key string) {
sl.getLockForKey(key).Lock()
}
// Unlock 对指定键解除写锁
func (sl *ShardedLock) Unlock(key string) {
sl.getLockForKey(key).Unlock()
}
// RLock 对指定键加读锁
func (sl *ShardedLock) RLock(key string) {
sl.getLockForKey(key).RLock()
}
// RUnlock 对指定键解除读锁
func (sl *ShardedLock) RUnlock(key string) {
sl.getLockForKey(key).RUnlock()
}
// CompactTimeSeriesBlock 实现时序数据的紧凑存储
type CompactTimeSeriesBlock struct {
baseTime int64 // 基准时间戳
deltaEncode []byte // 使用delta编码存储时间戳
values []byte // 压缩存储的值
}
// NewCompactBlock 创建新的紧凑存储块
func NewCompactBlock(baseTime int64, capacity int) *CompactTimeSeriesBlock {
return &CompactTimeSeriesBlock{
baseTime: baseTime,
deltaEncode: make([]byte, 0, capacity*8), // 预留足够空间
values: make([]byte, 0, capacity*8),
}
}
// nextPowerOfTwo 返回大于等于n的最小2的幂
func nextPowerOfTwo(n int) int {
n--
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n++
return n
}
// TimeRangeIndex 实现时间范围索引
type TimeRangeIndex struct {
windows []timeWindow
blockSize int64 // 时间窗口大小
}
type timeWindow struct {
startTime int64
endTime int64
offset int // 数据块中的偏移
}
// NewTimeRangeIndex 创建新的时间范围索引
func NewTimeRangeIndex(blockSize int64) *TimeRangeIndex {
return &TimeRangeIndex{
windows: make([]timeWindow, 0),
blockSize: blockSize,
}
}
// AddWindow 添加时间窗口
func (idx *TimeRangeIndex) AddWindow(start, end int64, offset int) {
idx.windows = append(idx.windows, timeWindow{
startTime: start,
endTime: end,
offset: offset,
})
}
// FindBlocks 查找指定时间范围内的数据块
func (idx *TimeRangeIndex) FindBlocks(start, end int64) []int {
var result []int
for i, window := range idx.windows {
if window.endTime >= start && window.startTime <= end {
result = append(result, i)
}
}
return result
}
// CircularBuffer 实现固定大小的环形缓冲区
type CircularBuffer struct {
values []DataPoint
head int
size int
capacity int
mu sync.RWMutex
}
// NewCircularBuffer 创建新的环形缓冲区
func NewCircularBuffer(capacity int) *CircularBuffer {
return &CircularBuffer{
values: make([]DataPoint, capacity),
capacity: capacity,
}
}
// Add 添加数据点到环形缓冲区
func (cb *CircularBuffer) Add(point DataPoint) {
cb.mu.Lock()
defer cb.mu.Unlock()
cb.values[cb.head] = point
cb.head = (cb.head + 1) % cb.capacity
if cb.size < cb.capacity {
cb.size++
}
}
// GetRecent 获取最近的n个数据点
func (cb *CircularBuffer) GetRecent(n int) []DataPoint {
cb.mu.RLock()
defer cb.mu.RUnlock()
if n > cb.size {
n = cb.size
}
result := make([]DataPoint, n)
for i := 0; i < n; i++ {
idx := (cb.head - i - 1 + cb.capacity) % cb.capacity
if idx < 0 {
idx += cb.capacity
}
result[i] = cb.values[idx]
}
return result
}
// Size 返回当前缓冲区中的数据点数量
func (cb *CircularBuffer) Size() int {
cb.mu.RLock()
defer cb.mu.RUnlock()
return cb.size
}
// Capacity 返回缓冲区容量
func (cb *CircularBuffer) Capacity() int {
return cb.capacity
}