gotidb/pkg/model/datapoint.go

125 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package model
import (
"fmt"
"sync"
"time"
)
// DataPointID 数据点标识
type DataPointID struct {
DeviceID string // 设备ID
MetricCode string // 指标代码
Labels map[string]string // 自定义标签
}
// String 返回数据点标识的字符串表示
func (id DataPointID) String() string {
return fmt.Sprintf("%s:%s:%v", id.DeviceID, id.MetricCode, id.Labels)
}
// DataValue 数据值
type DataValue struct {
Timestamp time.Time // 时间戳
Value interface{} // 支持 int64 或 float64
}
// CircularBuffer 环形缓冲区
type CircularBuffer struct {
Values [30]DataValue // 固定大小为30的环形缓冲区
Head int // 当前写入位置
Lock sync.RWMutex // 细粒度锁
}
// NewCircularBuffer 创建一个新的环形缓冲区
func NewCircularBuffer() *CircularBuffer {
return &CircularBuffer{
Head: -1, // 初始化为-1表示缓冲区为空
}
}
// Write 写入一个新的数据值
func (cb *CircularBuffer) Write(value DataValue) {
cb.Lock.Lock()
defer cb.Lock.Unlock()
cb.Head = (cb.Head + 1) % len(cb.Values)
cb.Values[cb.Head] = value
}
// Read 读取所有数据值,按时间顺序返回
func (cb *CircularBuffer) Read() []DataValue {
cb.Lock.RLock()
defer cb.Lock.RUnlock()
if cb.Head == -1 {
return []DataValue{} // 缓冲区为空
}
result := make([]DataValue, 0, len(cb.Values))
// 从最旧的数据开始
oldest := (cb.Head + 1) % len(cb.Values)
// 如果缓冲区未满oldest可能指向未初始化的元素
// 我们需要检查并跳过这些元素
for i := 0; i < len(cb.Values); i++ {
idx := (oldest + i) % len(cb.Values)
// 跳过未初始化的元素
if cb.Values[idx].Timestamp.IsZero() {
continue
}
result = append(result, cb.Values[idx])
}
return result
}
// GetLatest 获取最新的数据值
func (cb *CircularBuffer) GetLatest() (DataValue, bool) {
cb.Lock.RLock()
defer cb.Lock.RUnlock()
if cb.Head == -1 {
return DataValue{}, false // 缓冲区为空
}
return cb.Values[cb.Head], true
}
// GetDuration 获取最新值的持续时间
func (cb *CircularBuffer) GetDuration() time.Duration {
cb.Lock.RLock()
defer cb.Lock.RUnlock()
if cb.Head == -1 {
return 0 // 缓冲区为空
}
latest := cb.Values[cb.Head]
// 如果只有一个值,无法计算持续时间
if len(cb.Values) == 1 {
return 0
}
// 查找前一个不同的值
for i := 1; i < len(cb.Values); i++ {
idx := (cb.Head - i + len(cb.Values)) % len(cb.Values)
prev := cb.Values[idx]
// 跳过未初始化的元素
if prev.Timestamp.IsZero() {
continue
}
// 如果值不同,计算持续时间
if prev.Value != latest.Value {
return latest.Timestamp.Sub(prev.Timestamp)
}
}
// 所有值都相同,无法计算持续时间
return 0
}