diff --git a/tsdb/db_test.go b/tsdb/db_test.go index 2c9bfe6640..b0838fbb33 100644 --- a/tsdb/db_test.go +++ b/tsdb/db_test.go @@ -100,6 +100,26 @@ func openTestDB(t testing.TB, opts *Options, rngs []int64) (db *DB) { return db } +func openTestDBWithDir(t testing.TB, dir string, opts *Options, rngs []int64) (db *DB) { + var err error + + if opts == nil { + opts = DefaultOptions() + } + opts.EnableNativeHistograms = true + + if len(rngs) == 0 { + db, err = Open(dir, nil, nil, opts, nil) + } else { + opts, rngs = validateOpts(opts, rngs) + db, err = open(dir, nil, nil, opts, rngs, nil) + } + require.NoError(t, err) + + // Do not Close() the test database by default as it will deadlock on test failures. + return db +} + // query runs a matcher query against the querier and fully expands its data. func query(t testing.TB, q storage.Querier, matchers ...*labels.Matcher) map[string][]chunks.Sample { ss := q.Select(context.Background(), false, nil, matchers...) @@ -1472,6 +1492,69 @@ func TestTimeRetention(t *testing.T) { } } +func TestTsdbOpenTimeRetention(t *testing.T) { + testCases := []struct { + name string + blocks []*BlockMeta + expBlocks []*BlockMeta + retentionDuration int64 + }{ + { + name: "Block max time delta greater than retention duration", + blocks: []*BlockMeta{ + {MinTime: 500, MaxTime: 900}, // Oldest block, beyond retention + {MinTime: 1000, MaxTime: 1500}, + {MinTime: 1500, MaxTime: 2000}, // Newest block + }, + expBlocks: []*BlockMeta{ + {MinTime: 1000, MaxTime: 1500}, + {MinTime: 1500, MaxTime: 2000}, + }, + retentionDuration: 1000, + }, + { + name: "Block max time delta equal to retention duration", + blocks: []*BlockMeta{ + {MinTime: 500, MaxTime: 900}, // Oldest block + {MinTime: 1000, MaxTime: 1500}, // Coinciding exactly with the retention duration. + {MinTime: 1500, MaxTime: 2000}, // Newest block + }, + expBlocks: []*BlockMeta{ + {MinTime: 1500, MaxTime: 2000}, + }, + retentionDuration: 500, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + dir := t.TempDir() + db := openTestDBWithDir(t, dir, nil, []int64{1000}) + for _, m := range tc.blocks { + createBlock(t, db.Dir(), genSeries(10, 10, m.MinTime, m.MaxTime)) + } + + require.NoError(t, db.reloadBlocks()) // Reload the db to register the new blocks. + require.Len(t, db.Blocks(), len(tc.blocks)) // Ensure all blocks are registered. + + db.Close() + + db = openTestDBWithDir(t, dir, &Options{RetentionDuration: tc.retentionDuration}, []int64{1000}) + defer func() { + require.NoError(t, db.Close()) + }() + + actBlocks := db.Blocks() + require.Equal(t, 1, int(prom_testutil.ToFloat64(db.metrics.timeRetentionCount)), "metric retention count mismatch") + require.Len(t, actBlocks, len(tc.expBlocks)) + + for i, eb := range tc.expBlocks { + require.Equal(t, eb.MinTime, actBlocks[i].meta.MinTime) + require.Equal(t, eb.MaxTime, actBlocks[i].meta.MaxTime) + } + }) + } +} + func TestRetentionDurationMetric(t *testing.T) { db := openTestDB(t, &Options{ RetentionDuration: 1000,