diff --git a/promql/engine.go b/promql/engine.go index edc90d21a2..43a47c6cc7 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -1016,6 +1016,7 @@ type evaluator struct { lookbackDelta time.Duration samplesStats *stats.QuerySamples noStepSubqueryIntervalFn func(rangeMillis int64) int64 + reuseHistograms bool } // errorf causes a panic with the input formatted into an error. @@ -2152,10 +2153,19 @@ loop: histograms = getMatrixSelectorHPoints() } n := len(histograms) - if n < cap(histograms) { - histograms = histograms[:n+1] + if ev.reuseHistograms { + if n < cap(histograms) { + histograms = histograms[:n+1] + } else { + histograms = append(histograms, HPoint{H: &histogram.FloatHistogram{}}) + } } else { - histograms = append(histograms, HPoint{H: &histogram.FloatHistogram{}}) + if n < cap(histograms) { + histograms = histograms[:n+1] + histograms[n].H = nil + } else { + histograms = append(histograms, HPoint{}) + } } histograms[n].T, histograms[n].H = buf.AtFloatHistogram(histograms[n].H) if value.IsStaleNaN(histograms[n].H.Sum) { @@ -2195,10 +2205,19 @@ loop: histograms = getMatrixSelectorHPoints() } n := len(histograms) - if n < cap(histograms) { - histograms = histograms[:n+1] + if ev.reuseHistograms { + if n < cap(histograms) { + histograms = histograms[:n+1] + } else { + histograms = append(histograms, HPoint{H: &histogram.FloatHistogram{}}) + } } else { - histograms = append(histograms, HPoint{H: &histogram.FloatHistogram{}}) + if n < cap(histograms) { + histograms = histograms[:n+1] + histograms[n].H = nil + } else { + histograms = append(histograms, HPoint{}) + } } histograms[n].T, histograms[n].H = it.AtFloatHistogram(histograms[n].H) if value.IsStaleNaN(histograms[n].H.Sum) { diff --git a/storage/buffer.go b/storage/buffer.go index b3c789e97d..47c85a5ad0 100644 --- a/storage/buffer.go +++ b/storage/buffer.go @@ -240,6 +240,8 @@ func (s fhSample) Type() chunkenc.ValueType { type sampleRing struct { delta int64 + reuseHistograms bool + // Lookback buffers. We use iBuf for mixed samples, but one of the three // concrete ones for homogenous samples. (Only one of the four bufs is // allowed to be populated!) This avoids the overhead of the interface @@ -385,7 +387,7 @@ func (it *SampleRingIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (in it.fh.CopyTo(fh) return it.t, fh } - return it.t, it.fh.Copy() + return it.t, it.fh } func (it *SampleRingIterator) AtT() int64 { @@ -680,10 +682,14 @@ func addH(s hSample, buf []hSample, r *sampleRing) []hSample { } buf[r.i].t = s.t - if buf[r.i].h == nil { - buf[r.i].h = s.h.Copy() + if r.reuseHistograms { + if buf[r.i].h == nil { + buf[r.i].h = s.h.Copy() + } else { + s.h.CopyTo(buf[r.i].h) + } } else { - s.h.CopyTo(buf[r.i].h) + buf[r.i].h = s.h } r.l++ @@ -724,10 +730,14 @@ func addFH(s fhSample, buf []fhSample, r *sampleRing) []fhSample { } buf[r.i].t = s.t - if buf[r.i].fh == nil { - buf[r.i].fh = s.fh.Copy() + if r.reuseHistograms { + if buf[r.i].fh == nil { + buf[r.i].fh = s.fh.Copy() + } else { + s.fh.CopyTo(buf[r.i].fh) + } } else { - s.fh.CopyTo(buf[r.i].fh) + buf[r.i].fh = s.fh } r.l++