237 lines
5.2 KiB
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
|
|
}
|