mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-07-22 06:50:38 +02:00
feat(metricstore): add recomputeStats full-scan helper
This commit is contained in:
@@ -20,6 +20,33 @@ type Stats struct {
|
||||
Max schema.Float
|
||||
}
|
||||
|
||||
// recomputeStats rebuilds the buffer's running statistics from a single full
|
||||
// scan of its data and marks them valid. Used after an overwrite invalidated
|
||||
// the incremental aggregate, and at checkpoint load time.
|
||||
func (b *buffer) recomputeStats() {
|
||||
sum, samples := 0.0, 0
|
||||
min, max := math.MaxFloat32, -math.MaxFloat32
|
||||
for _, v := range b.data {
|
||||
xf := float64(v)
|
||||
if math.IsNaN(xf) {
|
||||
continue
|
||||
}
|
||||
samples++
|
||||
sum += xf
|
||||
if xf < min {
|
||||
min = xf
|
||||
}
|
||||
if xf > max {
|
||||
max = xf
|
||||
}
|
||||
}
|
||||
b.statSum = sum
|
||||
b.statSamples = samples
|
||||
b.statMin = min
|
||||
b.statMax = max
|
||||
b.statsValid = true
|
||||
}
|
||||
|
||||
func (b *buffer) stats(from, to int64) (Stats, int64, int64, error) {
|
||||
if from < b.start {
|
||||
if b.prev != nil {
|
||||
|
||||
@@ -84,3 +84,39 @@ func TestWriteOverwriteInvalidatesStats(t *testing.T) {
|
||||
t.Error("statsValid = true, want false after overwrite")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecomputeStatsRebuildsAfterOverwrite(t *testing.T) {
|
||||
b := newBuffer(100, 10)
|
||||
b.write(100, schema.Float(1.0))
|
||||
b.write(110, schema.Float(2.0))
|
||||
b.write(100, schema.Float(99.0)) // overwrite -> statsValid false, min stale
|
||||
|
||||
b.recomputeStats()
|
||||
|
||||
if !b.statsValid {
|
||||
t.Error("statsValid = false, want true after recompute")
|
||||
}
|
||||
if b.statSamples != 2 {
|
||||
t.Errorf("statSamples = %d, want 2", b.statSamples)
|
||||
}
|
||||
if b.statSum != 101.0 {
|
||||
t.Errorf("statSum = %v, want 101.0", b.statSum)
|
||||
}
|
||||
if b.statMin != 2.0 {
|
||||
t.Errorf("statMin = %v, want 2.0 (1.0 was overwritten)", b.statMin)
|
||||
}
|
||||
if b.statMax != 99.0 {
|
||||
t.Errorf("statMax = %v, want 99.0", b.statMax)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecomputeStatsEmptyBuffer(t *testing.T) {
|
||||
b := newBuffer(100, 10)
|
||||
b.recomputeStats()
|
||||
if b.statSamples != 0 || b.statSum != 0 {
|
||||
t.Errorf("empty buffer stats = samples %d sum %v, want 0/0", b.statSamples, b.statSum)
|
||||
}
|
||||
if b.statMin != math.MaxFloat32 || b.statMax != -math.MaxFloat32 {
|
||||
t.Errorf("empty buffer min/max = %v/%v, want sentinels", b.statMin, b.statMax)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user