From 299e08aed85684a815ffd0367134ea18fa0e4c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Fri, 25 Oct 2024 16:53:54 +0200 Subject: [PATCH] fix(tsdb): Clear reset hint when switching between ino and ooo head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear the native histogram counter reset hint when switching between the in-order and out-of-order head. Given the samples written in this order: t=1, v=40 t=4, v=30 (reset in in-order) t=2, v=40 t=3, v=10 (reset in out-of-order) When we read them back, this is the order: t=1, v=40 t=2, v=40 t=3, v=10 (reset in readback) t=4, v=30 Without this fix we also see a reset for t=4, v=30 because the chunk is a non-overlapping in-order chunk and it is used as is. The fix is to detect when we switch between in-order and out-of-order chunks and wrap the next chunk in an iterator that clears the counter reset as if it overlapped with another chunk. Signed-off-by: György Krajcsovits --- tsdb/head_read.go | 4 ++++ tsdb/ooo_head_read.go | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tsdb/head_read.go b/tsdb/head_read.go index 29adc3ee74..2a25e77725 100644 --- a/tsdb/head_read.go +++ b/tsdb/head_read.go @@ -262,6 +262,10 @@ func unpackHeadChunkRef(ref chunks.ChunkRef) (seriesID chunks.HeadSeriesRef, chu return sid, (cid & (oooChunkIDMask - 1)), (cid & oooChunkIDMask) != 0 } +func isOOOChunkID(cid chunks.HeadChunkID) bool { + return (cid & oooChunkIDMask) != 0 +} + // LabelValueFor returns label value for the given label name in the series referred to by ID. func (h *headIndexReader) LabelValueFor(_ context.Context, id storage.SeriesRef, label string) (string, error) { memSeries := h.head.series.getByID(chunks.HeadSeriesRef(id)) diff --git a/tsdb/ooo_head_read.go b/tsdb/ooo_head_read.go index 26cd4d057e..78ed1c4cdc 100644 --- a/tsdb/ooo_head_read.go +++ b/tsdb/ooo_head_read.go @@ -146,9 +146,13 @@ func getOOOSeriesChunks(s *memSeries, mint, maxt int64, lastGarbageCollectedMmap // In the example 5 overlaps with 7 and 6 overlaps with 8 so we will return // [5,7], [6,8]. toBeMerged := tmpChks[0] - for _, c := range tmpChks[1:] { - if c.MinTime > toBeMerged.MaxTime { - // This chunk doesn't overlap. Send current toBeMerged to output and start a new one. + prevIsOOO := false + for i, c := range tmpChks[1:] { + currIsOOO := isOOOChunkID(chunks.HeadChunkID(c.Ref)) + if c.MinTime > toBeMerged.MaxTime && (i == 0 || prevIsOOO == currIsOOO) { + // This chunk doesn't overlap and we are not switching between in-order + // and out-of-order chunks. Send current toBeMerged to output and start + // a new one. *chks = append(*chks, toBeMerged) toBeMerged = c } else { @@ -162,6 +166,7 @@ func getOOOSeriesChunks(s *memSeries, mint, maxt int64, lastGarbageCollectedMmap toBeMerged.MaxTime = c.MaxTime } } + prevIsOOO = currIsOOO } *chks = append(*chks, toBeMerged)