mirror of
https://github.com/prometheus/prometheus.git
synced 2026-02-03 20:39:32 -05:00
tsdb: fix division by zero in stale series compaction (#17952)
Guard the stale series ratio calculation by checking numSeries > 0 before computing the ratio. This prevents division by zero when the head has no series. Fixes #17949 Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
parent
dc34b90f93
commit
00a7faa2e3
2 changed files with 39 additions and 14 deletions
29
tsdb/db.go
29
tsdb/db.go
|
|
@ -1172,22 +1172,23 @@ func (db *DB) run(ctx context.Context) {
|
|||
db.head.mmapHeadChunks()
|
||||
|
||||
numStaleSeries, numSeries := db.Head().NumStaleSeries(), db.Head().NumSeries()
|
||||
staleSeriesRatio := float64(numStaleSeries) / float64(numSeries)
|
||||
if db.autoCompact && db.opts.staleSeriesCompactionThreshold.Load() > 0 &&
|
||||
staleSeriesRatio >= db.opts.staleSeriesCompactionThreshold.Load() {
|
||||
nextCompactionIsSoon := false
|
||||
if !db.lastHeadCompactionTime.IsZero() {
|
||||
compactionInterval := time.Duration(db.head.chunkRange.Load()) * time.Millisecond
|
||||
nextEstimatedCompactionTime := db.lastHeadCompactionTime.Add(compactionInterval)
|
||||
if time.Now().Add(10 * time.Minute).After(nextEstimatedCompactionTime) {
|
||||
// Next compaction is starting within next 10 mins.
|
||||
nextCompactionIsSoon = true
|
||||
if db.autoCompact && numSeries > 0 && db.opts.staleSeriesCompactionThreshold.Load() > 0 {
|
||||
staleSeriesRatio := float64(numStaleSeries) / float64(numSeries)
|
||||
if staleSeriesRatio >= db.opts.staleSeriesCompactionThreshold.Load() {
|
||||
nextCompactionIsSoon := false
|
||||
if !db.lastHeadCompactionTime.IsZero() {
|
||||
compactionInterval := time.Duration(db.head.chunkRange.Load()) * time.Millisecond
|
||||
nextEstimatedCompactionTime := db.lastHeadCompactionTime.Add(compactionInterval)
|
||||
if time.Now().Add(10 * time.Minute).After(nextEstimatedCompactionTime) {
|
||||
// Next compaction is starting within next 10 mins.
|
||||
nextCompactionIsSoon = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !nextCompactionIsSoon {
|
||||
if err := db.CompactStaleHead(); err != nil {
|
||||
db.logger.Error("immediate stale series compaction failed", "err", err)
|
||||
if !nextCompactionIsSoon {
|
||||
if err := db.CompactStaleHead(); err != nil {
|
||||
db.logger.Error("immediate stale series compaction failed", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9561,3 +9561,27 @@ func TestStaleSeriesCompaction(t *testing.T) {
|
|||
verifyHeadBlock()
|
||||
}
|
||||
}
|
||||
|
||||
// TestStaleSeriesCompactionWithZeroSeries verifies that CompactStaleHead handles
|
||||
// an empty head (0 series) gracefully without division by zero or incorrectly
|
||||
// triggering compaction. This is a regression test for issue #17949.
|
||||
func TestStaleSeriesCompactionWithZeroSeries(t *testing.T) {
|
||||
opts := DefaultOptions()
|
||||
opts.MinBlockDuration = 1000
|
||||
opts.MaxBlockDuration = 1000
|
||||
db := newTestDB(t, withOpts(opts))
|
||||
db.DisableCompactions()
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, db.Close())
|
||||
})
|
||||
|
||||
// Verify the head is empty.
|
||||
require.Equal(t, uint64(0), db.Head().NumSeries())
|
||||
require.Equal(t, uint64(0), db.Head().NumStaleSeries())
|
||||
|
||||
// CompactStaleHead should handle zero series gracefully (no panic, no error).
|
||||
require.NoError(t, db.CompactStaleHead())
|
||||
|
||||
// Should still have no blocks since there was nothing to compact.
|
||||
require.Empty(t, db.Blocks())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue