gotidb/pkg/engine/file/file.go

250 lines
5.9 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.

// findSeriesByTags 根据标签查找序列
func (e *FileEngine) findSeriesByTags(tags map[string]string) ([]string, error) {
e.tagIndex.mu.RLock()
defer e.tagIndex.mu.RUnlock()
if len(tags) == 0 {
// 如果没有指定标签,返回所有序列
allSeries := make(map[string]struct{})
for _, valueMap := range e.tagIndex.index {
for _, seriesIDs := range valueMap {
for _, seriesID := range seriesIDs {
allSeries[seriesID] = struct{}{}
}
}
}
// 转换为切片
result := make([]string, 0, len(allSeries))
for seriesID := range allSeries {
result = append(result, seriesID)
}
return result, nil
}
// 对于每个标签,找到匹配的序列
var matchedSeries map[string]struct{}
first := true
for key, value := range tags {
// 获取标签值映射
valueMap, ok := e.tagIndex.index[key]
if !ok {
// 如果标签键不存在,返回空结果
return []string{}, nil
}
// 获取匹配标签值的序列
seriesIDs, ok := valueMap[value]
if !ok {
// 如果标签值不存在,返回空结果
return []string{}, nil
}
// 初始化或取交集
if first {
matchedSeries = make(map[string]struct{})
for _, id := range seriesIDs {
matchedSeries[id] = struct{}{}
}
first = false
} else {
// 取交集
newMatched := make(map[string]struct{})
for _, id := range seriesIDs {
if _, ok := matchedSeries[id]; ok {
newMatched[id] = struct{}{}
}
}
matchedSeries = newMatched
}
// 如果没有匹配的序列,提前返回
if len(matchedSeries) == 0 {
return []string{}, nil
}
}
// 转换为切片
result := make([]string, 0, len(matchedSeries))
for seriesID := range matchedSeries {
result = append(result, seriesID)
}
return result, nil
}
// readPointsFromSegment 从段文件中读取数据点
func (e *FileEngine) readPointsFromSegment(segment *Segment, offset int64, count int) ([]engine.DataPoint, error) {
segment.mu.RLock()
defer segment.mu.RUnlock()
// 如果文件为空,直接返回
if segment.size == 0 {
return []engine.DataPoint{}, nil
}
// 移动文件指针到指定位置
_, err := segment.file.Seek(offset, 0)
if err != nil {
return nil, fmt.Errorf("failed to seek segment file: %v", err)
}
// 读取指定数量的数据点
points := make([]engine.DataPoint, 0, count)
for i := 0; i < count; i++ {
// 读取时间戳8字节
var timestamp int64
err := binary.Read(segment.file, binary.LittleEndian, &timestamp)
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("failed to read timestamp: %v", err)
}
// 读取值8字节
var value float64
err = binary.Read(segment.file, binary.LittleEndian, &value)
if err != nil {
return nil, fmt.Errorf("failed to read value: %v", err)
}
// 创建数据点
point := engine.DataPoint{
Timestamp: timestamp,
Value: value,
}
points = append(points, point)
}
return points, nil
}
// findTimeWindows 查找指定时间范围内的时间窗口
func (e *FileEngine) findTimeWindows(seriesID string, startTime, endTime int64) ([]timeWindow, error) {
e.timeIndex.mu.RLock()
defer e.timeIndex.mu.RUnlock()
// 获取序列的所有时间窗口
windows, ok := e.timeIndex.windows[seriesID]
if !ok {
return nil, nil // 序列不存在
}
// 找到所有与时间范围重叠的窗口
var matchedWindows []timeWindow
for _, window := range windows {
// 检查窗口是否与查询时间范围重叠
if window.endTime >= startTime && window.startTime <= endTime {
matchedWindows = append(matchedWindows, window)
}
}
// 按时间排序
sort.Slice(matchedWindows, func(i, j int) bool {
return matchedWindows[i].startTime < matchedWindows[j].startTime
})
return matchedWindows, nil
}
// getLabelsForSeries 获取序列的标签
func (e *FileEngine) getLabelsForSeries(seriesID string) map[string]string {
e.tagIndex.mu.RLock()
defer e.tagIndex.mu.RUnlock()
labels := make(map[string]string)
// 遍历所有标签
for key, valueMap := range e.tagIndex.index {
// 遍历每个标签值
for value, seriesIDs := range valueMap {
// 检查序列ID是否在列表中
for _, id := range seriesIDs {
if id == seriesID {
labels[key] = value
break
}
}
}
}
return labels
}
// newTimeIndex 创建新的时间索引
func newTimeIndex() *TimeIndex {
return &TimeIndex{
windows: make(map[string][]timeWindow),
}
}
// newTagIndex 创建新的标签索引
func newTagIndex() *TagIndex {
return &TagIndex{
index: make(map[string]map[string][]string),
}
}
// WritePoint 向段文件写入数据点
func (s *Segment) WritePoint(point engine.DataPoint) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
// 获取当前偏移量
offset, err := s.file.Seek(0, io.SeekCurrent)
if err != nil {
return 0, fmt.Errorf("failed to get file offset: %v", err)
}
// 写入时间戳8字节
err = binary.Write(s.file, binary.LittleEndian, point.Timestamp)
if err != nil {
return 0, fmt.Errorf("failed to write timestamp: %v", err)
}
// 写入值8字节
err = binary.Write(s.file, binary.LittleEndian, point.Value)
if err != nil {
return 0, fmt.Errorf("failed to write value: %v", err)
}
// 更新段文件信息
s.size += 16 // 每个数据点16字节
s.pointCount++
if s.startTime == 0 || point.Timestamp < s.startTime {
s.startTime = point.Timestamp
}
if point.Timestamp > s.endTime {
s.endTime = point.Timestamp
}
return offset, nil
}
// Close 关闭段文件
func (s *Segment) Close() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.file != nil {
if err := s.file.Close(); err != nil {
return fmt.Errorf("failed to close segment file: %v", err)
}
s.file = nil
}
return nil
}
// Sync 将段文件同步到磁盘
func (s *Segment) Sync() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.file != nil {
if err := s.file.Sync(); err != nil {
return fmt.Errorf("failed to sync segment file: %v", err)
}
}
return nil
}