shrooms-server/shroom_internals/cache.go

96 lines
1.9 KiB
Go

package shroom_internals
import (
"sync"
)
const MAX_CACHE_POINTS = 1000
type DataCache struct {
sync.RWMutex
data []Datapoint
start int
}
func (dc *DataCache) LatestTime() int64 {
dc.Lock()
defer dc.Unlock()
if len(dc.data) == 0 {
return -1
}
if dc.start == 0 {
return int64(dc.data[len(dc.data)-1].Time)
} else {
return int64(dc.data[dc.start-1].Time)
}
}
func (dc *DataCache) Add(data *Datapoint) {
dc.Lock()
defer dc.Unlock()
if len(dc.data) < MAX_CACHE_POINTS {
dc.data = append(dc.data, *data)
} else {
dc.data[dc.start] = *data
dc.start += 1
if dc.start >= len(dc.data) {
dc.start = 0
}
}
}
func (dc *DataCache) binarySearch(s int, e int, target uint64) int {
for s < e {
mid := (s + e) / 2
if dc.data[mid].Time < target {
s = mid + 1
} else {
e = mid
}
}
return s
}
func (dc *DataCache) ReadSince(start_time uint64) []Datapoint {
dc.RLock()
defer dc.RUnlock()
if len(dc.data) == 0 {
return nil
}
if dc.data[dc.start].Time <= start_time {
// binary search for the point right at/after
// start_time
if len(dc.data) >= MAX_CACHE_POINTS {
// if the data is full length we've been wrapping
// around
if dc.data[0].Time <= start_time {
// it's between [0, start)
idx := dc.binarySearch(0, dc.start, start_time)
ret := []Datapoint{}
ret = append(ret, dc.data[idx:dc.start]...)
return ret
} else {
// it's between [start, len(dc.data))
// and we can always include [0, start) afterwards
idx := dc.binarySearch(dc.start, len(dc.data), start_time)
ret := []Datapoint{}
ret = append(ret, dc.data[idx:len(dc.data)]...)
ret = append(ret, dc.data[0:dc.start]...)
return ret
}
} else {
// it's between [0, len(dc.data))
idx := dc.binarySearch(0, len(dc.data), start_time)
ret := []Datapoint{}
ret = append(ret, dc.data[idx:len(dc.data)]...)
return ret
}
} else {
return nil
}
}