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