Skip to content

Commit e9cbc7b

Browse files
committed
fix: native histogram: Simplify and fix addExemplar
mdIdx was redundant when len(exemplars)>1, so got rid of it, rIdx is enough. Don't compare timestamp of incoming exemplar to timestamp of minimal distance exemplar. Most of the time the incoming exemplar will be newer. And if not, the previous code just replaced an exemplar one index after the minimal distance exemplar. Which had an index out of range bug, plus is essentially random. Signed-off-by: György Krajcsovits <[email protected]> # Conflicts: # prometheus/histogram.go
1 parent 5123705 commit e9cbc7b

File tree

1 file changed

+28
-18
lines changed

1 file changed

+28
-18
lines changed

prometheus/histogram.go

+28-18
Original file line numberDiff line numberDiff line change
@@ -1705,17 +1705,23 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
17051705
return
17061706
}
17071707

1708+
if len(n.exemplars) == 1 {
1709+
// When the number of exemplars is 1, then
1710+
// replace the existing exemplar with the new exemplar.
1711+
n.exemplars[0] = e
1712+
return
1713+
}
1714+
// From this point on, the number of exemplars is greater than 1.
1715+
17081716
// When the number of exemplars exceeds the limit, remove one exemplar.
17091717
var (
1710-
rIdx int // The index where to remove the old exemplar.
1711-
17121718
ot = time.Now() // Oldest timestamp seen.
17131719
otIdx = -1 // Index of the exemplar with the oldest timestamp.
17141720

1715-
md = -1.0 // Logarithm of the delta of the closest pair of exemplars.
1716-
mdIdx = -1 // Index of the older exemplar within the closest pair.
1717-
cLog float64 // Logarithm of the current exemplar.
1718-
pLog float64 // Logarithm of the previous exemplar.
1721+
md = -1.0 // Logarithm of the delta of the closest pair of exemplars.
1722+
rIdx = -1 // Index of the older exemplar within the closest pair and where we need to insert the new exemplar.
1723+
cLog float64 // Logarithm of the current exemplar.
1724+
pLog float64 // Logarithm of the previous exemplar.
17191725
)
17201726

17211727
for i, exemplar := range n.exemplars {
@@ -1726,7 +1732,7 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
17261732
}
17271733

17281734
// Find the index at which to insert new the exemplar.
1729-
if *e.Value <= *exemplar.Value && nIdx == -1 {
1735+
if nIdx == -1 && *e.Value <= *exemplar.Value {
17301736
nIdx = i
17311737
}
17321738

@@ -1738,11 +1744,13 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
17381744
}
17391745
diff := math.Abs(cLog - pLog)
17401746
if md == -1 || diff < md {
1747+
// The closest exemplar pair is this: |exemplar.[i] - n.exemplars[i-1].Value| is minimal.
1748+
// Choose the exemplar with the older timestamp for replacement.
17411749
md = diff
17421750
if n.exemplars[i].Timestamp.AsTime().Before(n.exemplars[i-1].Timestamp.AsTime()) {
1743-
mdIdx = i
1751+
rIdx = i
17441752
} else {
1745-
mdIdx = i - 1
1753+
rIdx = i - 1
17461754
}
17471755
}
17481756

@@ -1753,8 +1761,11 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
17531761
if nIdx == -1 {
17541762
nIdx = len(n.exemplars)
17551763
}
1764+
// Here, we have the following relationships:
1765+
// n.exemplars[nIdx-1].Value < e.Value <= n.exemplars[nIdx].Value
17561766

17571767
if otIdx != -1 && e.Timestamp.AsTime().Sub(ot) > time.Duration(ttl) {
1768+
// If the oldest exemplar has expired, then replace it with the new exemplar.
17581769
rIdx = otIdx
17591770
} else {
17601771
// In the previous for loop, when calculating the closest pair of exemplars,
@@ -1764,23 +1775,22 @@ func (n *nativeExemplars) addExemplar(e *dto.Exemplar) {
17641775
if nIdx > 0 {
17651776
diff := math.Abs(elog - math.Log(n.exemplars[nIdx-1].GetValue()))
17661777
if diff < md {
1778+
// The closest exemplar pair is this: |e.Value - n.exemplars[nIdx-1].Value| is minimal.
1779+
// Assume that the exemplar we are inserting has a newer timestamp. This is not always
1780+
// true, due to concurrency, but it's a good enough approximation.
17671781
md = diff
1768-
mdIdx = nIdx
1769-
if n.exemplars[nIdx-1].Timestamp.AsTime().Before(e.Timestamp.AsTime()) {
1770-
mdIdx = nIdx - 1
1771-
}
1782+
rIdx = nIdx - 1
17721783
}
17731784
}
17741785
if nIdx < len(n.exemplars) {
17751786
diff := math.Abs(math.Log(n.exemplars[nIdx].GetValue()) - elog)
17761787
if diff < md {
1777-
mdIdx = nIdx
1778-
if n.exemplars[nIdx].Timestamp.AsTime().Before(e.Timestamp.AsTime()) {
1779-
mdIdx = nIdx
1780-
}
1788+
// The closest exemplar pair is this: |n.exemplars[nIdx].Value - e.Value| is minimal.
1789+
// Assume that the exemplar we are inserting has a newer timestamp. This is not always
1790+
// true, due to concurrency, but it's a good enough approximation.
1791+
rIdx = nIdx
17811792
}
17821793
}
1783-
rIdx = mdIdx
17841794
}
17851795

17861796
// Adjust the slice according to rIdx and nIdx.

0 commit comments

Comments
 (0)