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 } }