Repository: prometheus/prometheus
File: model/histogram/float_histogram.go (Go)

Code before:
		otherNegativeBuckets = other.NegativeBuckets
	)

	switch {
	case other.Schema < h.Schema:
		hPositiveSpans, hPositiveBuckets = reduceResolution(hPositiveSpans, hPositiveBuckets, h.Schema, other.Schema, false, true)
		hNegativeSpans, hNegativeBuckets = reduceResolution(hNegativeSpans, hNegativeBuckets, h.Schema, other.Schema, false, true)
		h.Schema = other.Schema

	case other.Schema > h.Schema:
		otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false, false)
		otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false, false)
	}

	h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, hPositiveSpans, hPositiveBuckets, otherPositiveSpans, otherPositiveBuckets)
	h.NegativeSpans, h.NegativeBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, hNegativeSpans, hNegativeBuckets, otherNegativeSpans, otherNegativeBuckets)

	return h, nil
}

// isNegated returns true if at least one of the following is true:
// - h has negative ZeroCount, Count, Sum
// - h has negative PositiveBuckets
// - h has negative NegativeBuckets
func (h *FloatHistogram) isNegated() bool {
	if h.ZeroCount < 0 || h.Count < 0 || h.Sum < 0 {
		return true
	}
	for i := range h.PositiveBuckets {
		if h.PositiveBuckets[i] < 0 {
			return true
		}
	}
	for i := range h.NegativeBuckets {
		if h.NegativeBuckets[i] < 0 {
			return true
		}
	}
	return false
}

// Sub works like Add but subtracts the other histogram.
func (h *FloatHistogram) Sub(other *FloatHistogram) (*FloatHistogram, error) {
	if h.UsesCustomBuckets() != other.UsesCustomBuckets() {
		return nil, ErrHistogramsIncompatibleSchema
	}
	if h.UsesCustomBuckets() && !FloatBucketsMatch(h.CustomValues, other.CustomValues) {
		return nil, ErrHistogramsIncompatibleBounds
	}

	if !h.UsesCustomBuckets() {

Review comment (suggestion):
The `Sum` value can be negative for a counter as well if there are negative buckets, so that doesn't matter for counter reset detection, just ignore it.


Code after:
		otherNegativeBuckets = other.NegativeBuckets
	)

	switch {
	case other.Schema < h.Schema:
		hPositiveSpans, hPositiveBuckets = reduceResolution(hPositiveSpans, hPositiveBuckets, h.Schema, other.Schema, false, true)
		hNegativeSpans, hNegativeBuckets = reduceResolution(hNegativeSpans, hNegativeBuckets, h.Schema, other.Schema, false, true)
		h.Schema = other.Schema

	case other.Schema > h.Schema:
		otherPositiveSpans, otherPositiveBuckets = reduceResolution(otherPositiveSpans, otherPositiveBuckets, other.Schema, h.Schema, false, false)
		otherNegativeSpans, otherNegativeBuckets = reduceResolution(otherNegativeSpans, otherNegativeBuckets, other.Schema, h.Schema, false, false)
	}

	h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, hPositiveSpans, hPositiveBuckets, otherPositiveSpans, otherPositiveBuckets)
	h.NegativeSpans, h.NegativeBuckets = addBuckets(h.Schema, h.ZeroThreshold, false, hNegativeSpans, hNegativeBuckets, otherNegativeSpans, otherNegativeBuckets)

	return h, nil
}

// Sub works like Add but subtracts the other histogram.
func (h *FloatHistogram) Sub(other *FloatHistogram) (*FloatHistogram, error) {
	if h.UsesCustomBuckets() != other.UsesCustomBuckets() {
		return nil, ErrHistogramsIncompatibleSchema
	}
	if h.UsesCustomBuckets() && !FloatBucketsMatch(h.CustomValues, other.CustomValues) {
		return nil, ErrHistogramsIncompatibleBounds
	}

	// Prevent counter resets when subtracting as this might decrease counters.
	h.CounterResetHint = GaugeType

	if !h.UsesCustomBuckets() {
		otherZeroCount := h.reconcileZeroBuckets(other)
		h.ZeroCount -= otherZeroCount
	}
	h.Count -= other.Count
	h.Sum -= other.Sum

	var (
		hPositiveSpans       = h.PositiveSpans
		hPositiveBuckets     = h.PositiveBuckets
		otherPositiveSpans   = other.PositiveSpans
		otherPositiveBuckets = other.PositiveBuckets
	)

	if h.UsesCustomBuckets() {
		h.PositiveSpans, h.PositiveBuckets = addBuckets(h.Schema, h.ZeroThreshold, true, hPositiveSpans, hPositiveBuckets, otherPositiveSpans, otherPositiveBuckets)
		return h, nil
	}