Skip to main content

mz_compute_types/
dyncfgs.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Dyncfgs used by the compute layer.
11
12use std::time::Duration;
13
14use mz_dyncfg::{Config, ConfigSet, ParameterScope};
15
16/// Whether rendering should collapse error multiplicities to one where it arranges errors.
17///
18/// Error semantics depend only on whether an error is present, so its multiplicity carries no
19/// information a consumer reads. Left uncollapsed, a shared collection contributes its errors once
20/// per plan path that reads it, and because those factors apply again at each level of sharing they
21/// compound multiplicatively until the `Diff` overflows.
22///
23/// Governs sharing within a dataflow only. Sharing across objects is bounded unconditionally, by
24/// normalizing at every boundary another dataflow can read, so what this flag decides is never
25/// durable state and two replicas rendering under different values still write the same thing.
26/// Environment-scoped for now because nothing needs finer granularity, not because finer would be
27/// unsafe.
28pub const ENABLE_ERROR_DISTINCT: Config<bool> = Config::new(
29    "enable_compute_error_distinct",
30    true,
31    "Whether compute rendering should collapse error multiplicities to one where it arranges \
32     errors.",
33    ParameterScope::Environment,
34);
35
36/// Use the chunked merge batcher code path at arrange sites. When `true`,
37/// arrange operators batch through `ChunkBatcher` over
38/// `ColumnChunk` (in `mz_timely_util::columnar::chunk`) and build batches
39/// with `RowRowColPagedBuilder` (in `mz_row_spine`) behind
40/// `UnchunkBuilder`: columnar-native chains whose bodies the process buffer
41/// pool can spill (gated by [`ENABLE_COLUMN_PAGED_BATCHER_SPILL`]). Read at
42/// operator construction time. Flips take effect on dataflows created after
43/// the change.
44///
45/// Takes precedence over [`ENABLE_COLUMNAR_MERGE_BATCHER`]: both select
46/// columnar chains, and this one additionally makes them spillable. With
47/// both `false` the arrange sites use the columnation `Col2ValBatcher` /
48/// `RowRowBuilder` path. See
49/// `mz_compute::extensions::arrange::ArrangementBatcher` for the resolution.
50///
51/// Disabled by default while the new path is stabilizing.
52/// `DifferentialJoinHydration*` feature-benchmark scenarios opt in
53/// explicitly so the spill path is measured.
54pub const ENABLE_COLUMN_PAGED_BATCHER: Config<bool> = Config::new(
55    "enable_column_paged_batcher",
56    false,
57    "Use the columnar-native chunked merge batcher at arrange sites, whose chunk bodies the \
58     process buffer pool can spill. Takes precedence over enable_columnar_merge_batcher; \
59     with both false, arranges use the columnation `Col2ValBatcher` / `RowRowBuilder` path.",
60    ParameterScope::Replica,
61);
62
63/// Use the resident columnar merge batcher at arrange sites. When `true`,
64/// arrange operators use `Col2ValColBatcher` (in `mz_timely_util::columnar`)
65/// and `RowRowColPagedBuilder` (in `mz_row_spine`): the same `Column` chains
66/// and the same builder as the chunked arm, merged by `ColumnMerger` with
67/// no spill budget. When `false` (the default), the arrange sites
68/// use the columnation `Col2ValBatcher` / `RowRowBuilder` path. Read at
69/// operator construction time. Flips take effect on dataflows created after
70/// the change.
71///
72/// This is the columnation-versus-columnar axis on its own, so the two paths
73/// can be compared without spilling in the measurement. It is ignored while
74/// [`ENABLE_COLUMN_PAGED_BATCHER`] is `true`.
75pub const ENABLE_COLUMNAR_MERGE_BATCHER: Config<bool> = Config::new(
76    "enable_columnar_merge_batcher",
77    false,
78    "Use the resident columnar merge batcher at arrange sites, instead of the columnation \
79     one. Ignored when enable_column_paged_batcher is true.",
80    ParameterScope::Replica,
81);
82
83/// Store the accumulable reduce's accumulators in columnar form.
84///
85/// The accumulable reduce keeps one accumulator per aggregate in the diff of its
86/// input arrangement. When `true`, that arrangement holds its diffs in a columnar
87/// container, which lays the accumulators out by variant so each pays only for its
88/// own fields. When `false`, the diffs live in a columnation stack at the width of
89/// the largest variant. The default is `true`. Read at operator construction time,
90/// so flips take effect on dataflows created after the change.
91pub const ENABLE_COLUMNAR_ACCUMULABLE_DIFF: Config<bool> = Config::new(
92    "enable_columnar_accumulable_diff",
93    true,
94    "Store the accumulable reduce's accumulators in a columnar arrangement diff, laid out by \
95     variant, instead of a columnation stack of fixed-width accumulator enums.",
96    ParameterScope::Replica,
97);
98
99/// Allow chunk bodies to spill to the process buffer pool under memory
100/// pressure. Sets the compute chunk spill gate
101/// (`mz_timely_util::columnar::chunk::ComputeSpill`), which every compute
102/// chunk batcher reads. With the gate clear every compute chunk stays
103/// resident regardless of budget.
104///
105/// This flag (or the storage-side `enable_upsert_paged_spill`, or
106/// [`ENABLE_CORRECTION_V2_SPILL`]) also gates installation of the process
107/// buffer pool (`mz_ore::pool`): the first configuration tick with any of
108/// these gates on reserves the pool's virtual
109/// address space and spawns its spill threads. Turning the gates back off
110/// stops retuning but does not tear the installed pool down.
111///
112/// It additionally enables the process-global column pager, which storage's
113/// paged upsert stash draws from, so it is not exclusive to the arrange path.
114///
115/// Off by default, even when the batcher path itself is on, so the
116/// no-pressure case stays a pure resident operation. Tune the budget via
117/// [`COLUMN_PAGED_BATCHER_BUDGET_FRACTION`].
118pub const ENABLE_COLUMN_PAGED_BATCHER_SPILL: Config<bool> = Config::new(
119    "enable_column_paged_batcher_spill",
120    false,
121    "Allow chunk bodies to spill to the process buffer pool under memory pressure. Only \
122     meaningful for arrange sites when `enable_column_paged_batcher = true`.",
123    ParameterScope::Replica,
124);
125
126/// Whether the buffer pool may use the scratch directory as its extent
127/// store. Takes effect only at pool installation, see `apply_pool_config` in
128/// `mz_timely_util::pool_config`.
129pub const ENABLE_COLUMN_PAGED_BATCHER_FILE_EXTENTS: Config<bool> = Config::new(
130    "enable_column_paged_batcher_file_extents",
131    false,
132    "Use the scratch directory as the buffer pool's extent store when one exists. \
133     Read once at pool installation.",
134    ParameterScope::Replica,
135);
136
137/// How often the buffer pool's spill threads release free extent slots of
138/// the file store back to the filesystem. The default follows
139/// [`LGALLOC_BACKGROUND_INTERVAL`].
140pub const COLUMN_PAGED_BATCHER_FILE_RELEASE_INTERVAL: Config<Duration> = Config::new(
141    "column_paged_batcher_file_release_interval",
142    Duration::from_secs(1),
143    "Interval at which the buffer pool releases free file store slots to the filesystem. \
144     Zero disables the release.",
145    ParameterScope::Replica,
146);
147
148/// The most bytes of free file store slots the buffer pool releases per
149/// extent class and [`COLUMN_PAGED_BATCHER_FILE_RELEASE_INTERVAL`]. Zero
150/// disables the release, so the store keeps freed slots allocated until an
151/// allocation needs their room. The default follows
152/// [`LGALLOC_SLOW_CLEAR_BYTES`].
153pub const COLUMN_PAGED_BATCHER_FILE_RELEASE_BYTES: Config<usize> = Config::new(
154    "column_paged_batcher_file_release_bytes",
155    128 << 20,
156    "Bytes of free file store slots the buffer pool releases per extent class and interval. \
157     Zero disables the release.",
158    ParameterScope::Replica,
159);
160
161/// The youngest chunk generation whose spilled bodies are compressed.
162///
163/// A chunk at generational depth `d` is rewritten with frequency
164/// proportional to `2^-d` under geometric merging, so compressing shallow
165/// generations buys pool bytes back for only a short stay at a guaranteed
166/// near-term codec round-trip. Generations below the floor spill under the
167/// identity codec: fully budgeted and backed, with encode and decode
168/// reduced to copies. The default exempts only fresh (depth 0) chunks. A
169/// chunk that outlives a merge untouched ages a generation regardless, and
170/// an identity-coded body at or past the floor is re-spilled compressed at
171/// its next survival, so key-disjoint input cannot hold its backlog
172/// uncompressed indefinitely. Lowering this at runtime therefore migrates
173/// bodies that already spilled, rather than applying only to new ones.
174/// `0` compresses every spilled body.
175pub const COLUMN_CHUNK_COMPRESS_MIN_DEPTH: Config<u32> = Config::new(
176    "column_chunk_compress_min_depth",
177    1,
178    "The youngest chunk generation whose spilled bodies are lz4-compressed in the buffer \
179     pool; younger generations store uncompressed. 0 compresses every spilled body.",
180    ParameterScope::Replica,
181);
182
183/// Resident-bytes budget fraction for chunk spilling. Two consumers read
184/// it: the column pager's tiered policy multiplies it against the
185/// announced memory limit, and the buffer pool (`mz_ore::pool`)
186/// multiplies it against physical RAM, since a resident budget must
187/// derive from memory that can be resident and the announced limit
188/// includes swap on swap-provisioned nodes.
189///
190/// The default of `0.20` is the budget the chunked upsert-v2 stash ran with
191/// in production on swap-provisioned replicas. Set lower to spill more
192/// aggressively under pressure. The computed budget is floored at 128 MiB so
193/// the no-pressure case doesn't page per chunk. Ignored while every spill
194/// gate ([`ENABLE_COLUMN_PAGED_BATCHER_SPILL`], [`ENABLE_CORRECTION_V2_SPILL`],
195/// and storage's `enable_upsert_paged_spill`) is off.
196pub const COLUMN_PAGED_BATCHER_BUDGET_FRACTION: Config<f64> = Config::new(
197    "column_paged_batcher_budget_fraction",
198    0.2,
199    "Budget fraction for chunk spilling: the buffer pool multiplies it against physical \
200     RAM and the column pager's tiered policy against the announced memory limit. \
201     Total pool budget = max(ram * fraction, 128 MiB).",
202    ParameterScope::Replica,
203);
204
205/// Buffer-pool spill threads performing eviction I/O (lz4 compression plus
206/// the synchronous-reclaim `MADV_PAGEOUT`) off the threads that trip the
207/// budget, as a fraction of the process's timely workers, rounded down to a
208/// power of two (`mz_timely_util::pool_config::spill_threads_for_workers`).
209/// Any positive fraction spawns at least one thread. Zero evicts inline on the
210/// calling thread, which measurably convoys workers behind eviction I/O at
211/// hydration eviction rates.
212///
213/// The default of `0.5` gives 1 thread below 4 workers, then 2, 4, 8 and 16
214/// threads from 4, 8, 16 and 32 workers. These are the per-size counts
215/// production ran the chunked upsert-v2 stash with. Hydration sweeps on a
216/// 62-worker replica convoyed all workers at 2 and 4 threads.
217///
218/// Thread spawning is once per process: raising the value later has no effect
219/// beyond re-enabling, and lowering it to zero falls back to inline eviction
220/// while spawned threads idle.
221pub const COLUMN_PAGED_BATCHER_SPILL_WORKER_FRACTION: Config<f64> = Config::new(
222    "column_paged_batcher_spill_worker_fraction",
223    0.5,
224    "Buffer-pool spill threads for off-worker eviction I/O, as a fraction of the process's \
225     timely workers, rounded down to a power of two and at least 1; 0 evicts inline on the \
226     caller.",
227    ParameterScope::Replica,
228);
229
230/// Compress chunks the column-paged batcher spills, using lz4. Only
231/// meaningful when [`ENABLE_COLUMN_PAGED_BATCHER_SPILL`] is `true`; the codec
232/// is applied on the pageout path and reversed on page-in. Trades CPU for a
233/// smaller on-storage (and, for the swap backend, resident) footprint.
234///
235/// Off by default so the spill path's cost stays a pure copy until compression
236/// is shown to pay for itself on the target workload.
237pub const COLUMN_PAGED_BATCHER_LZ4: Config<bool> = Config::new(
238    "column_paged_batcher_lz4",
239    false,
240    "Compress column-paged batcher chunks with lz4 on the spill path. Only meaningful when \
241     `enable_column_paged_batcher_spill = true`.",
242    ParameterScope::Replica,
243);
244
245/// Proactively evict the column-paged batcher's lz4-compressed spill chunks
246/// from RSS via `MADV_PAGEOUT` when spilling to the swap backend. Only
247/// meaningful when [`COLUMN_PAGED_BATCHER_LZ4`] is `true` and the active
248/// backend is swap (no scratch directory): on that path the compressed bytes
249/// stay resident in the process address space and currently receive no madvise
250/// at all, so the kernel reclaims them only lazily under LRU pressure.
251/// `MADV_PAGEOUT` instead swaps them out eagerly at spill time, holding RSS at
252/// the budget rather than letting it drift up to the pressure cliff. A later
253/// page-in re-faults the pages — cheap because lz4 shrank the byte volume,
254/// which is what makes eager eviction pay off on this path.
255///
256/// Off by default: the eager-reclaim syscall is the one kernel interaction the
257/// pager design singled out as risky, so it stays gated until proven on the
258/// target workload.
259pub const COLUMN_PAGED_BATCHER_SWAP_PAGEOUT: Config<bool> = Config::new(
260    "column_paged_batcher_swap_pageout",
261    false,
262    "Eagerly evict the column-paged batcher's lz4-compressed swap-backend spill chunks from RSS \
263     via `MADV_PAGEOUT` (they otherwise receive no madvise and are reclaimed only lazily). Only \
264     meaningful when `column_paged_batcher_lz4 = true` and the swap backend is active.",
265    ParameterScope::Replica,
266);
267
268/// Eagerly compress unbacked buffer-pool chunks to `BackedResident` on idle
269/// spill threads (write-behind). The chunk stays readable in its slot while
270/// a compressed extent accumulates on the swap device, so budget-driven
271/// eviction becomes a pure page release instead of a compression. Trades
272/// background CPU (compression of chunks that may die before pressure
273/// reaches them) for near-free pressure response.
274pub const COLUMN_PAGED_BATCHER_EAGER_BACKING: Config<bool> = Config::new(
275    "column_paged_batcher_eager_backing",
276    false,
277    "Eagerly compress buffer-pool chunks to compressed-but-resident on idle spill threads, so \
278     budget-driven eviction is a pure page release. Only meaningful with spill workers.",
279    ParameterScope::Replica,
280);
281
282/// Ceiling on the buffer pool's total RSS, as a fraction of *physical RAM*
283/// (never the announced limit, which includes swap on swap-provisioned
284/// nodes). The compressed-but-resident extent tier is the headroom above the
285/// slot budget and warm cap: chunks evicted from the budget stay in RAM
286/// compressed (~5.6x denser; reads decompress without faulting) until this
287/// ceiling forces the oldest extents out to the swap device via
288/// `MADV_PAGEOUT`. Zero collapses the tier: extents page out as soon as
289/// they are written.
290///
291/// With the 0.20 budget default this leaves at most 5% of RAM, less the warm
292/// cap, for the compressed tier, so most budget evictions page out to the
293/// swap device promptly. Three quarters of RAM stay available for everything
294/// else in the process.
295pub const COLUMN_PAGED_BATCHER_POOL_RSS_TARGET_FRACTION: Config<f64> = Config::new(
296    "column_paged_batcher_pool_rss_target_fraction",
297    0.25,
298    "Ceiling on the buffer pool's total RSS as a fraction of physical RAM; the headroom above \
299     the slot budget holds compressed-but-resident extents. Zero pages extents out immediately.",
300    ParameterScope::Replica,
301);
302
303/// Whether rendering should use `mz_join_core` rather than DD's `JoinCore::join_core`.
304pub const ENABLE_MZ_JOIN_CORE: Config<bool> = Config::new(
305    "enable_mz_join_core",
306    true,
307    "Whether compute should use `mz_join_core` rather than DD's `JoinCore::join_core` to render \
308     linear joins.",
309    ParameterScope::Environment,
310);
311
312/// Use sync Timely operators with Tokio tasks for the MV sink.
313pub const ENABLE_SYNC_MV_SINK: Config<bool> = Config::new(
314    "enable_compute_sync_mv_sink",
315    false,
316    "Use sync Timely operators with Tokio tasks for the MV sink.",
317    ParameterScope::Environment,
318);
319
320/// The size of a worker's updates for one batch interval below which the MV sink coalesces them
321/// with the other workers in its process into a single shared batch. Past it, the worker writes
322/// its own batch. Zero disables sharing.
323pub const MV_SINK_SHARED_BATCH_MAX_BYTES: Config<usize> = Config::new(
324    "compute_mv_sink_shared_batch_max_bytes",
325    1024 * 1024,
326    "The size of a worker's updates for one batch interval below which the MV sink coalesces \
327     them into a batch shared by the workers in one process. Zero disables sharing.",
328    ParameterScope::Environment,
329);
330
331/// Whether rendering should use the new MV sink correction buffer implementation.
332pub const ENABLE_CORRECTION_V2: Config<bool> = Config::new(
333    "enable_compute_correction_v2",
334    true,
335    "Whether compute should use the new MV sink correction buffer implementation.",
336    ParameterScope::Environment,
337);
338
339/// The size factor of subsequent chains in the correction V2 buffer.
340pub const CORRECTION_V2_CHAIN_PROPORTIONALITY: Config<f64> = Config::new(
341    "compute_correction_v2_chain_proportionality",
342    3.0,
343    "The size factor of subsequent chains in the correction V2 buffer.",
344    ParameterScope::Replica,
345);
346
347/// The byte size of the correction V2 buffer's staging area.
348pub const CORRECTION_V2_CHUNK_SIZE: Config<usize> = Config::new(
349    "compute_correction_v2_chunk_size",
350    2 * 1024 * 1024,
351    "The byte size of the staging area in the correction V2 buffer, heap bytes of the staged \
352     updates included, which sets how much it accumulates before minting a chain (the name \
353     predates that meaning; chunk bodies themselves are fixed at the columnar ship size).",
354    ParameterScope::Replica,
355);
356
357/// Allow the correction V2 buffer's chunk bodies to spill to the process
358/// buffer pool under memory pressure.
359///
360/// A gate of its own, so enabling the arrange or upsert spill flags does not
361/// move the MV sinks' memory behavior. Turning it on also installs the pool,
362/// budgeted by [`COLUMN_PAGED_BATCHER_BUDGET_FRACTION`]. Takes effect for
363/// chunks minted after the next configuration tick.
364pub const ENABLE_CORRECTION_V2_SPILL: Config<bool> = Config::new(
365    "enable_compute_correction_v2_spill",
366    false,
367    "Allow the MV sink correction V2 buffer's chunk bodies to spill to the process buffer pool \
368     under memory pressure.",
369    ParameterScope::Replica,
370);
371
372/// The summary to apply to the frontier in temporal bucketing in compute.
373pub const TEMPORAL_BUCKETING_SUMMARY: Config<Duration> = Config::new(
374    "compute_temporal_bucketing_summary",
375    Duration::from_secs(2),
376    "The summary to apply to frontiers in temporal bucketing in compute.",
377    ParameterScope::Environment,
378);
379
380/// The yielding behavior with which linear joins should be rendered.
381pub const LINEAR_JOIN_YIELDING: Config<&str> = Config::new(
382    "linear_join_yielding",
383    "work:1000000,time:100",
384    "The yielding behavior compute rendering should apply for linear join operators. Either \
385     'work:<amount>' or 'time:<milliseconds>' or 'work:<amount>,time:<milliseconds>'. Note \
386     that omitting one of 'work' or 'time' will entirely disable join yielding by time or \
387     work, respectively, rather than falling back to some default.",
388    ParameterScope::Replica,
389);
390
391/// Enable lgalloc.
392pub const ENABLE_LGALLOC: Config<bool> = Config::new(
393    "enable_lgalloc",
394    true,
395    "Enable lgalloc.",
396    ParameterScope::Replica,
397);
398
399/// Enable lgalloc's eager memory return/reclamation feature.
400pub const ENABLE_LGALLOC_EAGER_RECLAMATION: Config<bool> = Config::new(
401    "enable_lgalloc_eager_reclamation",
402    true,
403    "Enable lgalloc's eager return behavior.",
404    ParameterScope::Replica,
405);
406
407/// The interval at which the background thread wakes.
408pub const LGALLOC_BACKGROUND_INTERVAL: Config<Duration> = Config::new(
409    "lgalloc_background_interval",
410    Duration::from_secs(1),
411    "Scheduling interval for lgalloc's background worker.",
412    ParameterScope::Replica,
413);
414
415/// Enable lgalloc's eager memory return/reclamation feature.
416pub const LGALLOC_FILE_GROWTH_DAMPENER: Config<usize> = Config::new(
417    "lgalloc_file_growth_dampener",
418    2,
419    "Lgalloc's file growth dampener parameter.",
420    ParameterScope::Replica,
421);
422
423/// Enable lgalloc's eager memory return/reclamation feature.
424pub const LGALLOC_LOCAL_BUFFER_BYTES: Config<usize> = Config::new(
425    "lgalloc_local_buffer_bytes",
426    64 << 20,
427    "Lgalloc's local buffer bytes parameter.",
428    ParameterScope::Replica,
429);
430
431/// The bytes to reclaim (slow path) per size class, for each background thread activation.
432pub const LGALLOC_SLOW_CLEAR_BYTES: Config<usize> = Config::new(
433    "lgalloc_slow_clear_bytes",
434    128 << 20,
435    "Clear byte size per size class for every invocation",
436    ParameterScope::Replica,
437);
438
439/// Interval to run the memory limiter. A zero duration disables the limiter.
440pub const MEMORY_LIMITER_INTERVAL: Config<Duration> = Config::new(
441    "memory_limiter_interval",
442    Duration::from_secs(10),
443    "Interval to run the memory limiter. A zero duration disables the limiter.",
444    ParameterScope::Replica,
445);
446
447/// Bias to the memory limiter usage factor.
448pub const MEMORY_LIMITER_USAGE_BIAS: Config<f64> = Config::new(
449    "memory_limiter_usage_bias",
450    1.,
451    "Multiplicative bias to the memory limiter's limit.",
452    ParameterScope::Replica,
453);
454
455/// Burst factor to memory limit.
456pub const MEMORY_LIMITER_BURST_FACTOR: Config<f64> = Config::new(
457    "memory_limiter_burst_factor",
458    0.,
459    "Multiplicative burst factor to the memory limiter's limit.",
460    ParameterScope::Replica,
461);
462
463/// Enable lgalloc for columnation.
464pub const ENABLE_COLUMNATION_LGALLOC: Config<bool> = Config::new(
465    "enable_columnation_lgalloc",
466    true,
467    "Enable allocating regions from lgalloc.",
468    ParameterScope::Replica,
469);
470
471/// The interval at which the compute server performs maintenance tasks.
472pub const COMPUTE_SERVER_MAINTENANCE_INTERVAL: Config<Duration> = Config::new(
473    "compute_server_maintenance_interval",
474    Duration::from_millis(10),
475    "The interval at which the compute server performs maintenance tasks. Zero enables maintenance on every iteration.",
476    ParameterScope::Replica,
477);
478
479/// Maximum number of in-flight bytes emitted by persist_sources feeding dataflows.
480pub const DATAFLOW_MAX_INFLIGHT_BYTES: Config<Option<usize>> = Config::new(
481    "compute_dataflow_max_inflight_bytes",
482    None,
483    "The maximum number of in-flight bytes emitted by persist_sources feeding \
484     compute dataflows in non-cc clusters.",
485    ParameterScope::Replica,
486);
487
488/// The "physical backpressure" of `compute_dataflow_max_inflight_bytes_cc` has
489/// been replaced in cc replicas by persist lgalloc and we intend to remove it
490/// once everything has switched to cc. In the meantime, this is a CYA to turn
491/// it back on if absolutely necessary.
492pub const DATAFLOW_MAX_INFLIGHT_BYTES_CC: Config<Option<usize>> = Config::new(
493    "compute_dataflow_max_inflight_bytes_cc",
494    None,
495    "The maximum number of in-flight bytes emitted by persist_sources feeding \
496     compute dataflows in cc clusters.",
497    ParameterScope::Replica,
498);
499
500/// The term `n` in the growth rate `1 + 1/(n + 1)` for `ConsolidatingVec`.
501/// The smallest value `0` corresponds to the greatest allowed growth, of doubling.
502pub const CONSOLIDATING_VEC_GROWTH_DAMPENER: Config<usize> = Config::new(
503    "consolidating_vec_growth_dampener",
504    1,
505    "Dampener in growth rate for consolidating vector size",
506    ParameterScope::Replica,
507);
508
509/// The number of dataflows that may hydrate concurrently.
510///
511/// Enforced in `environmentd`, by the controller's per-replica hydration
512/// interceptor withholding `Schedule` commands, rather than by the replica. The
513/// interceptor resolves it from the configuration commands it observes, which
514/// are already specialized for its replica, so the limit still follows the
515/// replica's scoped override.
516pub const HYDRATION_CONCURRENCY: Config<usize> = Config::new(
517    "compute_hydration_concurrency",
518    4,
519    "Controls how many compute dataflows may hydrate concurrently.",
520    ParameterScope::Replica,
521);
522
523/// See `src/storage-operators/src/s3_oneshot_sink/parquet.rs` for more details.
524pub const COPY_TO_S3_PARQUET_ROW_GROUP_FILE_RATIO: Config<usize> = Config::new(
525    "copy_to_s3_parquet_row_group_file_ratio",
526    20,
527    "The ratio (defined as a percentage) of row-group size to max-file-size. \
528        Must be <= 100.",
529    ParameterScope::Environment,
530);
531
532/// See `src/storage-operators/src/s3_oneshot_sink/parquet.rs` for more details.
533pub const COPY_TO_S3_ARROW_BUILDER_BUFFER_RATIO: Config<usize> = Config::new(
534    "copy_to_s3_arrow_builder_buffer_ratio",
535    150,
536    "The ratio (defined as a percentage) of arrow-builder size to row-group size. \
537        Must be >= 100.",
538    ParameterScope::Environment,
539);
540
541/// The size of each part in the multi-part upload to use when uploading files to S3.
542pub const COPY_TO_S3_MULTIPART_PART_SIZE_BYTES: Config<usize> = Config::new(
543    "copy_to_s3_multipart_part_size_bytes",
544    1024 * 1024 * 8,
545    "The size of each part in a multipart upload to S3.",
546    ParameterScope::Environment,
547);
548
549/// Main switch to enable or disable replica expiration.
550///
551/// Changes affect existing replicas only after restart.
552///
553/// The env-wide kill switch for the feature, read in `environmentd` when
554/// specializing `CreateInstance` for a replica. [`COMPUTE_REPLICA_EXPIRATION_OFFSET`]
555/// is the replica-scoped half of the pair.
556pub const ENABLE_COMPUTE_REPLICA_EXPIRATION: Config<bool> = Config::new(
557    "enable_compute_replica_expiration",
558    true,
559    "Main switch to disable replica expiration.",
560    ParameterScope::Environment,
561);
562
563/// The maximum lifetime of a replica configured as an offset to the replica start time.
564/// Used in temporal filters to drop diffs generated at timestamps beyond the expiration time.
565///
566/// A zero duration implies no expiration. Changing this value does not affect existing replicas,
567/// even when they are restarted.
568pub const COMPUTE_REPLICA_EXPIRATION_OFFSET: Config<Duration> = Config::new(
569    "compute_replica_expiration_offset",
570    Duration::ZERO,
571    "The expiration time offset for replicas. Zero disables expiration.",
572    ParameterScope::Replica,
573);
574
575/// When enabled, applies the column demands from a MapFilterProject onto the RelationDesc used to
576/// read out of Persist. This allows Persist to prune unneeded columns as a performance
577/// optimization.
578pub const COMPUTE_APPLY_COLUMN_DEMANDS: Config<bool> = Config::new(
579    "compute_apply_column_demands",
580    true,
581    "When enabled, passes applys column demands to the RelationDesc used to read out of Persist.",
582    ParameterScope::Environment,
583);
584
585/// The amount of output the flat-map operator produces before yielding. Set to a high value to
586/// avoid yielding, or to a low value to yield frequently.
587pub const COMPUTE_FLAT_MAP_FUEL: Config<usize> = Config::new(
588    "compute_flat_map_fuel",
589    1_000_000,
590    "The amount of output the flat-map operator produces before yielding.",
591    ParameterScope::Replica,
592);
593
594/// Whether to apply logical backpressure in compute dataflows.
595pub const ENABLE_COMPUTE_LOGICAL_BACKPRESSURE: Config<bool> = Config::new(
596    "enable_compute_logical_backpressure",
597    false,
598    "When enabled, compute dataflows will apply logical backpressure.",
599    ParameterScope::Replica,
600);
601
602/// Maximal number of capabilities retained by the logical backpressure operator.
603///
604/// Selecting this value is subtle. If it's too small, it'll diminish the effectiveness of the
605/// logical backpressure operators. If it's too big, we can slow down hydration and cause state
606/// in the operator's implementation to build up.
607///
608/// The default value represents a compromise between these two extremes. We retain some metrics
609/// for 30 days, and the metrics update every minute. The default is exactly this number.
610pub const COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES: Config<Option<usize>> =
611    Config::new(
612        "compute_logical_backpressure_max_retained_capabilities",
613        Some(30 * 24 * 60),
614        "The maximum number of capabilities retained by the logical backpressure operator.",
615        ParameterScope::Replica,
616    );
617
618/// The slack to round observed timestamps up to.
619///
620/// The default corresponds to Mz's default tick interval, but does not need to do so. Ideally,
621/// it is not smaller than the tick interval, but it can be larger.
622pub const COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK: Config<Duration> = Config::new(
623    "compute_logical_backpressure_inflight_slack",
624    Duration::from_secs(1),
625    "Round observed timestamps to slack.",
626    ParameterScope::Replica,
627);
628
629/// Enable per-column dictionary compression for row containers in arrangements.
630///
631/// The `_alpha` suffix is load-bearing: this feature is not yet considered
632/// production-ready, and the name is meant to make that unmissable at the
633/// `ALTER SYSTEM SET` call site rather than relying on out-of-band warnings.
634///
635/// Disposition: added 2026-06-09; solicit feedback for one month and remove in
636/// the absence of a positive response.
637pub const ENABLE_ARRANGEMENT_DICTIONARY_COMPRESSION_ALPHA: Config<bool> = Config::new(
638    "enable_arrangement_dictionary_compression_alpha",
639    true,
640    "Enable arrangement dictionary compression (alpha; not yet production-ready).",
641    ParameterScope::Replica,
642);
643
644/// Whether to enable the peek response stash, for sending back large peek
645/// responses. The response stash will only be used for results that exceed
646/// `compute_peek_response_stash_threshold_bytes`.
647pub const ENABLE_PEEK_RESPONSE_STASH: Config<bool> = Config::new(
648    "enable_compute_peek_response_stash",
649    true,
650    "Whether to enable the peek response stash, for sending back large peek responses. Will only be used for results that exceed compute_peek_response_stash_threshold_bytes.",
651    ParameterScope::Environment,
652);
653
654/// The threshold for peek response size above which we should use the peek
655/// response stash. Only used if the peek response stash is enabled _and_ if the
656/// query is "streamable" (roughly: doesn't have an ORDER BY).
657pub const PEEK_RESPONSE_STASH_THRESHOLD_BYTES: Config<usize> = Config::new(
658    "compute_peek_response_stash_threshold_bytes",
659    1024 * 10, /* 10KB */
660    "The threshold above which to use the peek response stash, for sending back large peek responses.",
661    ParameterScope::Environment,
662);
663
664/// The size at which a peek bound for the stash hands its accumulated rows to the upload, once
665/// the first batch at [`PEEK_RESPONSE_STASH_THRESHOLD_BYTES`] has decided that the answer is not
666/// an inline one.
667///
668/// Kept apart from the threshold because they answer different questions: the threshold sizes
669/// what an inline answer may hold, this sizes one hand-over. Each hand-over costs a round trip
670/// through the blocking pool, and a scan retains up to this much between them.
671pub const PEEK_RESPONSE_STASH_BATCH_BYTES: Config<usize> = Config::new(
672    "compute_peek_response_stash_batch_bytes",
673    1024 * 1024,
674    "The size in bytes at which a peek bound for the peek response stash hands its rows to the upload, after the first batch at the stash threshold.",
675    ParameterScope::Replica,
676);
677
678/// The target number of maximum runs in the batches written to the stash.
679///
680/// Setting this reasonably low will make it so batches get consolidated/sorted
681/// concurrently with data being written. Which will in turn make it so that we
682/// have to do less work when reading/consolidating those batches in
683/// `environmentd`.
684pub const PEEK_RESPONSE_STASH_BATCH_MAX_RUNS: Config<usize> = Config::new(
685    "compute_peek_response_stash_batch_max_runs",
686    // The lowest possible setting, do as much work as possible on the
687    // `clusterd` side.
688    2,
689    "The target number of maximum runs in the batches written to the stash.",
690    ParameterScope::Environment,
691);
692
693/// The target size for batches of rows we read out of the peek stash.
694pub const PEEK_RESPONSE_STASH_READ_BATCH_SIZE_BYTES: Config<usize> = Config::new(
695    "compute_peek_response_stash_read_batch_size_bytes",
696    1024 * 1024 * 100, /* 100mb */
697    "The target size for batches of rows we read out of the peek stash.",
698    ParameterScope::Environment,
699);
700
701/// The memory budget for consolidating stashed peek responses in
702/// `environmentd`.
703pub const PEEK_RESPONSE_STASH_READ_MEMORY_BUDGET_BYTES: Config<usize> = Config::new(
704    "compute_peek_response_stash_read_memory_budget_bytes",
705    1024 * 1024 * 64, /* 64mb */
706    "The memory budget for consolidating stashed peek responses in environmentd.",
707    ParameterScope::Environment,
708);
709
710/// Whether compute should stop peeks that iterate over too many rows.
711pub const ENABLE_PEEK_ROW_ITERATION_LIMIT: Config<bool> = Config::new(
712    "enable_compute_peek_row_iteration_limit",
713    false,
714    "Whether compute should stop peeks that exceed compute_peek_row_iteration_limit.",
715    ParameterScope::Environment,
716);
717
718/// The maximum number of rows a peek may iterate over on each worker.
719///
720/// The count spans a peek's whole walk of its arrangement, rows written to the peek stash
721/// included, because a peek walks its arrangement once and the count travels with that walk.
722pub const PEEK_ROW_ITERATION_LIMIT: Config<usize> = Config::new(
723    "compute_peek_row_iteration_limit",
724    1000,
725    "The maximum number of rows a peek may iterate over on each worker when enable_compute_peek_row_iteration_limit is enabled. The count spans the peek's whole walk, rows written to the peek stash included.",
726    ParameterScope::Environment,
727);
728
729/// Whether a fast-path index peek may move its walk off the timely worker for latency.
730///
731/// Off, a peek walks on the worker that owns it until it answers, delaying every other message
732/// that worker serves. On, a peek that outruns [`INDEX_PEEK_INLINE_BUDGET`] finishes away from it.
733///
734/// This gates latency offload only. A peek whose rows outgrow an inline answer is offloaded either
735/// way, because the driver that writes to the peek stash is the offloaded one. Off means an ordinary
736/// peek runs where it used to, not that none leaves the worker.
737pub const ENABLE_INDEX_PEEK_OFFLOAD: Config<bool> = Config::new(
738    "enable_compute_index_peek_offload",
739    true,
740    "Whether a fast-path index peek may move its walk off the timely worker.",
741    ParameterScope::Replica,
742);
743
744/// How far one peek may walk on the worker before it is offloaded, in consumed cursor positions.
745///
746/// A peek that exceeds it has been measured expensive, not predicted to be, so a point lookup over
747/// a skewed hot key offloads without a special case.
748///
749/// Counted in cursor positions, not rows returned: the result iterator steps the cursor without
750/// returning anything whenever the MFP rejects a row, so a selective filter over a large
751/// arrangement would never spend a row-counted budget. No wall-clock component, since under memory
752/// pressure a time bound anti-correlates with progress, one major fault consuming a whole slice.
753///
754/// Zero walks one position, not none: a peek granted no fuel would suspend having walked nowhere
755/// and be offloaded for it.
756pub const INDEX_PEEK_INLINE_BUDGET: Config<usize> = Config::new(
757    "compute_index_peek_inline_budget",
758    1024,
759    "How far one index peek may walk on the timely worker, in consumed cursor positions, before it is offloaded.",
760    ParameterScope::Replica,
761);
762
763/// What all peeks together may spend in one worker activation, in consumed cursor positions.
764///
765/// Every activation visits every pending peek, so a per-peek budget with no aggregate lets N
766/// pending peeks cost N times [`INDEX_PEEK_INLINE_BUDGET`] in one pass, unbounded in N. Peeks that
767/// get no turn are served first on the next activation.
768///
769/// Raising the ratio to the inline budget drains a burst in fewer activations, lowering it caps
770/// how long one activation withholds the worker.
771pub const INDEX_PEEK_ACTIVATION_BUDGET: Config<usize> = Config::new(
772    "compute_index_peek_activation_budget",
773    8 * 1024,
774    "What all index peeks together may spend in one timely worker activation, in consumed cursor positions.",
775    ParameterScope::Replica,
776);
777
778/// How often an offloaded scan checks for cancellation and re-reads its configuration, in
779/// consumed cursor positions.
780///
781/// At a plausible 100ns to 1us per position this bounds cancellation latency to single-digit
782/// milliseconds. Larger than [`INDEX_PEEK_INLINE_BUDGET`] because an offloaded scan is off the
783/// worker's critical path, so its slices answer to cancellation latency, not to the worker's
784/// availability. A check is a few loads and no hand-off, so a finer granularity costs little.
785///
786/// An upper bound, not a period: a walk bound for the peek stash suspends once its accumulation
787/// crosses `peek_response_stash_threshold_bytes`, by far the smaller trigger at that threshold's
788/// default, and unspent fuel is not carried over.
789pub const INDEX_PEEK_YIELD_GRANULARITY: Config<usize> = Config::new(
790    "compute_index_peek_yield_granularity",
791    10000,
792    "How often an offloaded index peek scan checks for cancellation, in consumed cursor positions.",
793    ParameterScope::Replica,
794);
795
796/// How many offloaded index peek scans may run at once, as a fraction of the timely workers a
797/// compute runtime runs.
798///
799/// A fraction so the bound scales with the replica instead of being retuned per size. `1.0` admits
800/// one scan per worker, `0.5` one per two workers, and the bound is never below one scan.
801///
802/// The default admits four per worker because a scan holds its permit while it waits on its
803/// peek-stash upload, which is I/O rather than CPU. At one per worker, stash-heavy replicas queued
804/// scans behind uploads. At four per worker the wait disappeared with no increase in timely step
805/// duration.
806///
807/// Per compute runtime, not global: a process running a maintenance and an interactive runtime
808/// admits it once per runtime.
809///
810/// This bounds running scans only. Scans that do not fit queue, costing a queue entry holding a
811/// suspended scan instead of a thread. Queue depth is a signal to alert on, not a second bound,
812/// since capping it would mean failing peeks.
813pub const INDEX_PEEK_PERMIT_FRACTION: Config<f64> = Config::new(
814    "compute_index_peek_permit_fraction",
815    4.0,
816    "How many offloaded index peek scans may run at once in one compute runtime, as a fraction of \
817     the timely workers it runs. Never below one scan.",
818    ParameterScope::Replica,
819);
820
821/// The collection interval for the Prometheus metrics introspection source.
822///
823/// Set to zero to disable scraping and retract any existing data.
824pub const COMPUTE_PROMETHEUS_INTROSPECTION_SCRAPE_INTERVAL: Config<Duration> = Config::new(
825    "compute_prometheus_introspection_scrape_interval",
826    Duration::from_secs(10),
827    "The collection interval for the Prometheus metrics introspection source. Set to zero to disable.",
828    ParameterScope::Replica,
829);
830
831/// If set, skip fetching or processing the snapshot data for subscribes when possible.
832///
833/// Read twice. At plan time in `environmentd` it gates whether snapshot elision runs at all, and
834/// at render time on the replica it gates whether an elided snapshot is honored. The replica-side
835/// read only ever puts a snapshot back, never takes one away, so the two reads disagreeing costs
836/// work rather than correctness.
837///
838/// Environment-scoped because the plan-time read has no replica in scope. Making it
839/// cluster-coherent instead would need plan-time resolution of cluster overrides for
840/// `OptimizerConfig` fields that are not `OptimizerFeatures`, which is the only place cluster
841/// overrides are resolved today.
842pub const SUBSCRIBE_SNAPSHOT_OPTIMIZATION: Config<bool> = Config::new(
843    "compute_subscribe_snapshot_optimization",
844    true,
845    "If set, skip fetching or processing the snapshot data for subscribes when possible.",
846    ParameterScope::Environment,
847);
848
849/// Temporary flag to de-risk the rollout of a release-blocker fix.
850///
851/// TODO: Remove after one, or a couple, releases.
852pub const MV_SINK_ADVANCE_PERSIST_FRONTIERS: Config<bool> = Config::new(
853    "compute_mv_sink_advance_persist_frontiers",
854    true,
855    "Whether the MV sink's write operator advances its internal persist frontiers to the as_of.",
856    ParameterScope::Environment,
857);
858
859/// Adds the full set of all compute `Config`s.
860pub fn all_dyncfgs(configs: ConfigSet) -> ConfigSet {
861    configs
862        .add(&ENABLE_ERROR_DISTINCT)
863        .add(&ENABLE_MZ_JOIN_CORE)
864        .add(&ENABLE_SYNC_MV_SINK)
865        .add(&MV_SINK_SHARED_BATCH_MAX_BYTES)
866        .add(&ENABLE_CORRECTION_V2)
867        .add(&CORRECTION_V2_CHAIN_PROPORTIONALITY)
868        .add(&CORRECTION_V2_CHUNK_SIZE)
869        .add(&ENABLE_CORRECTION_V2_SPILL)
870        .add(&TEMPORAL_BUCKETING_SUMMARY)
871        .add(&LINEAR_JOIN_YIELDING)
872        .add(&ENABLE_LGALLOC)
873        .add(&LGALLOC_BACKGROUND_INTERVAL)
874        .add(&LGALLOC_FILE_GROWTH_DAMPENER)
875        .add(&LGALLOC_LOCAL_BUFFER_BYTES)
876        .add(&LGALLOC_SLOW_CLEAR_BYTES)
877        .add(&MEMORY_LIMITER_INTERVAL)
878        .add(&MEMORY_LIMITER_USAGE_BIAS)
879        .add(&MEMORY_LIMITER_BURST_FACTOR)
880        .add(&ENABLE_LGALLOC_EAGER_RECLAMATION)
881        .add(&ENABLE_COLUMNATION_LGALLOC)
882        .add(&COMPUTE_SERVER_MAINTENANCE_INTERVAL)
883        .add(&DATAFLOW_MAX_INFLIGHT_BYTES)
884        .add(&DATAFLOW_MAX_INFLIGHT_BYTES_CC)
885        .add(&HYDRATION_CONCURRENCY)
886        .add(&COPY_TO_S3_PARQUET_ROW_GROUP_FILE_RATIO)
887        .add(&COPY_TO_S3_ARROW_BUILDER_BUFFER_RATIO)
888        .add(&COPY_TO_S3_MULTIPART_PART_SIZE_BYTES)
889        .add(&ENABLE_COMPUTE_REPLICA_EXPIRATION)
890        .add(&COMPUTE_REPLICA_EXPIRATION_OFFSET)
891        .add(&COMPUTE_APPLY_COLUMN_DEMANDS)
892        .add(&COMPUTE_FLAT_MAP_FUEL)
893        .add(&CONSOLIDATING_VEC_GROWTH_DAMPENER)
894        .add(&ENABLE_COMPUTE_LOGICAL_BACKPRESSURE)
895        .add(&COMPUTE_LOGICAL_BACKPRESSURE_MAX_RETAINED_CAPABILITIES)
896        .add(&COMPUTE_LOGICAL_BACKPRESSURE_INFLIGHT_SLACK)
897        .add(&ENABLE_ARRANGEMENT_DICTIONARY_COMPRESSION_ALPHA)
898        .add(&ENABLE_PEEK_RESPONSE_STASH)
899        .add(&PEEK_RESPONSE_STASH_THRESHOLD_BYTES)
900        .add(&PEEK_RESPONSE_STASH_BATCH_BYTES)
901        .add(&PEEK_RESPONSE_STASH_BATCH_MAX_RUNS)
902        .add(&PEEK_RESPONSE_STASH_READ_BATCH_SIZE_BYTES)
903        .add(&PEEK_RESPONSE_STASH_READ_MEMORY_BUDGET_BYTES)
904        .add(&ENABLE_PEEK_ROW_ITERATION_LIMIT)
905        .add(&PEEK_ROW_ITERATION_LIMIT)
906        .add(&ENABLE_INDEX_PEEK_OFFLOAD)
907        .add(&INDEX_PEEK_INLINE_BUDGET)
908        .add(&INDEX_PEEK_ACTIVATION_BUDGET)
909        .add(&INDEX_PEEK_YIELD_GRANULARITY)
910        .add(&INDEX_PEEK_PERMIT_FRACTION)
911        .add(&COMPUTE_PROMETHEUS_INTROSPECTION_SCRAPE_INTERVAL)
912        .add(&SUBSCRIBE_SNAPSHOT_OPTIMIZATION)
913        .add(&MV_SINK_ADVANCE_PERSIST_FRONTIERS)
914        .add(&ENABLE_COLUMN_PAGED_BATCHER)
915        .add(&ENABLE_COLUMNAR_MERGE_BATCHER)
916        .add(&ENABLE_COLUMNAR_ACCUMULABLE_DIFF)
917        .add(&ENABLE_COLUMN_PAGED_BATCHER_SPILL)
918        .add(&ENABLE_COLUMN_PAGED_BATCHER_FILE_EXTENTS)
919        .add(&COLUMN_PAGED_BATCHER_FILE_RELEASE_INTERVAL)
920        .add(&COLUMN_PAGED_BATCHER_FILE_RELEASE_BYTES)
921        .add(&COLUMN_PAGED_BATCHER_BUDGET_FRACTION)
922        .add(&COLUMN_PAGED_BATCHER_LZ4)
923        .add(&COLUMN_PAGED_BATCHER_SWAP_PAGEOUT)
924        .add(&COLUMN_PAGED_BATCHER_SPILL_WORKER_FRACTION)
925        .add(&COLUMN_PAGED_BATCHER_EAGER_BACKING)
926        .add(&COLUMN_PAGED_BATCHER_POOL_RSS_TARGET_FRACTION)
927        .add(&COLUMN_CHUNK_COMPRESS_MIN_DEPTH)
928}