Repository: prometheus/prometheus
File: promql/histogram_stats_iterator.go (Go)

Code before:
func (hsi *HistogramStatsIterator) Seek(t int64) chunkenc.ValueType {
	// If the Seek is going to move the iterator, we have to forget the
	// lastFH.
	if t > hsi.AtT() {
		hsi.lastFH = nil
	}
	vt := hsi.Iterator.Seek(t)
	if vt == chunkenc.ValHistogram {
		return chunkenc.ValFloatHistogram
	}
	return vt
}

// AtHistogram must never be called.
func (*HistogramStatsIterator) AtHistogram(*histogram.Histogram) (int64, *histogram.Histogram) {
	panic("HistogramStatsIterator.AtHistogram must never be called")
}

// AtFloatHistogram returns the next timestamp/float histogram pair. The method
// performs a counter reset detection on the fly. It will return an explicit
// hint (not UnknownCounterReset) if the previous sample has been accessed with
// the same iterator.
func (hsi *HistogramStatsIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
	var t int64
	t, hsi.currentFH = hsi.Iterator.AtFloatHistogram(hsi.currentFH)
	if value.IsStaleNaN(hsi.currentFH.Sum) {
		return t, &histogram.FloatHistogram{Sum: hsi.currentFH.Sum}
	}

	if fh == nil {
		fh = &histogram.FloatHistogram{
			CounterResetHint: hsi.getFloatResetHint(hsi.currentFH.CounterResetHint),
			Count:            hsi.currentFH.Count,
			Sum:              hsi.currentFH.Sum,
		}
		hsi.setLastFH(hsi.currentFH)
		return t, fh
	}

	returnValue := histogram.FloatHistogram{
		CounterResetHint: hsi.getFloatResetHint(hsi.currentFH.CounterResetHint),
		Count:            hsi.currentFH.Count,
		Sum:              hsi.currentFH.Sum,
	}
	returnValue.CopyTo(fh)

	hsi.setLastFH(hsi.currentFH)
	return t, fh
}

func (hsi *HistogramStatsIterator) setLastFH(fh *histogram.FloatHistogram) {

Review comment (bug):
BTW, if you call AtFloatHistogram() twice without Next() in between. I think we always get `NotReset` on the second call. Even if the first hint was `Reset`.

Debug printout:
```
HistogramStatsIterator.AtFloatHistogram: 21 {count:1, sum:10, (1,2]:1} hint:0 retHint:1
vectorSelectorSingle: refTime=1260000, returning t=1260000
HistogramStatsIterator.AtFloatHistogram: 21 {count:1, sum:10, (1,2]:1} hint:0 retHint:2
```

From:
```
load 1m
     h{} {{schema:0 count:1 sum:10 buckets:[1]}}+{{}}x20 {{schema:0 count:1 sum:10 buckets:[0 1]}}+{{}}x20

eval instant at 41m increase(histogram_count(h)[40m:1m])
    {} 1.4814814814814814
```

Code after:

// Seek mostly relays to the underlying iterator, but changes a ValHistogram
// return into a ValFloatHistogram return.
func (hsi *HistogramStatsIterator) Seek(t int64) chunkenc.ValueType {
	// If the Seek is going to move the iterator, we have to forget the
	// lastFH and mark the currentFH as not current anymore.
	if t > hsi.AtT() {
		hsi.last = nil
		hsi.lastIsCurrent = false
	}
	vt := hsi.Iterator.Seek(t)
	if vt == chunkenc.ValHistogram {
		return chunkenc.ValFloatHistogram
	}
	return vt
}

// AtHistogram must never be called.
func (*HistogramStatsIterator) AtHistogram(*histogram.Histogram) (int64, *histogram.Histogram) {
	panic("HistogramStatsIterator.AtHistogram must never be called")
}

// AtFloatHistogram returns the next timestamp/float histogram pair. The method
// performs a counter reset detection on the fly. It will return an explicit
// hint (not UnknownCounterReset) if the previous sample has been accessed with
// the same iterator.
func (hsi *HistogramStatsIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
	populateFH := func(src *histogram.FloatHistogram, detectReset bool) {
		h := histogram.FloatHistogram{
			CounterResetHint: src.CounterResetHint,
			Count:            src.Count,
			Sum:              src.Sum,
		}
		if detectReset {
			h.CounterResetHint = hsi.getResetHint(src.CounterResetHint)
		}
		if fh == nil {
			// Note that we cannot simply write `fh = &h` here
			// because that would let h escape to the heap.
			fh = &histogram.FloatHistogram{}
			*fh = h
		} else {
			h.CopyTo(fh)
		}
	}

	if hsi.lastIsCurrent {
		// Nothing changed since last AtFloatHistogram call. Return a
		// copy of the stored last histogram rather than doing counter
		// reset detection again (which would yield a potentially wrong
		// result of "no counter reset").