Skip to content

Commit 8b6bc41

Browse files
ever0deRaduBerinde
authored andcommitted
compact: make TombstoneDenseCompactionThreshold dynamically reconfigurable
Previously, TombstoneDenseCompactionThreshold was a static float64 value that could only be set at initialization time. This made it impossible to dynamically adjust the threshold based on changing workload characteristics or operational requirements. This commit changes TombstoneDenseCompactionThreshold from a float64 to a function returning float64, following the pattern used by other dynamic options like CompactionGarbageFractionForMaxConcurrency and VirtualTableRewriteUnreferencedFraction. The default value remains 0.10. Benefits: - Allows runtime adjustment of tombstone compaction behavior - Enables workload-specific tuning without restarting the database - Makes it easier to turn down or disable tombstone compactions when they lead to increased resource usage with no visible latency benefits Changes: - Updated Options.Experimental.TombstoneDenseCompactionThreshold to func() float64 - Modified EnsureDefaults to use function wrapper - Updated String() and Parse() methods to handle function type - Modified pickTombstoneDensityCompaction to call the function - Updated all test files to use function syntax Fixes #5457.
1 parent 6f19d48 commit 8b6bc41

4 files changed

Lines changed: 22 additions & 13 deletions

File tree

compaction_picker.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,8 @@ func (p *compactionPickerByScore) pickRewriteCompaction(env compactionEnv) (pc *
15221522
func (p *compactionPickerByScore) pickTombstoneDensityCompaction(
15231523
env compactionEnv,
15241524
) (pc *pickedCompaction) {
1525-
if p.opts.Experimental.TombstoneDenseCompactionThreshold <= 0 {
1525+
threshold := p.opts.Experimental.TombstoneDenseCompactionThreshold()
1526+
if threshold <= 0 {
15261527
// Tombstone density compactions are disabled.
15271528
return nil
15281529
}
@@ -1545,7 +1546,7 @@ func (p *compactionPickerByScore) pickTombstoneDensityCompaction(
15451546
if f.IsCompacting() || !f.StatsValid() || f.Size == 0 {
15461547
continue
15471548
}
1548-
if f.Stats.TombstoneDenseBlocksRatio < p.opts.Experimental.TombstoneDenseCompactionThreshold {
1549+
if f.Stats.TombstoneDenseBlocksRatio < threshold {
15491550
continue
15501551
}
15511552
overlaps := p.vers.Overlaps(lastNonEmptyLevel, f.UserKeyBounds())

metamorphic/options_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func TestOptionsRoundtrip(t *testing.T) {
8080
"Experimental.RemoteStorage:",
8181
"Experimental.SingleDeleteInvariantViolationCallback:",
8282
"Experimental.EnableDeleteOnlyCompactionExcises:",
83+
"Experimental.TombstoneDenseCompactionThreshold:",
8384
"Levels[0].Compression:",
8485
"Levels[1].Compression:",
8586
"Levels[2].Compression:",
@@ -125,6 +126,7 @@ func TestOptionsRoundtrip(t *testing.T) {
125126
if o.Opts.Experimental.IngestSplit != nil && o.Opts.Experimental.IngestSplit() {
126127
require.Equal(t, o.Opts.Experimental.IngestSplit(), parsed.Opts.Experimental.IngestSplit())
127128
}
129+
require.Equal(t, o.Opts.Experimental.TombstoneDenseCompactionThreshold(), parsed.Opts.Experimental.TombstoneDenseCompactionThreshold())
128130

129131
expBaseline, expUpper := o.Opts.CompactionConcurrencyRange()
130132
parsedBaseline, parsedUpper := parsed.Opts.CompactionConcurrencyRange()

options.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -625,17 +625,19 @@ type Options struct {
625625
// sstable writers. The default value is 0.5.
626626
DeletionSizeRatioThreshold float32
627627

628-
// TombstoneDenseCompactionThreshold is the minimum percent of data
629-
// blocks in a table that must be tombstone-dense for that table to be
630-
// eligible for a tombstone density compaction. It should be defined as a
631-
// ratio out of 1. The default value is 0.10.
628+
// TombstoneDenseCompactionThreshold is a function that returns the minimum
629+
// percent of data blocks in a table that must be tombstone-dense for that
630+
// table to be eligible for a tombstone density compaction. The value should
631+
// be defined as a ratio out of 1. The default value is 0.10.
632632
//
633633
// If multiple tables are eligible for a tombstone density compaction, then
634634
// tables with a higher percent of tombstone-dense blocks are still
635635
// prioritized for compaction.
636636
//
637-
// A zero or negative value disables tombstone density compactions.
638-
TombstoneDenseCompactionThreshold float64
637+
// Using a function allows for dynamic reconfiguration of the threshold based
638+
// on workload characteristics. A zero or negative value disables tombstone
639+
// density compactions.
640+
TombstoneDenseCompactionThreshold func() float64
639641

640642
// TableCacheShards is the number of shards per table cache.
641643
// Reducing the value can reduce the number of idle goroutines per DB
@@ -1357,8 +1359,8 @@ func (o *Options) EnsureDefaults() *Options {
13571359
if o.Experimental.DeletionSizeRatioThreshold == 0 {
13581360
o.Experimental.DeletionSizeRatioThreshold = sstable.DefaultDeletionSizeRatioThreshold
13591361
}
1360-
if o.Experimental.TombstoneDenseCompactionThreshold == 0 {
1361-
o.Experimental.TombstoneDenseCompactionThreshold = 0.10
1362+
if o.Experimental.TombstoneDenseCompactionThreshold == nil {
1363+
o.Experimental.TombstoneDenseCompactionThreshold = func() float64 { return 0.10 }
13621364
}
13631365
if o.Experimental.TableCacheShards <= 0 {
13641366
o.Experimental.TableCacheShards = runtime.GOMAXPROCS(0)
@@ -1495,7 +1497,7 @@ func (o *Options) String() string {
14951497
fmt.Fprintf(&buf, " read_sampling_multiplier=%d\n", o.Experimental.ReadSamplingMultiplier)
14961498
fmt.Fprintf(&buf, " num_deletions_threshold=%d\n", o.Experimental.NumDeletionsThreshold)
14971499
fmt.Fprintf(&buf, " deletion_size_ratio_threshold=%f\n", o.Experimental.DeletionSizeRatioThreshold)
1498-
fmt.Fprintf(&buf, " tombstone_dense_compaction_threshold=%f\n", o.Experimental.TombstoneDenseCompactionThreshold)
1500+
fmt.Fprintf(&buf, " tombstone_dense_compaction_threshold=%f\n", o.Experimental.TombstoneDenseCompactionThreshold())
14991501
// We no longer care about strict_wal_tail, but set it to true in case an
15001502
// older version reads the options.
15011503
fmt.Fprintf(&buf, " strict_wal_tail=%t\n", true)
@@ -1899,7 +1901,11 @@ func (o *Options) Parse(s string, hooks *ParseHooks) error {
18991901
o.Experimental.DeletionSizeRatioThreshold = float32(val)
19001902
err = parseErr
19011903
case "tombstone_dense_compaction_threshold":
1902-
o.Experimental.TombstoneDenseCompactionThreshold, err = strconv.ParseFloat(value, 64)
1904+
var threshold float64
1905+
threshold, err = strconv.ParseFloat(value, 64)
1906+
if err == nil {
1907+
o.Experimental.TombstoneDenseCompactionThreshold = func() float64 { return threshold }
1908+
}
19031909
case "table_cache_shards":
19041910
o.Experimental.TableCacheShards, err = strconv.Atoi(value)
19051911
case "table_format":

options_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ func TestOptionsParse(t *testing.T) {
303303
opts.Experimental.ReadSamplingMultiplier = 400
304304
opts.Experimental.NumDeletionsThreshold = 500
305305
opts.Experimental.DeletionSizeRatioThreshold = 0.7
306-
opts.Experimental.TombstoneDenseCompactionThreshold = 0.2
306+
opts.Experimental.TombstoneDenseCompactionThreshold = func() float64 { return 0.2 }
307307
opts.Experimental.TableCacheShards = 500
308308
opts.Experimental.MaxWriterConcurrency = 1
309309
opts.Experimental.ForceWriterParallelism = true

0 commit comments

Comments
 (0)