Skip to content

Commit 9ff7737

Browse files
committed
storage/upsert: v2 stash on ChunkBatcher; feedback arrangement as ChunkSpine with the UnloadChunk drain
1 parent 5ae338b commit 9ff7737

5 files changed

Lines changed: 314 additions & 273 deletions

File tree

misc/python/materialize/mzcompose/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ def get_variable_system_parameters(
299299
"true",
300300
["true", "false"],
301301
),
302+
VariableSystemParameter(
303+
"enable_upsert_paged_spill",
304+
"true",
305+
["true", "false"],
306+
),
302307
VariableSystemParameter(
303308
"enable_upsert_v2",
304309
"false",
@@ -598,7 +603,6 @@ def get_default_system_parameters(
598603
"column_paged_batcher_spill_worker_count",
599604
"column_paged_batcher_eager_backing",
600605
"column_paged_batcher_pool_rss_target_fraction",
601-
"enable_upsert_paged_spill",
602606
"enable_lgalloc_eager_reclamation",
603607
"lgalloc_background_interval",
604608
"lgalloc_file_growth_dampener",

src/storage-types/src/dyncfgs.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! Dyncfgs used by the storage layer. Despite their name, these can be used
1111
//! "statically" during rendering, or dynamically within timely operators.
1212
13-
use mz_dyncfg::{Config, ConfigSet};
13+
use mz_dyncfg::{Config, ConfigSet, ParameterScope};
1414
use std::time::Duration;
1515

1616
/// When dataflows observe an invariant violation it is either due to a bug or due to the cluster
@@ -328,22 +328,23 @@ pub const STORAGE_UPSERT_MAX_SNAPSHOT_BATCH_BUFFERING: Config<Option<usize>> = C
328328
"Limit snapshot buffering in upsert.",
329329
);
330330

331-
/// Allow the upsert-v2 source stash's chunk batcher to spill cold chains out
332-
/// of RSS via the process buffer pool. The stash draws from the same shared
333-
/// pool budget as the compute chunk batchers — there is one budget — but
334-
/// this flag gates the stash's participation independently of the
335-
/// compute-side `enable_column_paged_batcher_spill`.
331+
/// Storage's leg of the process-wide chunk spill gate
332+
/// (`mz_timely_util::columnar::chunk`). The gate is the OR of a compute leg
333+
/// (`enable_column_paged_batcher_spill`) and this storage leg: chunks spill
334+
/// while either is set, so this flag cannot veto spilling that the compute
335+
/// flag has enabled. Spilled chunks draw on the one shared pool budget.
336336
///
337-
/// Off by default; the stash keeps every chunk resident until enabled.
338-
/// Enabling it also installs the process buffer pool (via compute's config
339-
/// handler, which reads this flag from the aggregate dyncfg set), so
340-
/// storage-only spilling needs no compute-side gate.
337+
/// Off by default. Enabling it also installs the process buffer pool (via
338+
/// compute's config handler, which reads this flag from the aggregate dyncfg
339+
/// set), so storage-only spilling needs no compute-side gate.
341340
pub const ENABLE_UPSERT_PAGED_SPILL: Config<bool> = Config::new(
342341
"enable_upsert_paged_spill",
343342
false,
344-
"Allow the upsert-v2 source stash to spill chunks to the shared buffer pool, gated \
345-
independently of the compute `enable_column_paged_batcher_spill`.",
346-
);
343+
"Allow upsert-v2 chunks to spill to the shared buffer pool. Sets the storage leg of the \
344+
process-wide spill gate, which is the OR of this flag and the compute \
345+
`enable_column_paged_batcher_spill`.",
346+
)
347+
.scoped(ParameterScope::Replica);
347348

348349
// RocksDB
349350

