From 74ed44a1c6f8657874aa0f385102270343fb306b Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Thu, 3 Aug 2023 10:56:27 +0200 Subject: [PATCH] Pass ref to SeriesLifecycleCallback.PostDeletion (#12626) When a particular SeriesLifecycleCallback tries to optimize and run closer to the Head, keeping track of the HeadSeriesRef instead of the labelsets, it's impossible to handle the PostDeletion callback properly as there's no way to know which series refs were deleted from the head. This changes the callback to provide the series refs alongside the labelsets, so the implementation can choose what to do. Signed-off-by: Oleg Zaytsev --- tsdb/head.go | 25 +++++++++++++------------ tsdb/head_bench_test.go | 7 ++++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tsdb/head.go b/tsdb/head.go index e6433ec474..ed724c068d 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -230,7 +230,7 @@ type SeriesLifecycleCallback interface { // PostCreation is called after creating a series to indicate a creation of series. PostCreation(labels.Labels) // PostDeletion is called after deletion of series. - PostDeletion(...labels.Labels) + PostDeletion(map[chunks.HeadSeriesRef]labels.Labels) } // NewHead opens the head block in dir. @@ -1748,16 +1748,17 @@ func newStripeSeries(stripeSize int, seriesCallback SeriesLifecycleCallback) *st // minMmapFile is the min mmap file number seen in the series (in-order and out-of-order) after gc'ing the series. func (s *stripeSeries) gc(mint int64, minOOOMmapRef chunks.ChunkDiskMapperRef) (_ map[storage.SeriesRef]struct{}, _ int, _, _ int64, minMmapFile int) { var ( - deleted = map[storage.SeriesRef]struct{}{} - deletedForCallback = []labels.Labels{} - rmChunks = 0 - actualMint int64 = math.MaxInt64 - minOOOTime int64 = math.MaxInt64 + deleted = map[storage.SeriesRef]struct{}{} + rmChunks = 0 + actualMint int64 = math.MaxInt64 + minOOOTime int64 = math.MaxInt64 + deletedFromPrevStripe = 0 ) minMmapFile = math.MaxInt32 // Run through all series and truncate old chunks. Mark those with no // chunks left as deleted and store their ID. for i := 0; i < s.size; i++ { + deletedForCallback := make(map[chunks.HeadSeriesRef]labels.Labels, deletedFromPrevStripe) s.locks[i].Lock() for hash, all := range s.hashes[i] { @@ -1811,7 +1812,7 @@ func (s *stripeSeries) gc(mint int64, minOOOMmapRef chunks.ChunkDiskMapperRef) ( deleted[storage.SeriesRef(series.ref)] = struct{}{} s.hashes[i].del(hash, series.lset) delete(s.series[j], series.ref) - deletedForCallback = append(deletedForCallback, series.lset) + deletedForCallback[series.ref] = series.lset if i != j { s.locks[j].Unlock() @@ -1823,8 +1824,8 @@ func (s *stripeSeries) gc(mint int64, minOOOMmapRef chunks.ChunkDiskMapperRef) ( s.locks[i].Unlock() - s.seriesLifecycleCallback.PostDeletion(deletedForCallback...) - deletedForCallback = deletedForCallback[:0] + s.seriesLifecycleCallback.PostDeletion(deletedForCallback) + deletedFromPrevStripe = len(deletedForCallback) } if actualMint == math.MaxInt64 { @@ -2112,9 +2113,9 @@ func (mc *mmappedChunk) OverlapsClosedInterval(mint, maxt int64) bool { type noopSeriesLifecycleCallback struct{} -func (noopSeriesLifecycleCallback) PreCreation(labels.Labels) error { return nil } -func (noopSeriesLifecycleCallback) PostCreation(labels.Labels) {} -func (noopSeriesLifecycleCallback) PostDeletion(...labels.Labels) {} +func (noopSeriesLifecycleCallback) PreCreation(labels.Labels) error { return nil } +func (noopSeriesLifecycleCallback) PostCreation(labels.Labels) {} +func (noopSeriesLifecycleCallback) PostDeletion(map[chunks.HeadSeriesRef]labels.Labels) {} func (h *Head) Size() int64 { var walSize, wblSize int64 diff --git a/tsdb/head_bench_test.go b/tsdb/head_bench_test.go index 2f8e0ba374..8fdf94db0e 100644 --- a/tsdb/head_bench_test.go +++ b/tsdb/head_bench_test.go @@ -22,6 +22,7 @@ import ( "go.uber.org/atomic" "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/tsdb/chunks" ) func BenchmarkHeadStripeSeriesCreate(b *testing.B) { @@ -80,6 +81,6 @@ func BenchmarkHeadStripeSeriesCreate_PreCreationFailure(b *testing.B) { type failingSeriesLifecycleCallback struct{} -func (failingSeriesLifecycleCallback) PreCreation(labels.Labels) error { return errors.New("failed") } -func (failingSeriesLifecycleCallback) PostCreation(labels.Labels) {} -func (failingSeriesLifecycleCallback) PostDeletion(...labels.Labels) {} +func (failingSeriesLifecycleCallback) PreCreation(labels.Labels) error { return errors.New("failed") } +func (failingSeriesLifecycleCallback) PostCreation(labels.Labels) {} +func (failingSeriesLifecycleCallback) PostDeletion(map[chunks.HeadSeriesRef]labels.Labels) {}