Skip to content

Commit d74aad9

Browse files
mo4islonaclaudecodex
committed
feat(hotblocks): expose the LSM base level size
Raising write_buffer_size 8x without touching this left L0 arriving larger than the level it merges into: four 512 MB memtables flush ~512 MB of compressed L0 into a 256 MB L1, so every L0 compaction rewrites all of L1 and immediately pushes it down. The canonical pairing is base >= level0_file_num_compaction_trigger x the compressed flush size. It is also the lever the memtable change could not reach. A byte is rewritten once per level, and memtable size only addresses the L0->L1 hop; at ~60 GB live the ladder runs several levels deeper and that work is untouched. The production numbers show it: the bench predicted 2.4x fewer device writes at ~130 MB live, internal delivered 1.67x at ~60 GB. Default stays RocksDB's 256 MB, so this is inert until a deployment sets it. Deliberately unmeasured: the bench cannot price it at 130 MB live, where there is barely a ladder to shorten. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Co-Authored-By: Codex <[email protected]>
1 parent fb6cbbd commit d74aad9

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

crates/hotblocks/src/cli.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ pub struct CLI {
9191
#[arg(long, value_name = "N", default_value = "2")]
9292
pub rocksdb_max_write_buffers: i32,
9393

94+
/// Target size of the LSM base level. With ~60 GB live and the default
95+
/// multiplier of 10, this decides how many levels deep the ladder runs, and
96+
/// a byte is rewritten once per level it descends. The default 256 MB is
97+
/// smaller than one 512 MB memtable's flush, so L0 currently arrives larger
98+
/// than the level it merges into. Validate boot time and compaction behavior
99+
/// before raising it.
100+
#[arg(long, value_name = "MB", default_value = "256")]
101+
pub rocksdb_level_base_mb: usize,
102+
94103
/// Rewrite every table SST older than this, collecting dead data that never made a file
95104
/// tombstone-dense enough for the deletion collector. Lower means faster reclaim and
96105
/// proportionally more write amplification. 0 disables it, leaving RocksDB's 30-day
@@ -165,6 +174,7 @@ impl CLI {
165174
.with_periodic_compaction_secs(self.rocksdb_periodic_compaction_secs)
166175
.with_write_buffer_mb(self.rocksdb_write_buffer_mb)
167176
.with_max_write_buffers(self.rocksdb_max_write_buffers)
177+
.with_level_base_mb(self.rocksdb_level_base_mb)
168178
.with_block_hash_index(self.block_hash_index)
169179
.with_transaction_hash_index(self.transaction_hash_index);
170180

crates/storage/src/db/db.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub struct DatabaseSettings {
6060
with_rocksdb_stats: bool,
6161
write_buffer_mb: usize,
6262
max_write_buffers: i32,
63+
level_base_mb: usize,
6364
direct_io: bool,
6465
cache_index_and_filter_blocks: bool,
6566
max_log_file_size: usize,
@@ -89,6 +90,7 @@ impl Default for DatabaseSettings {
8990
// RocksDB's own defaults; the CLI carries the deployed values
9091
write_buffer_mb: 64,
9192
max_write_buffers: 2,
93+
level_base_mb: 256,
9294
direct_io: false,
9395
cache_index_and_filter_blocks: false,
9496
max_log_file_size: 10,
@@ -133,6 +135,11 @@ impl DatabaseSettings {
133135
self
134136
}
135137

138+
pub fn with_level_base_mb(mut self, mb: usize) -> Self {
139+
self.level_base_mb = mb;
140+
self
141+
}
142+
136143
pub fn with_cache_index_and_filter_blocks(mut self, yes: bool) -> Self {
137144
self.cache_index_and_filter_blocks = yes;
138145
self
@@ -257,6 +264,10 @@ impl DatabaseSettings {
257264
// memory cost (write_buffer_mb x max_write_buffers) is paid once rather than per CF.
258265
options.set_write_buffer_size(self.write_buffer_mb << 20);
259266
options.set_max_write_buffer_number(self.max_write_buffers);
267+
// Sets how many levels the ladder has, and a byte is rewritten once per level.
268+
// Wants to be >= level0_file_num_compaction_trigger x the compressed flush size,
269+
// or L0 arrives larger than the level it merges into.
270+
options.set_max_bytes_for_level_base((self.level_base_mb as u64) << 20);
260271
if !self.auto_compactions {
261272
options.set_disable_auto_compactions(true);
262273
}

0 commit comments

Comments
 (0)