src/storage/src/storage_state.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -846,17 +846,27 @@ impl<'w> Worker<'w> {
846846
STORAGE_SERVER_MAINTENANCE_INTERVAL
847847
.get(self.storage_state.storage_configuration.config_set());
848848

849-
// Gate the upsert source-stash's use of the column pager. The
850-
// pager's budget pool, backend, and codec are the shared ones
849+
// Set storage's leg of the process-wide chunk spill gate.
850+
// The buffer pool and its budget are the shared ones
851851
// configured by compute's `apply_worker_config` (compute and
852-
// storage run in the same process); storage only decides whether
853-
// its stash participates, via its own dyncfg.
852+
// storage run in the same process). The gate ORs this leg
853+
// with compute's, so chunks spill while either subsystem's
854+
// flag is set.
855+
//
856+
// The flag is replica-scoped: the storage controller merges
857+
// per-replica overrides into the `UpdateConfiguration`
858+
// commands it sends, so reading this worker's `ConfigSet`
859+
// here observes them.
854860
{
855861
use mz_storage_types::dyncfgs::ENABLE_UPSERT_PAGED_SPILL;
856862

857863
let enabled = ENABLE_UPSERT_PAGED_SPILL
858864
.get(self.storage_state.storage_configuration.config_set());
859-
crate::upsert::upsert_stash_pager::set_enabled(enabled);
865+
info!(
866+
worker = self.timely_worker.index(),
867+
enabled, "upsert stash spill: applying gate",
868+
);
869+
crate::upsert::upsert_stash_spill::set_enabled(enabled);
860870
}
861871
}
862872
InternalStorageCommand::StatisticsUpdate { sources, sinks } => self

src/storage/src/upsert.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -296,37 +296,22 @@ macro_rules! upsert_source_time_unit {
296296
}
297297
upsert_source_time_unit!(GtidPartition, Lsn);
298298

299-
/// Pager for the upsert-v2 source stash.
299+
/// Storage's leg of the process-wide chunk spill gate.
300300
///
301-
/// This draws from the same process-wide [`TieredPolicy`] budget pool as the
302-
/// compute column-paged batcher — there is one budget and one underlying
303-
/// `mz_ore::pager` — but whether the stash *uses* it is gated by storage's own
304-
/// `enable_upsert_paged_spill` flag, independently of compute's
305-
/// `enable_column_paged_batcher_spill`. The shared pool's budget / backend /
306-
/// codec are configured by compute's `apply_tiered_config` (storage and compute
307-
/// run in the same `clusterd` process).
301+
/// The upsert-v2 source stash and feedback arrangement spill through the
302+
/// process buffer pool ([`mz_timely_util::columnar::chunk`]): committed chunk
303+
/// bodies land in the pool once compute's config handler has installed and
304+
/// budgeted it (storage and compute run in the same `clusterd` process).
308305
///
309-
/// [`TieredPolicy`]: mz_timely_util::column_pager::policy::TieredPolicy
310-
pub mod upsert_stash_pager {
311-
use std::sync::{LazyLock, RwLock};
312-
313-
use mz_timely_util::column_pager::{ColumnPager, shared_pager};
314-
315-
/// Active pager handed to upsert source-stash batchers. Defaults to
316-
/// disabled (every chunk resident) until [`set_enabled`] turns it on.
317-
static PAGER: LazyLock<RwLock<ColumnPager>> =
318-
LazyLock::new(|| RwLock::new(ColumnPager::disabled()));
319-
320-
/// Enable or disable the stash's use of the shared column pager. When
321-
/// enabled, the stash spills through the shared budget pool; when disabled
322-
/// it keeps every chunk resident.
306+
/// The gate is process-wide with one leg per subsystem, and chunks spill
307+
/// while either leg is set. Storage sets its leg from
308+
/// `enable_upsert_paged_spill`, so that flag alone cannot veto spilling
309+
/// enabled by compute's leg. The gate is consulted at every chunk commit, so
310+
/// flips apply to running dataflows.
311+
pub mod upsert_stash_spill {
312+
/// Enable or disable spilling of upsert chunk bodies to the buffer pool.
323313
pub fn set_enabled(enabled: bool) {
324-
*PAGER.write().expect("upsert stash pager poisoned") = shared_pager(enabled);
325-
}
326-
327-
/// The current upsert-stash pager. Cheap: clones the inner `Arc`.
328-
pub fn pager() -> ColumnPager {
329-
PAGER.read().expect("upsert stash pager poisoned").clone()
314+
mz_timely_util::columnar::chunk::set_storage_spill_enabled(enabled);
330315
}
331316
}
332317

0 commit comments

Comments
 (0)