From 55effbfc3aa2a6b678252fa1ef925f7e3bf05c51 Mon Sep 17 00:00:00 2001 From: Carrie Edwards Date: Tue, 5 May 2026 09:52:37 -0700 Subject: [PATCH] Fix for appendHistogram Signed-off-by: Carrie Edwards --- tsdb/head_append.go | 16 +++++++++++-- tsdb/head_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/tsdb/head_append.go b/tsdb/head_append.go index c7143d8d96..e6d243f074 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -1873,7 +1873,13 @@ func (s *memSeries) appendHistogram(st, t int64, h *histogram.Histogram, appendI // chunk reference afterwards and mmap used up chunks. // Ignoring ok is ok, since we don't want to compare to the wrong previous appender anyway. - prevApp, _ := s.app.(*chunkenc.HistogramAppender) + var prevApp *chunkenc.HistogramAppender + switch p := s.app.(type) { + case *chunkenc.HistogramAppender: + prevApp = p + case *chunkenc.HistogramSTAppender: + prevApp = &p.HistogramAppender + } c, sampleInOrder, chunkCreated := s.histogramsAppendPreprocessor(t, chunkenc.ValHistogram.ChunkEncoding(o.useXOR2), o) if !sampleInOrder { @@ -1930,7 +1936,13 @@ func (s *memSeries) appendFloatHistogram(st, t int64, fh *histogram.FloatHistogr // chunk reference afterwards and mmap used up chunks. // Ignoring ok is ok, since we don't want to compare to the wrong previous appender anyway. - prevApp, _ := s.app.(*chunkenc.FloatHistogramAppender) + var prevApp *chunkenc.FloatHistogramAppender + switch p := s.app.(type) { + case *chunkenc.FloatHistogramAppender: + prevApp = p + case *chunkenc.FloatHistogramSTAppender: + prevApp = &p.FloatHistogramAppender + } c, sampleInOrder, chunkCreated := s.histogramsAppendPreprocessor(t, chunkenc.ValFloatHistogram.ChunkEncoding(o.useXOR2), o) if !sampleInOrder { diff --git a/tsdb/head_test.go b/tsdb/head_test.go index 1000b292ea..7f8eb84286 100644 --- a/tsdb/head_test.go +++ b/tsdb/head_test.go @@ -5179,6 +5179,63 @@ func TestHistogramCounterResetHeader(t *testing.T) { } } +func TestHistogramSTCounterResetHeaderOnChunkCut(t *testing.T) { + for _, floatHisto := range []bool{false, true} { + t.Run(fmt.Sprintf("floatHistogram=%t", floatHisto), func(t *testing.T) { + l := labels.FromStrings("a", "b") + opts := newTestHeadDefaultOptions(2, false) + opts.EnableXOR2Encoding.Store(true) + head, _ := newTestHeadWithOptions(t, compression.None, opts) + t.Cleanup(func() { + require.NoError(t, head.Close()) + }) + require.NoError(t, head.Init(0)) + + appendHistogram := func(ts int64, h *histogram.Histogram) { + app := head.Appender(context.Background()) + var err error + if floatHisto { + _, err = app.AppendHistogram(0, l, ts, nil, h.ToFloat(nil)) + } else { + _, err = app.AppendHistogram(0, l, ts, h.Copy(), nil) + } + require.NoError(t, err) + require.NoError(t, app.Commit()) + } + + h1 := tsdbutil.GenerateTestHistogram(0) + h2 := tsdbutil.GenerateTestHistogram(1) + + // Chunk range is 2, so appending at t=1 and t=2 cuts a new chunk on the second append. + appendHistogram(1, h1) + appendHistogram(2, h2) + + ms, _, err := head.getOrCreate(l.Hash(), l, false) + require.NoError(t, err) + require.NotNil(t, ms.headChunks) + require.NotNil(t, ms.headChunks.prev) + + if floatHisto { + prevChunk, ok := ms.headChunks.prev.chunk.(*chunkenc.FloatHistogramSTChunk) + require.True(t, ok) + require.Equal(t, chunkenc.UnknownCounterReset, prevChunk.GetCounterResetHeader()) + + headChunk, ok := ms.headChunks.chunk.(*chunkenc.FloatHistogramSTChunk) + require.True(t, ok) + require.Equal(t, chunkenc.NotCounterReset, headChunk.GetCounterResetHeader()) + } else { + prevChunk, ok := ms.headChunks.prev.chunk.(*chunkenc.HistogramSTChunk) + require.True(t, ok) + require.Equal(t, chunkenc.UnknownCounterReset, prevChunk.GetCounterResetHeader()) + + headChunk, ok := ms.headChunks.chunk.(*chunkenc.HistogramSTChunk) + require.True(t, ok) + require.Equal(t, chunkenc.NotCounterReset, headChunk.GetCounterResetHeader()) + } + }) + } +} + func TestOOOHistogramCounterResetHeaders(t *testing.T) { for _, floatHisto := range []bool{true, false} { t.Run(fmt.Sprintf("floatHistogram=%t", floatHisto), func(t *testing.T) {