89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
package main
|
|
|
|
import "sync"
|
|
|
|
// sigRing is a fixed-capacity circular buffer storing (time, value) pairs.
|
|
// Writes come from the Hub.Run() goroutine; reads come from HTTP handler goroutines.
|
|
// The embedded RWMutex protects concurrent access.
|
|
type sigRing struct {
|
|
mu sync.RWMutex
|
|
t, v []float64
|
|
cap int
|
|
head, size int // next write position; current fill
|
|
}
|
|
|
|
func newSigRing(capacity int) *sigRing {
|
|
return &sigRing{
|
|
t: make([]float64, capacity),
|
|
v: make([]float64, capacity),
|
|
cap: capacity,
|
|
}
|
|
}
|
|
|
|
// write appends (tArr[i], vArr[i]) pairs, overwriting oldest entries when full.
|
|
func (rb *sigRing) write(tArr, vArr []float64) {
|
|
rb.mu.Lock()
|
|
defer rb.mu.Unlock()
|
|
for i := 0; i < len(tArr); i++ {
|
|
rb.t[rb.head] = tArr[i]
|
|
rb.v[rb.head] = vArr[i]
|
|
rb.head = (rb.head + 1) % rb.cap
|
|
if rb.size < rb.cap {
|
|
rb.size++
|
|
}
|
|
}
|
|
}
|
|
|
|
// slice returns copies of all (t, v) pairs whose timestamp falls in [t0, t1].
|
|
// The returned slices are safe to use after the call without holding any lock.
|
|
func (rb *sigRing) slice(t0, t1 float64) ([]float64, []float64) {
|
|
rb.mu.RLock()
|
|
defer rb.mu.RUnlock()
|
|
|
|
if rb.size == 0 {
|
|
return nil, nil
|
|
}
|
|
start := 0
|
|
if rb.size == rb.cap {
|
|
start = rb.head
|
|
}
|
|
physAt := func(k int) int { return (start + k) % rb.cap }
|
|
|
|
// Binary search for t0
|
|
lo, hi := 0, rb.size
|
|
for lo < hi {
|
|
m := (lo + hi) >> 1
|
|
if rb.t[physAt(m)] < t0 {
|
|
lo = m + 1
|
|
} else {
|
|
hi = m
|
|
}
|
|
}
|
|
kStart := lo
|
|
|
|
// Binary search for t1
|
|
lo, hi = kStart, rb.size
|
|
for lo < hi {
|
|
m := (lo + hi) >> 1
|
|
if rb.t[physAt(m)] <= t1 {
|
|
lo = m + 1
|
|
} else {
|
|
hi = m
|
|
}
|
|
}
|
|
kEnd := lo
|
|
|
|
n := kEnd - kStart
|
|
if n <= 0 {
|
|
return nil, nil
|
|
}
|
|
outT := make([]float64, n)
|
|
outV := make([]float64, n)
|
|
for i := 0; i < n; i++ {
|
|
p := physAt(kStart + i)
|
|
outT[i] = rb.t[p]
|
|
outV[i] = rb.v[p]
|
|
}
|
|
return outT, outV
|
|
}
|