risingwave_common/
config.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module defines the structure of the configuration file `risingwave.toml`.
16//!
17//! [`RwConfig`] corresponds to the whole config file and each other config struct corresponds to a
18//! section in `risingwave.toml`.
19
20use std::collections::BTreeMap;
21use std::fs;
22use std::num::NonZeroUsize;
23
24use anyhow::Context;
25use clap::ValueEnum;
26use educe::Educe;
27use foyer::{
28    Compression, LfuConfig, LruConfig, RecoverMode, RuntimeOptions, S3FifoConfig, Throttle,
29};
30use risingwave_common_proc_macro::ConfigDoc;
31pub use risingwave_common_proc_macro::OverrideConfig;
32use risingwave_pb::meta::SystemParams;
33use serde::{Deserialize, Serialize, Serializer};
34use serde_default::DefaultFromSerde;
35use serde_json::Value;
36
37use crate::for_all_params;
38
39/// Use the maximum value for HTTP/2 connection window size to avoid deadlock among multiplexed
40/// streams on the same connection.
41pub const MAX_CONNECTION_WINDOW_SIZE: u32 = (1 << 31) - 1;
42/// Use a large value for HTTP/2 stream window size to improve the performance of remote exchange,
43/// as we don't rely on this for back-pressure.
44pub const STREAM_WINDOW_SIZE: u32 = 32 * 1024 * 1024; // 32 MB
45
46/// Unrecognized fields in a config section. Generic over the config section type to provide better
47/// error messages.
48///
49/// The current implementation will log warnings if there are unrecognized fields.
50#[derive(Educe)]
51#[educe(Clone, Default)]
52pub struct Unrecognized<T: 'static> {
53    inner: BTreeMap<String, Value>,
54    _marker: std::marker::PhantomData<&'static T>,
55}
56
57impl<T> std::fmt::Debug for Unrecognized<T> {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        self.inner.fmt(f)
60    }
61}
62
63impl<T> Unrecognized<T> {
64    /// Returns all unrecognized fields as a map.
65    pub fn into_inner(self) -> BTreeMap<String, Value> {
66        self.inner
67    }
68}
69
70impl<'de, T> Deserialize<'de> for Unrecognized<T> {
71    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72    where
73        D: serde::Deserializer<'de>,
74    {
75        let inner = BTreeMap::deserialize(deserializer)?;
76        if !inner.is_empty() {
77            tracing::warn!(
78                "unrecognized fields in `{}`: {:?}",
79                std::any::type_name::<T>(),
80                inner.keys()
81            );
82        }
83        Ok(Unrecognized {
84            inner,
85            _marker: std::marker::PhantomData,
86        })
87    }
88}
89
90impl<T> Serialize for Unrecognized<T> {
91    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92    where
93        S: serde::Serializer,
94    {
95        self.inner.serialize(serializer)
96    }
97}
98
99pub fn load_config(path: &str, cli_override: impl OverrideConfig) -> RwConfig
100where
101{
102    let mut config = if path.is_empty() {
103        tracing::warn!("risingwave.toml not found, using default config.");
104        RwConfig::default()
105    } else {
106        let config_str = fs::read_to_string(path)
107            .with_context(|| format!("failed to open config file at `{path}`"))
108            .unwrap();
109        toml::from_str(config_str.as_str())
110            .context("failed to parse config file")
111            .unwrap()
112    };
113    cli_override.r#override(&mut config);
114    config
115}
116
117pub trait OverrideConfig {
118    fn r#override(&self, config: &mut RwConfig);
119}
120
121impl<T: OverrideConfig> OverrideConfig for &T {
122    fn r#override(&self, config: &mut RwConfig) {
123        T::r#override(self, config)
124    }
125}
126
127/// For non-user-facing components where the CLI arguments do not override the config file.
128#[derive(Clone, Copy)]
129pub struct NoOverride;
130
131impl OverrideConfig for NoOverride {
132    fn r#override(&self, _config: &mut RwConfig) {}
133}
134
135/// [`RwConfig`] corresponds to the whole config file `risingwave.toml`. Each field corresponds to a
136/// section.
137#[derive(Educe, Clone, Serialize, Deserialize, Default, ConfigDoc)]
138#[educe(Debug)]
139pub struct RwConfig {
140    #[serde(default)]
141    #[config_doc(nested)]
142    pub server: ServerConfig,
143
144    #[serde(default)]
145    #[config_doc(nested)]
146    pub meta: MetaConfig,
147
148    #[serde(default)]
149    #[config_doc(nested)]
150    pub batch: BatchConfig,
151
152    #[serde(default)]
153    #[config_doc(nested)]
154    pub frontend: FrontendConfig,
155
156    #[serde(default)]
157    #[config_doc(nested)]
158    pub streaming: StreamingConfig,
159
160    #[serde(default)]
161    #[config_doc(nested)]
162    pub storage: StorageConfig,
163
164    #[serde(default)]
165    #[educe(Debug(ignore))]
166    #[config_doc(nested)]
167    pub system: SystemConfig,
168
169    #[serde(default)]
170    #[config_doc(nested)]
171    pub udf: UdfConfig,
172
173    #[serde(flatten)]
174    #[config_doc(omitted)]
175    pub unrecognized: Unrecognized<Self>,
176}
177
178serde_with::with_prefix!(meta_prefix "meta_");
179serde_with::with_prefix!(streaming_prefix "stream_");
180serde_with::with_prefix!(batch_prefix "batch_");
181
182#[derive(Copy, Clone, Debug, Default, ValueEnum, Serialize, Deserialize)]
183pub enum MetaBackend {
184    #[default]
185    Mem,
186    Sql, // any database url
187    Sqlite,
188    Postgres,
189    Mysql,
190}
191
192/// The section `[meta]` in `risingwave.toml`.
193#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
194pub struct MetaConfig {
195    /// Objects within `min_sst_retention_time_sec` won't be deleted by hummock full GC, even they
196    /// are dangling.
197    #[serde(default = "default::meta::min_sst_retention_time_sec")]
198    pub min_sst_retention_time_sec: u64,
199
200    /// Interval of automatic hummock full GC.
201    #[serde(default = "default::meta::full_gc_interval_sec")]
202    pub full_gc_interval_sec: u64,
203
204    /// Max number of object per full GC job can fetch.
205    #[serde(default = "default::meta::full_gc_object_limit")]
206    pub full_gc_object_limit: u64,
207
208    /// Duration in seconds to retain garbage collection history data.
209    #[serde(default = "default::meta::gc_history_retention_time_sec")]
210    pub gc_history_retention_time_sec: u64,
211
212    /// Max number of inflight time travel query.
213    #[serde(default = "default::meta::max_inflight_time_travel_query")]
214    pub max_inflight_time_travel_query: u64,
215
216    /// Schedule compaction for all compaction groups with this interval.
217    #[serde(default = "default::meta::periodic_compaction_interval_sec")]
218    pub periodic_compaction_interval_sec: u64,
219
220    /// Interval of invoking a vacuum job, to remove stale metadata from meta store and objects
221    /// from object store.
222    #[serde(default = "default::meta::vacuum_interval_sec")]
223    pub vacuum_interval_sec: u64,
224
225    /// The spin interval inside a vacuum job. It avoids the vacuum job monopolizing resources of
226    /// meta node.
227    #[serde(default = "default::meta::vacuum_spin_interval_ms")]
228    pub vacuum_spin_interval_ms: u64,
229
230    /// Interval of hummock version checkpoint.
231    #[serde(default = "default::meta::hummock_version_checkpoint_interval_sec")]
232    pub hummock_version_checkpoint_interval_sec: u64,
233
234    /// If enabled, `SSTable` object file and version delta will be retained.
235    ///
236    /// `SSTable` object file need to be deleted via full GC.
237    ///
238    /// version delta need to be manually deleted.
239    #[serde(default = "default::meta::enable_hummock_data_archive")]
240    pub enable_hummock_data_archive: bool,
241
242    /// The interval at which a Hummock version snapshot is taken for time travel.
243    ///
244    /// Larger value indicates less storage overhead but worse query performance.
245    #[serde(default = "default::meta::hummock_time_travel_snapshot_interval")]
246    pub hummock_time_travel_snapshot_interval: u64,
247
248    /// The minimum delta log number a new checkpoint should compact, otherwise the checkpoint
249    /// attempt is rejected.
250    #[serde(default = "default::meta::min_delta_log_num_for_hummock_version_checkpoint")]
251    pub min_delta_log_num_for_hummock_version_checkpoint: u64,
252
253    /// Maximum allowed heartbeat interval in seconds.
254    #[serde(default = "default::meta::max_heartbeat_interval_sec")]
255    pub max_heartbeat_interval_secs: u32,
256
257    /// Whether to enable fail-on-recovery. Should only be used in e2e tests.
258    #[serde(default)]
259    pub disable_recovery: bool,
260
261    /// Whether to disable adaptive-scaling feature.
262    #[serde(default)]
263    pub disable_automatic_parallelism_control: bool,
264
265    /// The number of streaming jobs per scaling operation.
266    #[serde(default = "default::meta::parallelism_control_batch_size")]
267    pub parallelism_control_batch_size: usize,
268
269    /// The period of parallelism control trigger.
270    #[serde(default = "default::meta::parallelism_control_trigger_period_sec")]
271    pub parallelism_control_trigger_period_sec: u64,
272
273    /// The first delay of parallelism control.
274    #[serde(default = "default::meta::parallelism_control_trigger_first_delay_sec")]
275    pub parallelism_control_trigger_first_delay_sec: u64,
276
277    #[serde(default = "default::meta::meta_leader_lease_secs")]
278    pub meta_leader_lease_secs: u64,
279
280    /// After specified seconds of idle (no mview or flush), the process will be exited.
281    /// It is mainly useful for playgrounds.
282    #[serde(default)]
283    pub dangerous_max_idle_secs: Option<u64>,
284
285    /// The default global parallelism for all streaming jobs, if user doesn't specify the
286    /// parallelism, this value will be used. `FULL` means use all available parallelism units,
287    /// otherwise it's a number.
288    #[serde(default = "default::meta::default_parallelism")]
289    pub default_parallelism: DefaultParallelism,
290
291    /// Whether to enable deterministic compaction scheduling, which
292    /// will disable all auto scheduling of compaction tasks.
293    /// Should only be used in e2e tests.
294    #[serde(default)]
295    pub enable_compaction_deterministic: bool,
296
297    /// Enable sanity check when SSTs are committed.
298    #[serde(default)]
299    pub enable_committed_sst_sanity_check: bool,
300
301    #[serde(default = "default::meta::node_num_monitor_interval_sec")]
302    pub node_num_monitor_interval_sec: u64,
303
304    #[serde(default = "default::meta::backend")]
305    pub backend: MetaBackend,
306
307    /// Schedule `space_reclaim` compaction for all compaction groups with this interval.
308    #[serde(default = "default::meta::periodic_space_reclaim_compaction_interval_sec")]
309    pub periodic_space_reclaim_compaction_interval_sec: u64,
310
311    /// Schedule `ttl_reclaim` compaction for all compaction groups with this interval.
312    #[serde(default = "default::meta::periodic_ttl_reclaim_compaction_interval_sec")]
313    pub periodic_ttl_reclaim_compaction_interval_sec: u64,
314
315    #[serde(default = "default::meta::periodic_tombstone_reclaim_compaction_interval_sec")]
316    pub periodic_tombstone_reclaim_compaction_interval_sec: u64,
317
318    #[serde(default = "default::meta::move_table_size_limit")]
319    #[deprecated]
320    pub move_table_size_limit: u64,
321
322    #[serde(default = "default::meta::split_group_size_limit")]
323    #[deprecated]
324    pub split_group_size_limit: u64,
325
326    #[serde(default = "default::meta::cut_table_size_limit")]
327    #[deprecated]
328    pub cut_table_size_limit: u64,
329
330    #[serde(default, flatten)]
331    #[config_doc(omitted)]
332    pub unrecognized: Unrecognized<Self>,
333
334    /// Whether config object storage bucket lifecycle to purge stale data.
335    #[serde(default)]
336    pub do_not_config_object_storage_lifecycle: bool,
337
338    /// Count of partition in split group. Meta will assign this value to every new group when it splits from default-group by automatically.
339    /// Each partition contains aligned data of `vnode_count / partition_vnode_count` consecutive virtual-nodes of one state table.
340    #[serde(default = "default::meta::partition_vnode_count")]
341    pub partition_vnode_count: u32,
342
343    /// The threshold of write throughput to trigger a group split.
344    #[serde(
345        default = "default::meta::table_high_write_throughput_threshold",
346        alias = "table_write_throughput_threshold"
347    )]
348    pub table_high_write_throughput_threshold: u64,
349
350    #[serde(
351        default = "default::meta::table_low_write_throughput_threshold",
352        alias = "min_table_split_write_throughput"
353    )]
354    /// The threshold of write throughput to trigger a group merge.
355    pub table_low_write_throughput_threshold: u64,
356
357    // If the compaction task does not report heartbeat beyond the
358    // `compaction_task_max_heartbeat_interval_secs` interval, we will cancel the task
359    #[serde(default = "default::meta::compaction_task_max_heartbeat_interval_secs")]
360    pub compaction_task_max_heartbeat_interval_secs: u64,
361
362    // If the compaction task does not change in progress beyond the
363    // `compaction_task_max_heartbeat_interval_secs` interval, we will cancel the task
364    #[serde(default = "default::meta::compaction_task_max_progress_interval_secs")]
365    pub compaction_task_max_progress_interval_secs: u64,
366
367    #[serde(default)]
368    #[config_doc(nested)]
369    pub compaction_config: CompactionConfig,
370
371    /// Count of partitions of tables in default group and materialized view group.
372    /// The meta node will decide according to some strategy whether to cut the boundaries of the file according to the vnode alignment.
373    /// Each partition contains aligned data of `vnode_count / hybrid_partition_vnode_count` consecutive virtual-nodes of one state table.
374    /// Set it zero to disable this feature.
375    #[serde(default = "default::meta::hybrid_partition_vnode_count")]
376    pub hybrid_partition_vnode_count: u32,
377
378    #[serde(default = "default::meta::event_log_enabled")]
379    pub event_log_enabled: bool,
380    /// Keeps the latest N events per channel.
381    #[serde(default = "default::meta::event_log_channel_max_size")]
382    pub event_log_channel_max_size: u32,
383
384    #[serde(default, with = "meta_prefix")]
385    #[config_doc(omitted)]
386    pub developer: MetaDeveloperConfig,
387    /// Whether compactor should rewrite row to remove dropped column.
388    #[serde(default = "default::meta::enable_dropped_column_reclaim")]
389    pub enable_dropped_column_reclaim: bool,
390
391    /// Whether to split the compaction group when the size of the group exceeds the `compaction_group_config.max_estimated_group_size() * split_group_size_ratio`.
392    #[serde(default = "default::meta::split_group_size_ratio")]
393    pub split_group_size_ratio: f64,
394
395    // During group scheduling, the configured `*_throughput_ratio` is used to determine if the sample exceeds the threshold.
396    // Use `table_stat_throuput_window_seconds_for_*` to check if the split and merge conditions are met.
397    /// To split the compaction group when the high throughput statistics of the group exceeds the threshold.
398    #[serde(default = "default::meta::table_stat_high_write_throughput_ratio_for_split")]
399    pub table_stat_high_write_throughput_ratio_for_split: f64,
400
401    /// To merge the compaction group when the low throughput statistics of the group exceeds the threshold.
402    #[serde(default = "default::meta::table_stat_low_write_throughput_ratio_for_merge")]
403    pub table_stat_low_write_throughput_ratio_for_merge: f64,
404
405    // Hummock also control the size of samples to be judged during group scheduling by `table_stat_sample_size_for_split` and `table_stat_sample_size_for_merge`.
406    // Will use max(table_stat_throuput_window_seconds_for_split /ckpt, table_stat_throuput_window_seconds_for_merge/ckpt) as the global sample size.
407    // For example, if `table_stat_throuput_window_seconds_for_merge` = 240 and `table_stat_throuput_window_seconds_for_split` = 60, and `ckpt_sec = 1`,
408    //  global sample size will be max(240/1, 60/1), then only the last 60 samples will be considered for split, and so on.
409    /// The window seconds of table throughput statistic history for split compaction group.
410    #[serde(default = "default::meta::table_stat_throuput_window_seconds_for_split")]
411    pub table_stat_throuput_window_seconds_for_split: usize,
412
413    /// The window seconds of table throughput statistic history for merge compaction group.
414    #[serde(default = "default::meta::table_stat_throuput_window_seconds_for_merge")]
415    pub table_stat_throuput_window_seconds_for_merge: usize,
416
417    /// The threshold of table size in one compact task to decide whether to partition one table into `hybrid_partition_vnode_count` parts, which belongs to default group and materialized view group.
418    /// Set it max value of 64-bit number to disable this feature.
419    #[serde(default = "default::meta::compact_task_table_size_partition_threshold_low")]
420    pub compact_task_table_size_partition_threshold_low: u64,
421
422    /// The threshold of table size in one compact task to decide whether to partition one table into `partition_vnode_count` parts, which belongs to default group and materialized view group.
423    /// Set it max value of 64-bit number to disable this feature.
424    #[serde(default = "default::meta::compact_task_table_size_partition_threshold_high")]
425    pub compact_task_table_size_partition_threshold_high: u64,
426
427    /// The interval of the periodic scheduling compaction group split job.
428    #[serde(
429        default = "default::meta::periodic_scheduling_compaction_group_split_interval_sec",
430        alias = "periodic_split_compact_group_interval_sec"
431    )]
432    pub periodic_scheduling_compaction_group_split_interval_sec: u64,
433
434    /// The interval of the periodic scheduling compaction group merge job.
435    #[serde(default = "default::meta::periodic_scheduling_compaction_group_merge_interval_sec")]
436    pub periodic_scheduling_compaction_group_merge_interval_sec: u64,
437
438    /// The threshold of each dimension of the compaction group after merging. When the dimension * `compaction_group_merge_dimension_threshold` >= limit, the merging job will be rejected.
439    #[serde(default = "default::meta::compaction_group_merge_dimension_threshold")]
440    pub compaction_group_merge_dimension_threshold: f64,
441
442    #[serde(default)]
443    #[config_doc(nested)]
444    pub meta_store_config: MetaStoreConfig,
445}
446
447#[derive(Copy, Clone, Debug, Default)]
448pub enum DefaultParallelism {
449    #[default]
450    Full,
451    Default(NonZeroUsize),
452}
453
454impl Serialize for DefaultParallelism {
455    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
456    where
457        S: Serializer,
458    {
459        #[derive(Debug, Serialize, Deserialize)]
460        #[serde(untagged)]
461        enum Parallelism {
462            Str(String),
463            Int(usize),
464        }
465        match self {
466            DefaultParallelism::Full => Parallelism::Str("Full".to_owned()).serialize(serializer),
467            DefaultParallelism::Default(val) => {
468                Parallelism::Int(val.get() as _).serialize(serializer)
469            }
470        }
471    }
472}
473
474impl<'de> Deserialize<'de> for DefaultParallelism {
475    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
476    where
477        D: serde::Deserializer<'de>,
478    {
479        #[derive(Debug, Deserialize)]
480        #[serde(untagged)]
481        enum Parallelism {
482            Str(String),
483            Int(usize),
484        }
485        let p = Parallelism::deserialize(deserializer)?;
486        match p {
487            Parallelism::Str(s) => {
488                if s.trim().eq_ignore_ascii_case("full") {
489                    Ok(DefaultParallelism::Full)
490                } else {
491                    Err(serde::de::Error::custom(format!(
492                        "invalid default parallelism: {}",
493                        s
494                    )))
495                }
496            }
497            Parallelism::Int(i) => Ok(DefaultParallelism::Default(
498                // Note: we won't check whether this exceeds the maximum parallelism (i.e., vnode count)
499                // here because it requires extra context. The check will be done when scheduling jobs.
500                NonZeroUsize::new(i).ok_or_else(|| {
501                    serde::de::Error::custom("default parallelism should not be 0")
502                })?,
503            )),
504        }
505    }
506}
507
508/// The subsections `[meta.developer]`.
509///
510/// It is put at [`MetaConfig::developer`].
511#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
512pub struct MetaDeveloperConfig {
513    /// The number of traces to be cached in-memory by the tracing collector
514    /// embedded in the meta node.
515    #[serde(default = "default::developer::meta_cached_traces_num")]
516    pub cached_traces_num: u32,
517
518    /// The maximum memory usage in bytes for the tracing collector embedded
519    /// in the meta node.
520    #[serde(default = "default::developer::meta_cached_traces_memory_limit_bytes")]
521    pub cached_traces_memory_limit_bytes: usize,
522
523    /// Compaction picker config
524    #[serde(default = "default::developer::enable_trivial_move")]
525    pub enable_trivial_move: bool,
526    #[serde(default = "default::developer::enable_check_task_level_overlap")]
527    pub enable_check_task_level_overlap: bool,
528    #[serde(default = "default::developer::max_trivial_move_task_count_per_loop")]
529    pub max_trivial_move_task_count_per_loop: usize,
530
531    #[serde(default = "default::developer::max_get_task_probe_times")]
532    pub max_get_task_probe_times: usize,
533
534    /// Max number of actor allowed per parallelism (default = 100).
535    /// CREATE MV/Table will be noticed when the number of actors exceeds this limit.
536    #[serde(default = "default::developer::actor_cnt_per_worker_parallelism_soft_limit")]
537    pub actor_cnt_per_worker_parallelism_soft_limit: usize,
538
539    /// Max number of actor allowed per parallelism (default = 400).
540    /// CREATE MV/Table will be rejected when the number of actors exceeds this limit.
541    #[serde(default = "default::developer::actor_cnt_per_worker_parallelism_hard_limit")]
542    pub actor_cnt_per_worker_parallelism_hard_limit: usize,
543
544    /// Max number of SSTs fetched from meta store per SELECT, during time travel Hummock version replay.
545    #[serde(default = "default::developer::hummock_time_travel_sst_info_fetch_batch_size")]
546    pub hummock_time_travel_sst_info_fetch_batch_size: usize,
547
548    /// Max number of SSTs inserted into meta store per INSERT, during time travel metadata writing.
549    #[serde(default = "default::developer::hummock_time_travel_sst_info_insert_batch_size")]
550    pub hummock_time_travel_sst_info_insert_batch_size: usize,
551
552    #[serde(default = "default::developer::time_travel_vacuum_interval_sec")]
553    pub time_travel_vacuum_interval_sec: u64,
554
555    /// Max number of epoch-to-version inserted into meta store per INSERT, during time travel metadata writing.
556    #[serde(default = "default::developer::hummock_time_travel_epoch_version_insert_batch_size")]
557    pub hummock_time_travel_epoch_version_insert_batch_size: usize,
558
559    #[serde(default = "default::developer::hummock_gc_history_insert_batch_size")]
560    pub hummock_gc_history_insert_batch_size: usize,
561
562    #[serde(default = "default::developer::hummock_time_travel_filter_out_objects_batch_size")]
563    pub hummock_time_travel_filter_out_objects_batch_size: usize,
564
565    #[serde(default = "default::developer::hummock_time_travel_filter_out_objects_v1")]
566    pub hummock_time_travel_filter_out_objects_v1: bool,
567
568    #[serde(
569        default = "default::developer::hummock_time_travel_filter_out_objects_list_version_batch_size"
570    )]
571    pub hummock_time_travel_filter_out_objects_list_version_batch_size: usize,
572
573    #[serde(
574        default = "default::developer::hummock_time_travel_filter_out_objects_list_delta_batch_size"
575    )]
576    pub hummock_time_travel_filter_out_objects_list_delta_batch_size: usize,
577
578    #[serde(default)]
579    pub compute_client_config: RpcClientConfig,
580
581    #[serde(default)]
582    pub stream_client_config: RpcClientConfig,
583
584    #[serde(default)]
585    pub frontend_client_config: RpcClientConfig,
586}
587
588#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
589pub struct RpcClientConfig {
590    #[serde(default = "default::developer::rpc_client_connect_timeout_secs")]
591    pub connect_timeout_secs: u64,
592}
593
594/// The section `[server]` in `risingwave.toml`.
595#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
596pub struct ServerConfig {
597    /// The interval for periodic heartbeat from worker to the meta service.
598    #[serde(default = "default::server::heartbeat_interval_ms")]
599    pub heartbeat_interval_ms: u32,
600
601    /// The default number of the connections when connecting to a gRPC server.
602    ///
603    /// For the connections used in streaming or batch exchange, please refer to the entries in
604    /// `[stream.developer]` and `[batch.developer]` sections. This value will be used if they
605    /// are not specified.
606    #[serde(default = "default::server::connection_pool_size")]
607    // Intentionally made private to avoid abuse. Check the related methods on `RwConfig`.
608    connection_pool_size: u16,
609
610    /// Used for control the metrics level, similar to log level.
611    #[serde(default = "default::server::metrics_level")]
612    pub metrics_level: MetricLevel,
613
614    #[serde(default = "default::server::telemetry_enabled")]
615    pub telemetry_enabled: bool,
616
617    /// Enable heap profile dump when memory usage is high.
618    #[serde(default)]
619    pub heap_profiling: HeapProfilingConfig,
620
621    // Number of max pending reset stream for grpc server.
622    #[serde(default = "default::server::grpc_max_reset_stream_size")]
623    pub grpc_max_reset_stream: u32,
624
625    #[serde(default, flatten)]
626    #[config_doc(omitted)]
627    pub unrecognized: Unrecognized<Self>,
628}
629
630/// The section `[batch]` in `risingwave.toml`.
631#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
632pub struct BatchConfig {
633    /// The thread number of the batch task runtime in the compute node. The default value is
634    /// decided by `tokio`.
635    #[serde(default)]
636    pub worker_threads_num: Option<usize>,
637
638    #[serde(default, with = "batch_prefix")]
639    #[config_doc(omitted)]
640    pub developer: BatchDeveloperConfig,
641
642    /// This is the max number of queries per sql session.
643    #[serde(default)]
644    pub distributed_query_limit: Option<u64>,
645
646    /// This is the max number of batch queries per frontend node.
647    #[serde(default)]
648    pub max_batch_queries_per_frontend_node: Option<u64>,
649
650    #[serde(default = "default::batch::enable_barrier_read")]
651    pub enable_barrier_read: bool,
652
653    /// Timeout for a batch query in seconds.
654    #[serde(default = "default::batch::statement_timeout_in_sec")]
655    pub statement_timeout_in_sec: u32,
656
657    #[serde(default, flatten)]
658    #[config_doc(omitted)]
659    pub unrecognized: Unrecognized<Self>,
660
661    #[serde(default = "default::batch::frontend_compute_runtime_worker_threads")]
662    /// frontend compute runtime worker threads
663    pub frontend_compute_runtime_worker_threads: usize,
664
665    /// This is the secs used to mask a worker unavailable temporarily.
666    #[serde(default = "default::batch::mask_worker_temporary_secs")]
667    pub mask_worker_temporary_secs: usize,
668
669    /// Keywords on which SQL option redaction is based in the query log.
670    /// A SQL option with a name containing any of these keywords will be redacted.
671    #[serde(default = "default::batch::redact_sql_option_keywords")]
672    pub redact_sql_option_keywords: Vec<String>,
673
674    /// Enable the spill out to disk feature for batch queries.
675    #[serde(default = "default::batch::enable_spill")]
676    pub enable_spill: bool,
677}
678
679#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
680pub struct FrontendConfig {
681    /// Total memory constraints for running queries.
682    #[serde(default = "default::frontend::max_total_query_size_bytes")]
683    pub max_total_query_size_bytes: u64,
684
685    /// A query of size under this threshold will never be rejected due to memory constraints.
686    #[serde(default = "default::frontend::min_single_query_size_bytes")]
687    pub min_single_query_size_bytes: u64,
688
689    /// A query of size exceeding this threshold will always be rejected due to memory constraints.
690    #[serde(default = "default::frontend::max_single_query_size_bytes")]
691    pub max_single_query_size_bytes: u64,
692}
693
694#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
695pub struct UdfConfig {
696    /// Allow embedded Python UDFs to be created.
697    #[serde(default = "default::udf::enable_embedded_python_udf")]
698    pub enable_embedded_python_udf: bool,
699
700    /// Allow embedded JS UDFs to be created.
701    #[serde(default = "default::udf::enable_embedded_javascript_udf")]
702    pub enable_embedded_javascript_udf: bool,
703
704    /// Allow embedded WASM UDFs to be created.
705    #[serde(default = "default::udf::enable_embedded_wasm_udf")]
706    pub enable_embedded_wasm_udf: bool,
707}
708
709/// The section `[streaming]` in `risingwave.toml`.
710#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
711pub struct StreamingConfig {
712    /// The maximum number of barriers in-flight in the compute nodes.
713    #[serde(default = "default::streaming::in_flight_barrier_nums")]
714    pub in_flight_barrier_nums: usize,
715
716    /// The thread number of the streaming actor runtime in the compute node. The default value is
717    /// decided by `tokio`.
718    #[serde(default)]
719    pub actor_runtime_worker_threads_num: Option<usize>,
720
721    /// Enable async stack tracing through `await-tree` for risectl.
722    #[serde(default = "default::streaming::async_stack_trace")]
723    pub async_stack_trace: AsyncStackTraceOption,
724
725    #[serde(default, with = "streaming_prefix")]
726    #[config_doc(omitted)]
727    pub developer: StreamingDeveloperConfig,
728
729    /// Max unique user stream errors per actor
730    #[serde(default = "default::streaming::unique_user_stream_errors")]
731    pub unique_user_stream_errors: usize,
732
733    /// Control the strictness of stream consistency.
734    #[serde(default = "default::streaming::unsafe_enable_strict_consistency")]
735    pub unsafe_enable_strict_consistency: bool,
736
737    #[serde(default, flatten)]
738    #[config_doc(omitted)]
739    pub unrecognized: Unrecognized<Self>,
740}
741
742pub use risingwave_common_metrics::MetricLevel;
743
744/// the section `[storage.cache]` in `risingwave.toml`.
745#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
746pub struct CacheConfig {
747    /// Configure the capacity of the block cache in MB explicitly.
748    /// The overridden value will only be effective if:
749    /// 1. `meta_cache_capacity_mb` and `shared_buffer_capacity_mb` are also configured explicitly.
750    /// 2. `block_cache_capacity_mb` + `meta_cache_capacity_mb` + `meta_cache_capacity_mb` doesn't exceed 0.3 * non-reserved memory.
751    #[serde(default)]
752    pub block_cache_capacity_mb: Option<usize>,
753
754    /// Configure the number of shards in the block cache explicitly.
755    /// If not set, the shard number will be determined automatically based on cache capacity.
756    #[serde(default)]
757    pub block_cache_shard_num: Option<usize>,
758
759    #[serde(default)]
760    #[config_doc(omitted)]
761    pub block_cache_eviction: CacheEvictionConfig,
762
763    /// Configure the capacity of the block cache in MB explicitly.
764    /// The overridden value will only be effective if:
765    /// 1. `block_cache_capacity_mb` and `shared_buffer_capacity_mb` are also configured explicitly.
766    /// 2. `block_cache_capacity_mb` + `meta_cache_capacity_mb` + `meta_cache_capacity_mb` doesn't exceed 0.3 * non-reserved memory.
767    #[serde(default)]
768    pub meta_cache_capacity_mb: Option<usize>,
769
770    /// Configure the number of shards in the meta cache explicitly.
771    /// If not set, the shard number will be determined automatically based on cache capacity.
772    #[serde(default)]
773    pub meta_cache_shard_num: Option<usize>,
774
775    #[serde(default)]
776    #[config_doc(omitted)]
777    pub meta_cache_eviction: CacheEvictionConfig,
778}
779
780/// the section `[storage.cache.eviction]` in `risingwave.toml`.
781#[derive(Clone, Debug, Serialize, Deserialize)]
782#[serde(tag = "algorithm")]
783pub enum CacheEvictionConfig {
784    Lru {
785        high_priority_ratio_in_percent: Option<usize>,
786    },
787    Lfu {
788        window_capacity_ratio_in_percent: Option<usize>,
789        protected_capacity_ratio_in_percent: Option<usize>,
790        cmsketch_eps: Option<f64>,
791        cmsketch_confidence: Option<f64>,
792    },
793    S3Fifo {
794        small_queue_capacity_ratio_in_percent: Option<usize>,
795        ghost_queue_capacity_ratio_in_percent: Option<usize>,
796        small_to_main_freq_threshold: Option<u8>,
797    },
798}
799
800impl Default for CacheEvictionConfig {
801    fn default() -> Self {
802        Self::Lru {
803            high_priority_ratio_in_percent: None,
804        }
805    }
806}
807
808/// The section `[storage]` in `risingwave.toml`.
809#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
810pub struct StorageConfig {
811    /// parallelism while syncing share buffers into L0 SST. Should NOT be 0.
812    #[serde(default = "default::storage::share_buffers_sync_parallelism")]
813    pub share_buffers_sync_parallelism: u32,
814
815    /// Worker threads number of dedicated tokio runtime for share buffer compaction. 0 means use
816    /// tokio's default value (number of CPU core).
817    #[serde(default = "default::storage::share_buffer_compaction_worker_threads_number")]
818    pub share_buffer_compaction_worker_threads_number: u32,
819
820    /// Configure the maximum shared buffer size in MB explicitly. Writes attempting to exceed the capacity
821    /// will stall until there is enough space. The overridden value will only be effective if:
822    /// 1. `block_cache_capacity_mb` and `meta_cache_capacity_mb` are also configured explicitly.
823    /// 2. `block_cache_capacity_mb` + `meta_cache_capacity_mb` + `meta_cache_capacity_mb` doesn't exceed 0.3 * non-reserved memory.
824    #[serde(default)]
825    pub shared_buffer_capacity_mb: Option<usize>,
826
827    /// The shared buffer will start flushing data to object when the ratio of memory usage to the
828    /// shared buffer capacity exceed such ratio.
829    #[serde(default = "default::storage::shared_buffer_flush_ratio")]
830    pub shared_buffer_flush_ratio: f32,
831
832    /// The minimum total flush size of shared buffer spill. When a shared buffer spilled is trigger,
833    /// the total flush size across multiple epochs should be at least higher than this size.
834    #[serde(default = "default::storage::shared_buffer_min_batch_flush_size_mb")]
835    pub shared_buffer_min_batch_flush_size_mb: usize,
836
837    /// The threshold for the number of immutable memtables to merge to a new imm.
838    #[serde(default = "default::storage::imm_merge_threshold")]
839    #[deprecated]
840    pub imm_merge_threshold: usize,
841
842    /// Whether to enable write conflict detection
843    #[serde(default = "default::storage::write_conflict_detection_enabled")]
844    pub write_conflict_detection_enabled: bool,
845
846    #[serde(default)]
847    #[config_doc(nested)]
848    pub cache: CacheConfig,
849
850    /// DEPRECATED: This config will be deprecated in the future version, use `storage.cache.block_cache_capacity_mb` instead.
851    #[serde(default)]
852    pub block_cache_capacity_mb: Option<usize>,
853
854    /// DEPRECATED: This config will be deprecated in the future version, use `storage.cache.meta_cache_capacity_mb` instead.
855    #[serde(default)]
856    pub meta_cache_capacity_mb: Option<usize>,
857
858    /// DEPRECATED: This config will be deprecated in the future version, use `storage.cache.block_cache_eviction.high_priority_ratio_in_percent` with `storage.cache.block_cache_eviction.algorithm = "Lru"` instead.
859    #[serde(default)]
860    pub high_priority_ratio_in_percent: Option<usize>,
861
862    /// max memory usage for large query
863    #[serde(default)]
864    pub prefetch_buffer_capacity_mb: Option<usize>,
865
866    #[serde(default = "default::storage::max_cached_recent_versions_number")]
867    pub max_cached_recent_versions_number: usize,
868
869    /// max prefetch block number
870    #[serde(default = "default::storage::max_prefetch_block_number")]
871    pub max_prefetch_block_number: usize,
872
873    #[serde(default = "default::storage::disable_remote_compactor")]
874    pub disable_remote_compactor: bool,
875
876    /// Number of tasks shared buffer can upload in parallel.
877    #[serde(default = "default::storage::share_buffer_upload_concurrency")]
878    pub share_buffer_upload_concurrency: usize,
879
880    #[serde(default)]
881    pub compactor_memory_limit_mb: Option<usize>,
882
883    /// Compactor calculates the maximum number of tasks that can be executed on the node based on
884    /// `worker_num` and `compactor_max_task_multiplier`.
885    /// `max_pull_task_count` = `worker_num` * `compactor_max_task_multiplier`
886    #[serde(default = "default::storage::compactor_max_task_multiplier")]
887    pub compactor_max_task_multiplier: f32,
888
889    /// The percentage of memory available when compactor is deployed separately.
890    /// `non_reserved_memory_bytes` = `system_memory_available_bytes` * `compactor_memory_available_proportion`
891    #[serde(default = "default::storage::compactor_memory_available_proportion")]
892    pub compactor_memory_available_proportion: f64,
893
894    /// Number of SST ids fetched from meta per RPC
895    #[serde(default = "default::storage::sstable_id_remote_fetch_number")]
896    pub sstable_id_remote_fetch_number: u32,
897
898    #[serde(default = "default::storage::min_sstable_size_mb")]
899    pub min_sstable_size_mb: u32,
900
901    #[serde(default)]
902    #[config_doc(nested)]
903    pub data_file_cache: FileCacheConfig,
904
905    #[serde(default)]
906    #[config_doc(nested)]
907    pub meta_file_cache: FileCacheConfig,
908
909    #[serde(default)]
910    #[config_doc(nested)]
911    pub cache_refill: CacheRefillConfig,
912
913    /// Whether to enable streaming upload for sstable.
914    #[serde(default = "default::storage::min_sst_size_for_streaming_upload")]
915    pub min_sst_size_for_streaming_upload: u64,
916
917    #[serde(default = "default::storage::max_concurrent_compaction_task_number")]
918    pub max_concurrent_compaction_task_number: u64,
919
920    #[serde(default = "default::storage::max_preload_wait_time_mill")]
921    pub max_preload_wait_time_mill: u64,
922
923    #[serde(default = "default::storage::max_version_pinning_duration_sec")]
924    pub max_version_pinning_duration_sec: u64,
925
926    #[serde(default = "default::storage::compactor_max_sst_key_count")]
927    pub compactor_max_sst_key_count: u64,
928    // DEPRECATED: This config will be deprecated in the future version, use `storage.compactor_iter_max_io_retry_times` instead.
929    #[serde(default = "default::storage::compact_iter_recreate_timeout_ms")]
930    pub compact_iter_recreate_timeout_ms: u64,
931    #[serde(default = "default::storage::compactor_max_sst_size")]
932    pub compactor_max_sst_size: u64,
933    #[serde(default = "default::storage::enable_fast_compaction")]
934    pub enable_fast_compaction: bool,
935    #[serde(default = "default::storage::check_compaction_result")]
936    pub check_compaction_result: bool,
937    #[serde(default = "default::storage::max_preload_io_retry_times")]
938    pub max_preload_io_retry_times: usize,
939    #[serde(default = "default::storage::compactor_fast_max_compact_delete_ratio")]
940    pub compactor_fast_max_compact_delete_ratio: u32,
941    #[serde(default = "default::storage::compactor_fast_max_compact_task_size")]
942    pub compactor_fast_max_compact_task_size: u64,
943    #[serde(default = "default::storage::compactor_iter_max_io_retry_times")]
944    pub compactor_iter_max_io_retry_times: usize,
945
946    /// Deprecated: The window size of table info statistic history.
947    #[serde(default = "default::storage::table_info_statistic_history_times")]
948    #[deprecated]
949    pub table_info_statistic_history_times: usize,
950
951    #[serde(default, flatten)]
952    #[config_doc(omitted)]
953    pub unrecognized: Unrecognized<Self>,
954
955    /// The spill threshold for mem table.
956    #[serde(default = "default::storage::mem_table_spill_threshold")]
957    pub mem_table_spill_threshold: usize,
958
959    /// The concurrent uploading number of `SSTables` of builder
960    #[serde(default = "default::storage::compactor_concurrent_uploading_sst_count")]
961    pub compactor_concurrent_uploading_sst_count: Option<usize>,
962
963    #[serde(default = "default::storage::compactor_max_overlap_sst_count")]
964    pub compactor_max_overlap_sst_count: usize,
965
966    /// The maximum number of meta files that can be preloaded.
967    /// If the number of meta files exceeds this value, the compactor will try to compute parallelism only through `SstableInfo`, no longer preloading `SstableMeta`.
968    /// This is to prevent the compactor from consuming too much memory, but it may cause the compactor to be less efficient.
969    #[serde(default = "default::storage::compactor_max_preload_meta_file_count")]
970    pub compactor_max_preload_meta_file_count: usize,
971
972    /// Object storage configuration
973    /// 1. General configuration
974    /// 2. Some special configuration of Backend
975    /// 3. Retry and timeout configuration
976    #[serde(default)]
977    pub object_store: ObjectStoreConfig,
978
979    #[serde(default = "default::storage::time_travel_version_cache_capacity")]
980    pub time_travel_version_cache_capacity: u64,
981
982    // iceberg compaction
983    #[serde(default = "default::storage::iceberg_compaction_target_file_size_mb")]
984    pub iceberg_compaction_target_file_size_mb: u32,
985    #[serde(default = "default::storage::iceberg_compaction_enable_validate")]
986    pub iceberg_compaction_enable_validate: bool,
987    #[serde(default = "default::storage::iceberg_compaction_max_record_batch_rows")]
988    pub iceberg_compaction_max_record_batch_rows: usize,
989    #[serde(default = "default::storage::iceberg_compaction_min_size_per_partition_mb")]
990    pub iceberg_compaction_min_size_per_partition_mb: u32,
991    #[serde(default = "default::storage::iceberg_compaction_max_file_count_per_partition")]
992    pub iceberg_compaction_max_file_count_per_partition: u32,
993
994    #[serde(default = "default::storage::iceberg_compaction_write_parquet_max_row_group_rows")]
995    pub iceberg_compaction_write_parquet_max_row_group_rows: usize,
996}
997
998#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
999pub struct CacheRefillConfig {
1000    /// `SSTable` levels to refill.
1001    #[serde(default = "default::cache_refill::data_refill_levels")]
1002    pub data_refill_levels: Vec<u32>,
1003
1004    /// Cache refill maximum timeout to apply version delta.
1005    #[serde(default = "default::cache_refill::timeout_ms")]
1006    pub timeout_ms: u64,
1007
1008    /// Inflight data cache refill tasks.
1009    #[serde(default = "default::cache_refill::concurrency")]
1010    pub concurrency: usize,
1011
1012    /// Block count that a data cache refill request fetches.
1013    #[serde(default = "default::cache_refill::unit")]
1014    pub unit: usize,
1015
1016    /// Data cache refill unit admission ratio.
1017    ///
1018    /// Only unit whose blocks are admitted above the ratio will be refilled.
1019    #[serde(default = "default::cache_refill::threshold")]
1020    pub threshold: f64,
1021
1022    /// Recent filter layer count.
1023    #[serde(default = "default::cache_refill::recent_filter_layers")]
1024    pub recent_filter_layers: usize,
1025
1026    /// Recent filter layer rotate interval.
1027    #[serde(default = "default::cache_refill::recent_filter_rotate_interval_ms")]
1028    pub recent_filter_rotate_interval_ms: usize,
1029
1030    #[serde(default, flatten)]
1031    #[config_doc(omitted)]
1032    pub unrecognized: Unrecognized<Self>,
1033}
1034
1035/// The subsection `[storage.data_file_cache]` and `[storage.meta_file_cache]` in `risingwave.toml`.
1036///
1037/// It's put at [`StorageConfig::data_file_cache`] and  [`StorageConfig::meta_file_cache`].
1038#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1039pub struct FileCacheConfig {
1040    #[serde(default = "default::file_cache::dir")]
1041    pub dir: String,
1042
1043    #[serde(default = "default::file_cache::capacity_mb")]
1044    pub capacity_mb: usize,
1045
1046    #[serde(default = "default::file_cache::file_capacity_mb")]
1047    pub file_capacity_mb: usize,
1048
1049    #[serde(default = "default::file_cache::flushers")]
1050    pub flushers: usize,
1051
1052    #[serde(default = "default::file_cache::reclaimers")]
1053    pub reclaimers: usize,
1054
1055    #[serde(default = "default::file_cache::recover_concurrency")]
1056    pub recover_concurrency: usize,
1057
1058    /// Deprecated soon. Please use `throttle` to do I/O throttling instead.
1059    #[serde(default = "default::file_cache::insert_rate_limit_mb")]
1060    pub insert_rate_limit_mb: usize,
1061
1062    #[serde(default = "default::file_cache::indexer_shards")]
1063    pub indexer_shards: usize,
1064
1065    #[serde(default = "default::file_cache::compression")]
1066    pub compression: Compression,
1067
1068    #[serde(default = "default::file_cache::flush_buffer_threshold_mb")]
1069    pub flush_buffer_threshold_mb: Option<usize>,
1070
1071    #[serde(default = "default::file_cache::throttle")]
1072    pub throttle: Throttle,
1073
1074    #[serde(default = "default::file_cache::fifo_probation_ratio")]
1075    pub fifo_probation_ratio: f64,
1076
1077    /// Recover mode.
1078    ///
1079    /// Options:
1080    ///
1081    /// - "None": Do not recover disk cache.
1082    /// - "Quiet": Recover disk cache and skip errors.
1083    /// - "Strict": Recover disk cache and panic on errors.
1084    ///
1085    /// More details, see [`RecoverMode::None`], [`RecoverMode::Quiet`] and [`RecoverMode::Strict`],
1086    #[serde(default = "default::file_cache::recover_mode")]
1087    pub recover_mode: RecoverMode,
1088
1089    #[serde(default = "default::file_cache::runtime_config")]
1090    pub runtime_config: RuntimeOptions,
1091
1092    #[serde(default, flatten)]
1093    #[config_doc(omitted)]
1094    pub unrecognized: Unrecognized<Self>,
1095}
1096
1097#[derive(Debug, Default, Clone, Copy, ValueEnum, Serialize, Deserialize)]
1098pub enum AsyncStackTraceOption {
1099    /// Disabled.
1100    Off,
1101    /// Enabled with basic instruments.
1102    On,
1103    /// Enabled with extra verbose instruments in release build.
1104    /// Behaves the same as `on` in debug build due to performance concern.
1105    #[default]
1106    #[clap(alias = "verbose")]
1107    ReleaseVerbose,
1108}
1109
1110impl AsyncStackTraceOption {
1111    pub fn is_verbose(self) -> Option<bool> {
1112        match self {
1113            Self::Off => None,
1114            Self::On => Some(false),
1115            Self::ReleaseVerbose => Some(!cfg!(debug_assertions)),
1116        }
1117    }
1118}
1119
1120#[derive(Debug, Default, Clone, Copy, ValueEnum)]
1121pub enum CompactorMode {
1122    #[default]
1123    #[clap(alias = "dedicated")]
1124    Dedicated,
1125
1126    #[clap(alias = "shared")]
1127    Shared,
1128
1129    #[clap(alias = "dedicated_iceberg")]
1130    DedicatedIceberg,
1131
1132    #[clap(alias = "shared_iceberg")]
1133    SharedIceberg,
1134}
1135
1136#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1137pub struct HeapProfilingConfig {
1138    /// Enable to auto dump heap profile when memory usage is high
1139    #[serde(default = "default::heap_profiling::enable_auto")]
1140    pub enable_auto: bool,
1141
1142    /// The proportion (number between 0 and 1) of memory usage to trigger heap profile dump
1143    #[serde(default = "default::heap_profiling::threshold_auto")]
1144    pub threshold_auto: f32,
1145
1146    /// The directory to dump heap profile. If empty, the prefix in `MALLOC_CONF` will be used
1147    #[serde(default = "default::heap_profiling::dir")]
1148    pub dir: String,
1149}
1150
1151/// The subsections `[streaming.developer]`.
1152///
1153/// It is put at [`StreamingConfig::developer`].
1154#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1155pub struct StreamingDeveloperConfig {
1156    /// Set to true to enable per-executor row count metrics. This will produce a lot of timeseries
1157    /// and might affect the prometheus performance. If you only need actor input and output
1158    /// rows data, see `stream_actor_in_record_cnt` and `stream_actor_out_record_cnt` instead.
1159    #[serde(default = "default::developer::stream_enable_executor_row_count")]
1160    pub enable_executor_row_count: bool,
1161
1162    /// The capacity of the chunks in the channel that connects between `ConnectorSource` and
1163    /// `SourceExecutor`.
1164    #[serde(default = "default::developer::connector_message_buffer_size")]
1165    pub connector_message_buffer_size: usize,
1166
1167    /// Limit number of the cached entries in an extreme aggregation call.
1168    #[serde(default = "default::developer::unsafe_stream_extreme_cache_size")]
1169    pub unsafe_extreme_cache_size: usize,
1170
1171    /// The maximum size of the chunk produced by executor at a time.
1172    #[serde(default = "default::developer::stream_chunk_size")]
1173    pub chunk_size: usize,
1174
1175    /// The initial permits that a channel holds, i.e., the maximum row count can be buffered in
1176    /// the channel.
1177    #[serde(default = "default::developer::stream_exchange_initial_permits")]
1178    pub exchange_initial_permits: usize,
1179
1180    /// The permits that are batched to add back, for reducing the backward `AddPermits` messages
1181    /// in remote exchange.
1182    #[serde(default = "default::developer::stream_exchange_batched_permits")]
1183    pub exchange_batched_permits: usize,
1184
1185    /// The maximum number of concurrent barriers in an exchange channel.
1186    #[serde(default = "default::developer::stream_exchange_concurrent_barriers")]
1187    pub exchange_concurrent_barriers: usize,
1188
1189    /// The concurrency for dispatching messages to different downstream jobs.
1190    ///
1191    /// - `1` means no concurrency, i.e., dispatch messages to downstream jobs one by one.
1192    /// - `0` means unlimited concurrency.
1193    #[serde(default = "default::developer::stream_exchange_concurrent_dispatchers")]
1194    pub exchange_concurrent_dispatchers: usize,
1195
1196    /// The initial permits for a dml channel, i.e., the maximum row count can be buffered in
1197    /// the channel.
1198    #[serde(default = "default::developer::stream_dml_channel_initial_permits")]
1199    pub dml_channel_initial_permits: usize,
1200
1201    /// The max heap size of dirty groups of `HashAggExecutor`.
1202    #[serde(default = "default::developer::stream_hash_agg_max_dirty_groups_heap_size")]
1203    pub hash_agg_max_dirty_groups_heap_size: usize,
1204
1205    #[serde(default = "default::developer::memory_controller_threshold_aggressive")]
1206    pub memory_controller_threshold_aggressive: f64,
1207
1208    #[serde(default = "default::developer::memory_controller_threshold_graceful")]
1209    pub memory_controller_threshold_graceful: f64,
1210
1211    #[serde(default = "default::developer::memory_controller_threshold_stable")]
1212    pub memory_controller_threshold_stable: f64,
1213
1214    #[serde(default = "default::developer::memory_controller_eviction_factor_aggressive")]
1215    pub memory_controller_eviction_factor_aggressive: f64,
1216
1217    #[serde(default = "default::developer::memory_controller_eviction_factor_graceful")]
1218    pub memory_controller_eviction_factor_graceful: f64,
1219
1220    #[serde(default = "default::developer::memory_controller_eviction_factor_stable")]
1221    pub memory_controller_eviction_factor_stable: f64,
1222
1223    #[serde(default = "default::developer::memory_controller_update_interval_ms")]
1224    pub memory_controller_update_interval_ms: usize,
1225
1226    #[serde(default = "default::developer::memory_controller_sequence_tls_step")]
1227    pub memory_controller_sequence_tls_step: u64,
1228
1229    #[serde(default = "default::developer::memory_controller_sequence_tls_lag")]
1230    pub memory_controller_sequence_tls_lag: u64,
1231
1232    #[serde(default = "default::developer::stream_enable_arrangement_backfill")]
1233    /// Enable arrangement backfill
1234    /// If false, the arrangement backfill will be disabled,
1235    /// even if session variable set.
1236    /// If true, it's decided by session variable `streaming_use_arrangement_backfill` (default true)
1237    pub enable_arrangement_backfill: bool,
1238
1239    #[serde(default = "default::developer::stream_high_join_amplification_threshold")]
1240    /// If number of hash join matches exceeds this threshold number,
1241    /// it will be logged.
1242    pub high_join_amplification_threshold: usize,
1243
1244    /// Actor tokio metrics is enabled if `enable_actor_tokio_metrics` is set or metrics level >= Debug.
1245    #[serde(default = "default::developer::enable_actor_tokio_metrics")]
1246    pub enable_actor_tokio_metrics: bool,
1247
1248    /// The number of the connections for streaming remote exchange between two nodes.
1249    /// If not specified, the value of `server.connection_pool_size` will be used.
1250    #[serde(default = "default::developer::stream_exchange_connection_pool_size")]
1251    pub exchange_connection_pool_size: Option<u16>,
1252
1253    /// A flag to allow disabling the auto schema change handling
1254    #[serde(default = "default::developer::stream_enable_auto_schema_change")]
1255    pub enable_auto_schema_change: bool,
1256
1257    #[serde(default = "default::developer::enable_shared_source")]
1258    /// Enable shared source
1259    /// If false, the shared source will be disabled,
1260    /// even if session variable set.
1261    /// If true, it's decided by session variable `streaming_use_shared_source` (default true)
1262    pub enable_shared_source: bool,
1263
1264    #[serde(default = "default::developer::switch_jdbc_pg_to_native")]
1265    /// When true, all jdbc sinks with connector='jdbc' and jdbc.url="jdbc:postgresql://..."
1266    /// will be switched from jdbc postgresql sinks to rust native (connector='postgres') sinks.
1267    pub switch_jdbc_pg_to_native: bool,
1268
1269    /// The maximum number of consecutive barriers allowed in a message when sent between actors.
1270    #[serde(default = "default::developer::stream_max_barrier_batch_size")]
1271    pub max_barrier_batch_size: u32,
1272
1273    /// Configure the system-wide cache row cardinality of hash join.
1274    /// For example, if this is set to 1000, it means we can have at most 1000 rows in cache.
1275    #[serde(default = "default::developer::streaming_hash_join_entry_state_max_rows")]
1276    pub hash_join_entry_state_max_rows: usize,
1277
1278    /// Enable / Disable profiling stats used by `EXPLAIN ANALYZE`
1279    #[serde(default = "default::developer::enable_explain_analyze_stats")]
1280    pub enable_explain_analyze_stats: bool,
1281
1282    #[serde(default)]
1283    pub compute_client_config: RpcClientConfig,
1284
1285    /// `IcebergListExecutor`: The interval in seconds for Iceberg source to list new files.
1286    #[serde(default = "default::developer::iceberg_list_interval_sec")]
1287    pub iceberg_list_interval_sec: u64,
1288
1289    /// `IcebergFetchExecutor`: The number of files the executor will fetch concurrently in a batch.
1290    #[serde(default = "default::developer::iceberg_fetch_batch_size")]
1291    pub iceberg_fetch_batch_size: u64,
1292
1293    /// `IcebergSink`: The size of the cache for positional delete in the sink.
1294    #[serde(default = "default::developer::iceberg_sink_positional_delete_cache_size")]
1295    pub iceberg_sink_positional_delete_cache_size: usize,
1296}
1297
1298/// The subsections `[batch.developer]`.
1299///
1300/// It is put at [`BatchConfig::developer`].
1301#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1302pub struct BatchDeveloperConfig {
1303    /// The capacity of the chunks in the channel that connects between `ConnectorSource` and
1304    /// `SourceExecutor`.
1305    #[serde(default = "default::developer::connector_message_buffer_size")]
1306    pub connector_message_buffer_size: usize,
1307
1308    /// The size of the channel used for output to exchange/shuffle.
1309    #[serde(default = "default::developer::batch_output_channel_size")]
1310    pub output_channel_size: usize,
1311
1312    #[serde(default = "default::developer::batch_receiver_channel_size")]
1313    pub receiver_channel_size: usize,
1314
1315    #[serde(default = "default::developer::batch_root_stage_channel_size")]
1316    pub root_stage_channel_size: usize,
1317
1318    /// The size of a chunk produced by `RowSeqScanExecutor`
1319    #[serde(default = "default::developer::batch_chunk_size")]
1320    pub chunk_size: usize,
1321
1322    /// The number of the connections for batch remote exchange between two nodes.
1323    /// If not specified, the value of `server.connection_pool_size` will be used.
1324    #[serde(default = "default::developer::batch_exchange_connection_pool_size")]
1325    exchange_connection_pool_size: Option<u16>,
1326
1327    #[serde(default)]
1328    pub compute_client_config: RpcClientConfig,
1329
1330    #[serde(default)]
1331    pub frontend_client_config: RpcClientConfig,
1332
1333    #[serde(default = "default::developer::batch_local_execute_buffer_size")]
1334    pub local_execute_buffer_size: usize,
1335}
1336
1337macro_rules! define_system_config {
1338    ($({ $field:ident, $type:ty, $default:expr, $is_mutable:expr, $doc:literal, $($rest:tt)* },)*) => {
1339        paste::paste!(
1340            /// The section `[system]` in `risingwave.toml`. All these fields are used to initialize the system
1341            /// parameters persisted in Meta store. Most fields are for testing purpose only and should not be
1342            /// documented.
1343            #[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1344            pub struct SystemConfig {
1345                $(
1346                    #[doc = $doc]
1347                    #[serde(default = "default::system::" $field "_opt")]
1348                    pub $field: Option<$type>,
1349                )*
1350            }
1351        );
1352    };
1353}
1354
1355for_all_params!(define_system_config);
1356
1357/// The subsections `[storage.object_store]`.
1358#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1359pub struct ObjectStoreConfig {
1360    // alias is for backward compatibility
1361    #[serde(
1362        default = "default::object_store_config::set_atomic_write_dir",
1363        alias = "object_store_set_atomic_write_dir"
1364    )]
1365    pub set_atomic_write_dir: bool,
1366
1367    /// Retry and timeout configuration
1368    /// Description retry strategy driven by exponential back-off
1369    /// Exposes the timeout and retries of each Object store interface. Therefore, the total timeout for each interface is determined based on the interface's timeout/retry configuration and the exponential back-off policy.
1370    #[serde(default)]
1371    pub retry: ObjectStoreRetryConfig,
1372
1373    /// Some special configuration of S3 Backend
1374    #[serde(default)]
1375    pub s3: S3ObjectStoreConfig,
1376
1377    // TODO: the following field will be deprecated after opendal is stabilized
1378    #[serde(default = "default::object_store_config::opendal_upload_concurrency")]
1379    pub opendal_upload_concurrency: usize,
1380
1381    // TODO: the following field will be deprecated after opendal is stabilized
1382    #[serde(default)]
1383    pub opendal_writer_abort_on_err: bool,
1384
1385    #[serde(default = "default::object_store_config::upload_part_size")]
1386    pub upload_part_size: usize,
1387}
1388
1389impl ObjectStoreConfig {
1390    pub fn set_atomic_write_dir(&mut self) {
1391        self.set_atomic_write_dir = true;
1392    }
1393}
1394
1395/// The subsections `[storage.object_store.s3]`.
1396#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1397pub struct S3ObjectStoreConfig {
1398    // alias is for backward compatibility
1399    #[serde(
1400        default = "default::object_store_config::s3::keepalive_ms",
1401        alias = "object_store_keepalive_ms"
1402    )]
1403    pub keepalive_ms: Option<u64>,
1404    #[serde(
1405        default = "default::object_store_config::s3::recv_buffer_size",
1406        alias = "object_store_recv_buffer_size"
1407    )]
1408    pub recv_buffer_size: Option<usize>,
1409    #[serde(
1410        default = "default::object_store_config::s3::send_buffer_size",
1411        alias = "object_store_send_buffer_size"
1412    )]
1413    pub send_buffer_size: Option<usize>,
1414    #[serde(
1415        default = "default::object_store_config::s3::nodelay",
1416        alias = "object_store_nodelay"
1417    )]
1418    pub nodelay: Option<bool>,
1419    /// For backwards compatibility, users should use `S3ObjectStoreDeveloperConfig` instead.
1420    #[serde(default = "default::object_store_config::s3::developer::retry_unknown_service_error")]
1421    pub retry_unknown_service_error: bool,
1422    #[serde(default = "default::object_store_config::s3::identity_resolution_timeout_s")]
1423    pub identity_resolution_timeout_s: u64,
1424    #[serde(default)]
1425    pub developer: S3ObjectStoreDeveloperConfig,
1426}
1427
1428/// The subsections `[storage.object_store.s3.developer]`.
1429#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1430pub struct S3ObjectStoreDeveloperConfig {
1431    /// Whether to retry s3 sdk error from which no error metadata is provided.
1432    #[serde(
1433        default = "default::object_store_config::s3::developer::retry_unknown_service_error",
1434        alias = "object_store_retry_unknown_service_error"
1435    )]
1436    pub retry_unknown_service_error: bool,
1437    /// An array of error codes that should be retried.
1438    /// e.g. `["SlowDown", "TooManyRequests"]`
1439    #[serde(
1440        default = "default::object_store_config::s3::developer::retryable_service_error_codes",
1441        alias = "object_store_retryable_service_error_codes"
1442    )]
1443    pub retryable_service_error_codes: Vec<String>,
1444
1445    // TODO: deprecate this config when we are completely deprecate aws sdk.
1446    #[serde(default = "default::object_store_config::s3::developer::use_opendal")]
1447    pub use_opendal: bool,
1448}
1449
1450#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1451pub struct ObjectStoreRetryConfig {
1452    // A retry strategy driven by exponential back-off.
1453    // The retry strategy is used for all object store operations.
1454    /// Given a base duration for retry strategy in milliseconds.
1455    #[serde(default = "default::object_store_config::object_store_req_backoff_interval_ms")]
1456    pub req_backoff_interval_ms: u64,
1457
1458    /// The max delay interval for the retry strategy. No retry delay will be longer than this `Duration`.
1459    #[serde(default = "default::object_store_config::object_store_req_backoff_max_delay_ms")]
1460    pub req_backoff_max_delay_ms: u64,
1461
1462    /// A multiplicative factor that will be applied to the exponential back-off retry delay.
1463    #[serde(default = "default::object_store_config::object_store_req_backoff_factor")]
1464    pub req_backoff_factor: u64,
1465
1466    /// Maximum timeout for `upload` operation
1467    #[serde(default = "default::object_store_config::object_store_upload_attempt_timeout_ms")]
1468    pub upload_attempt_timeout_ms: u64,
1469
1470    /// Total counts of `upload` operation retries
1471    #[serde(default = "default::object_store_config::object_store_upload_retry_attempts")]
1472    pub upload_retry_attempts: usize,
1473
1474    /// Maximum timeout for `streaming_upload_init` and `streaming_upload`
1475    #[serde(
1476        default = "default::object_store_config::object_store_streaming_upload_attempt_timeout_ms"
1477    )]
1478    pub streaming_upload_attempt_timeout_ms: u64,
1479
1480    /// Total counts of `streaming_upload` operation retries
1481    #[serde(
1482        default = "default::object_store_config::object_store_streaming_upload_retry_attempts"
1483    )]
1484    pub streaming_upload_retry_attempts: usize,
1485
1486    /// Maximum timeout for `read` operation
1487    #[serde(default = "default::object_store_config::object_store_read_attempt_timeout_ms")]
1488    pub read_attempt_timeout_ms: u64,
1489
1490    /// Total counts of `read` operation retries
1491    #[serde(default = "default::object_store_config::object_store_read_retry_attempts")]
1492    pub read_retry_attempts: usize,
1493
1494    /// Maximum timeout for `streaming_read_init` and `streaming_read` operation
1495    #[serde(
1496        default = "default::object_store_config::object_store_streaming_read_attempt_timeout_ms"
1497    )]
1498    pub streaming_read_attempt_timeout_ms: u64,
1499
1500    /// Total counts of `streaming_read operation` retries
1501    #[serde(default = "default::object_store_config::object_store_streaming_read_retry_attempts")]
1502    pub streaming_read_retry_attempts: usize,
1503
1504    /// Maximum timeout for `metadata` operation
1505    #[serde(default = "default::object_store_config::object_store_metadata_attempt_timeout_ms")]
1506    pub metadata_attempt_timeout_ms: u64,
1507
1508    /// Total counts of `metadata` operation retries
1509    #[serde(default = "default::object_store_config::object_store_metadata_retry_attempts")]
1510    pub metadata_retry_attempts: usize,
1511
1512    /// Maximum timeout for `delete` operation
1513    #[serde(default = "default::object_store_config::object_store_delete_attempt_timeout_ms")]
1514    pub delete_attempt_timeout_ms: u64,
1515
1516    /// Total counts of `delete` operation retries
1517    #[serde(default = "default::object_store_config::object_store_delete_retry_attempts")]
1518    pub delete_retry_attempts: usize,
1519
1520    /// Maximum timeout for `delete_object` operation
1521    #[serde(
1522        default = "default::object_store_config::object_store_delete_objects_attempt_timeout_ms"
1523    )]
1524    pub delete_objects_attempt_timeout_ms: u64,
1525
1526    /// Total counts of `delete_object` operation retries
1527    #[serde(default = "default::object_store_config::object_store_delete_objects_retry_attempts")]
1528    pub delete_objects_retry_attempts: usize,
1529
1530    /// Maximum timeout for `list` operation
1531    #[serde(default = "default::object_store_config::object_store_list_attempt_timeout_ms")]
1532    pub list_attempt_timeout_ms: u64,
1533
1534    /// Total counts of `list` operation retries
1535    #[serde(default = "default::object_store_config::object_store_list_retry_attempts")]
1536    pub list_retry_attempts: usize,
1537}
1538
1539impl SystemConfig {
1540    #![allow(deprecated)]
1541    pub fn into_init_system_params(self) -> SystemParams {
1542        macro_rules! fields {
1543            ($({ $field:ident, $($rest:tt)* },)*) => {
1544                SystemParams {
1545                    $($field: self.$field.map(Into::into),)*
1546                    ..Default::default() // deprecated fields
1547                }
1548            };
1549        }
1550
1551        let mut system_params = for_all_params!(fields);
1552
1553        // Initialize backup_storage_url and backup_storage_directory if not set.
1554        if let Some(state_store) = &system_params.state_store
1555            && let Some(data_directory) = &system_params.data_directory
1556        {
1557            if system_params.backup_storage_url.is_none() {
1558                if let Some(hummock_state_store) = state_store.strip_prefix("hummock+") {
1559                    system_params.backup_storage_url = Some(hummock_state_store.to_owned());
1560                } else {
1561                    system_params.backup_storage_url = Some("memory".to_owned());
1562                }
1563                tracing::info!("initialize backup_storage_url based on state_store");
1564            }
1565            if system_params.backup_storage_directory.is_none() {
1566                system_params.backup_storage_directory = Some(format!("{data_directory}/backup"));
1567                tracing::info!("initialize backup_storage_directory based on data_directory");
1568            }
1569        }
1570        system_params
1571    }
1572}
1573
1574impl RwConfig {
1575    pub const fn default_connection_pool_size(&self) -> u16 {
1576        self.server.connection_pool_size
1577    }
1578
1579    /// Returns [`StreamingDeveloperConfig::exchange_connection_pool_size`] if set,
1580    /// otherwise [`ServerConfig::connection_pool_size`].
1581    pub fn streaming_exchange_connection_pool_size(&self) -> u16 {
1582        self.streaming
1583            .developer
1584            .exchange_connection_pool_size
1585            .unwrap_or_else(|| self.default_connection_pool_size())
1586    }
1587
1588    /// Returns [`BatchDeveloperConfig::exchange_connection_pool_size`] if set,
1589    /// otherwise [`ServerConfig::connection_pool_size`].
1590    pub fn batch_exchange_connection_pool_size(&self) -> u16 {
1591        self.batch
1592            .developer
1593            .exchange_connection_pool_size
1594            .unwrap_or_else(|| self.default_connection_pool_size())
1595    }
1596}
1597
1598pub mod default {
1599    pub mod meta {
1600        use crate::config::{DefaultParallelism, MetaBackend};
1601
1602        pub fn min_sst_retention_time_sec() -> u64 {
1603            3600 * 6
1604        }
1605
1606        pub fn gc_history_retention_time_sec() -> u64 {
1607            3600 * 6
1608        }
1609
1610        pub fn full_gc_interval_sec() -> u64 {
1611            3600
1612        }
1613
1614        pub fn full_gc_object_limit() -> u64 {
1615            100_000
1616        }
1617
1618        pub fn max_inflight_time_travel_query() -> u64 {
1619            1000
1620        }
1621
1622        pub fn periodic_compaction_interval_sec() -> u64 {
1623            60
1624        }
1625
1626        pub fn vacuum_interval_sec() -> u64 {
1627            30
1628        }
1629
1630        pub fn vacuum_spin_interval_ms() -> u64 {
1631            100
1632        }
1633
1634        pub fn hummock_version_checkpoint_interval_sec() -> u64 {
1635            30
1636        }
1637
1638        pub fn enable_hummock_data_archive() -> bool {
1639            false
1640        }
1641
1642        pub fn hummock_time_travel_snapshot_interval() -> u64 {
1643            100
1644        }
1645
1646        pub fn min_delta_log_num_for_hummock_version_checkpoint() -> u64 {
1647            10
1648        }
1649
1650        pub fn max_heartbeat_interval_sec() -> u32 {
1651            60
1652        }
1653
1654        pub fn meta_leader_lease_secs() -> u64 {
1655            30
1656        }
1657
1658        pub fn default_parallelism() -> DefaultParallelism {
1659            DefaultParallelism::Full
1660        }
1661
1662        pub fn node_num_monitor_interval_sec() -> u64 {
1663            10
1664        }
1665
1666        pub fn backend() -> MetaBackend {
1667            MetaBackend::Mem
1668        }
1669
1670        pub fn periodic_space_reclaim_compaction_interval_sec() -> u64 {
1671            3600 // 60min
1672        }
1673
1674        pub fn periodic_ttl_reclaim_compaction_interval_sec() -> u64 {
1675            1800 // 30mi
1676        }
1677
1678        pub fn periodic_scheduling_compaction_group_split_interval_sec() -> u64 {
1679            10 // 10s
1680        }
1681
1682        pub fn periodic_tombstone_reclaim_compaction_interval_sec() -> u64 {
1683            600
1684        }
1685
1686        // limit the size of state table to trigger split by high throughput
1687        pub fn move_table_size_limit() -> u64 {
1688            10 * 1024 * 1024 * 1024 // 10GB
1689        }
1690
1691        // limit the size of group to trigger split by group_size and avoid too many small groups
1692        pub fn split_group_size_limit() -> u64 {
1693            64 * 1024 * 1024 * 1024 // 64GB
1694        }
1695
1696        pub fn partition_vnode_count() -> u32 {
1697            16
1698        }
1699
1700        pub fn table_high_write_throughput_threshold() -> u64 {
1701            16 * 1024 * 1024 // 16MB
1702        }
1703
1704        pub fn table_low_write_throughput_threshold() -> u64 {
1705            4 * 1024 * 1024 // 4MB
1706        }
1707
1708        pub fn compaction_task_max_heartbeat_interval_secs() -> u64 {
1709            30 // 30s
1710        }
1711
1712        pub fn compaction_task_max_progress_interval_secs() -> u64 {
1713            60 * 10 // 10min
1714        }
1715
1716        pub fn cut_table_size_limit() -> u64 {
1717            1024 * 1024 * 1024 // 1GB
1718        }
1719
1720        pub fn hybrid_partition_vnode_count() -> u32 {
1721            4
1722        }
1723
1724        pub fn compact_task_table_size_partition_threshold_low() -> u64 {
1725            128 * 1024 * 1024 // 128MB
1726        }
1727
1728        pub fn compact_task_table_size_partition_threshold_high() -> u64 {
1729            512 * 1024 * 1024 // 512MB
1730        }
1731
1732        pub fn event_log_enabled() -> bool {
1733            true
1734        }
1735
1736        pub fn event_log_channel_max_size() -> u32 {
1737            10
1738        }
1739
1740        pub fn parallelism_control_batch_size() -> usize {
1741            10
1742        }
1743
1744        pub fn parallelism_control_trigger_period_sec() -> u64 {
1745            10
1746        }
1747
1748        pub fn parallelism_control_trigger_first_delay_sec() -> u64 {
1749            30
1750        }
1751
1752        pub fn enable_dropped_column_reclaim() -> bool {
1753            false
1754        }
1755
1756        pub fn split_group_size_ratio() -> f64 {
1757            0.9
1758        }
1759
1760        pub fn table_stat_high_write_throughput_ratio_for_split() -> f64 {
1761            0.5
1762        }
1763
1764        pub fn table_stat_low_write_throughput_ratio_for_merge() -> f64 {
1765            0.7
1766        }
1767
1768        pub fn table_stat_throuput_window_seconds_for_split() -> usize {
1769            60
1770        }
1771
1772        pub fn table_stat_throuput_window_seconds_for_merge() -> usize {
1773            240
1774        }
1775
1776        pub fn periodic_scheduling_compaction_group_merge_interval_sec() -> u64 {
1777            60 * 10 // 10min
1778        }
1779
1780        pub fn compaction_group_merge_dimension_threshold() -> f64 {
1781            1.2
1782        }
1783    }
1784
1785    pub mod server {
1786        use crate::config::MetricLevel;
1787
1788        pub fn heartbeat_interval_ms() -> u32 {
1789            1000
1790        }
1791
1792        pub fn connection_pool_size() -> u16 {
1793            16
1794        }
1795
1796        pub fn metrics_level() -> MetricLevel {
1797            MetricLevel::Info
1798        }
1799
1800        pub fn telemetry_enabled() -> bool {
1801            true
1802        }
1803
1804        pub fn grpc_max_reset_stream_size() -> u32 {
1805            200
1806        }
1807    }
1808
1809    pub mod storage {
1810        pub fn share_buffers_sync_parallelism() -> u32 {
1811            1
1812        }
1813
1814        pub fn share_buffer_compaction_worker_threads_number() -> u32 {
1815            4
1816        }
1817
1818        pub fn shared_buffer_capacity_mb() -> usize {
1819            1024
1820        }
1821
1822        pub fn shared_buffer_flush_ratio() -> f32 {
1823            0.8
1824        }
1825
1826        pub fn shared_buffer_min_batch_flush_size_mb() -> usize {
1827            800
1828        }
1829
1830        pub fn imm_merge_threshold() -> usize {
1831            0 // disable
1832        }
1833
1834        pub fn write_conflict_detection_enabled() -> bool {
1835            cfg!(debug_assertions)
1836        }
1837
1838        pub fn max_cached_recent_versions_number() -> usize {
1839            60
1840        }
1841
1842        pub fn block_cache_capacity_mb() -> usize {
1843            512
1844        }
1845
1846        pub fn high_priority_ratio_in_percent() -> usize {
1847            70
1848        }
1849
1850        pub fn window_capacity_ratio_in_percent() -> usize {
1851            10
1852        }
1853
1854        pub fn protected_capacity_ratio_in_percent() -> usize {
1855            80
1856        }
1857
1858        pub fn cmsketch_eps() -> f64 {
1859            0.002
1860        }
1861
1862        pub fn cmsketch_confidence() -> f64 {
1863            0.95
1864        }
1865
1866        pub fn small_queue_capacity_ratio_in_percent() -> usize {
1867            10
1868        }
1869
1870        pub fn ghost_queue_capacity_ratio_in_percent() -> usize {
1871            1000
1872        }
1873
1874        pub fn small_to_main_freq_threshold() -> u8 {
1875            1
1876        }
1877
1878        pub fn meta_cache_capacity_mb() -> usize {
1879            128
1880        }
1881
1882        pub fn disable_remote_compactor() -> bool {
1883            false
1884        }
1885
1886        pub fn share_buffer_upload_concurrency() -> usize {
1887            8
1888        }
1889
1890        pub fn compactor_memory_limit_mb() -> usize {
1891            512
1892        }
1893
1894        pub fn compactor_max_task_multiplier() -> f32 {
1895            3.0000
1896        }
1897
1898        pub fn compactor_memory_available_proportion() -> f64 {
1899            0.8
1900        }
1901
1902        pub fn sstable_id_remote_fetch_number() -> u32 {
1903            10
1904        }
1905
1906        pub fn min_sstable_size_mb() -> u32 {
1907            32
1908        }
1909
1910        pub fn min_sst_size_for_streaming_upload() -> u64 {
1911            // 32MB
1912            32 * 1024 * 1024
1913        }
1914
1915        pub fn max_concurrent_compaction_task_number() -> u64 {
1916            16
1917        }
1918
1919        pub fn max_preload_wait_time_mill() -> u64 {
1920            0
1921        }
1922
1923        pub fn max_version_pinning_duration_sec() -> u64 {
1924            3 * 3600
1925        }
1926
1927        pub fn compactor_max_sst_key_count() -> u64 {
1928            2 * 1024 * 1024 // 200w
1929        }
1930
1931        pub fn compact_iter_recreate_timeout_ms() -> u64 {
1932            10 * 60 * 1000
1933        }
1934
1935        pub fn compactor_iter_max_io_retry_times() -> usize {
1936            8
1937        }
1938
1939        pub fn compactor_max_sst_size() -> u64 {
1940            512 * 1024 * 1024 // 512m
1941        }
1942
1943        pub fn enable_fast_compaction() -> bool {
1944            true
1945        }
1946
1947        pub fn check_compaction_result() -> bool {
1948            false
1949        }
1950
1951        pub fn max_preload_io_retry_times() -> usize {
1952            3
1953        }
1954
1955        pub fn mem_table_spill_threshold() -> usize {
1956            4 << 20
1957        }
1958
1959        pub fn compactor_fast_max_compact_delete_ratio() -> u32 {
1960            40
1961        }
1962
1963        pub fn compactor_fast_max_compact_task_size() -> u64 {
1964            2 * 1024 * 1024 * 1024 // 2g
1965        }
1966
1967        pub fn max_prefetch_block_number() -> usize {
1968            16
1969        }
1970
1971        pub fn compactor_concurrent_uploading_sst_count() -> Option<usize> {
1972            None
1973        }
1974
1975        pub fn compactor_max_overlap_sst_count() -> usize {
1976            64
1977        }
1978
1979        pub fn compactor_max_preload_meta_file_count() -> usize {
1980            32
1981        }
1982
1983        // deprecated
1984        pub fn table_info_statistic_history_times() -> usize {
1985            240
1986        }
1987
1988        pub fn block_file_cache_flush_buffer_threshold_mb() -> usize {
1989            256
1990        }
1991
1992        pub fn meta_file_cache_flush_buffer_threshold_mb() -> usize {
1993            64
1994        }
1995
1996        pub fn time_travel_version_cache_capacity() -> u64 {
1997            10
1998        }
1999
2000        pub fn iceberg_compaction_target_file_size_mb() -> u32 {
2001            1024
2002        }
2003
2004        pub fn iceberg_compaction_enable_validate() -> bool {
2005            false
2006        }
2007
2008        pub fn iceberg_compaction_max_record_batch_rows() -> usize {
2009            1024
2010        }
2011
2012        pub fn iceberg_compaction_write_parquet_max_row_group_rows() -> usize {
2013            1024 * 100 // 100k
2014        }
2015
2016        pub fn iceberg_compaction_min_size_per_partition_mb() -> u32 {
2017            1024
2018        }
2019
2020        pub fn iceberg_compaction_max_file_count_per_partition() -> u32 {
2021            32
2022        }
2023    }
2024
2025    pub mod streaming {
2026        use crate::config::AsyncStackTraceOption;
2027
2028        pub fn in_flight_barrier_nums() -> usize {
2029            // quick fix
2030            // TODO: remove this limitation from code
2031            10000
2032        }
2033
2034        pub fn async_stack_trace() -> AsyncStackTraceOption {
2035            AsyncStackTraceOption::default()
2036        }
2037
2038        pub fn unique_user_stream_errors() -> usize {
2039            10
2040        }
2041
2042        pub fn unsafe_enable_strict_consistency() -> bool {
2043            true
2044        }
2045    }
2046
2047    pub mod file_cache {
2048        use std::num::NonZeroUsize;
2049
2050        use foyer::{Compression, RecoverMode, RuntimeOptions, Throttle, TokioRuntimeOptions};
2051
2052        pub fn dir() -> String {
2053            "".to_owned()
2054        }
2055
2056        pub fn capacity_mb() -> usize {
2057            1024
2058        }
2059
2060        pub fn file_capacity_mb() -> usize {
2061            64
2062        }
2063
2064        pub fn flushers() -> usize {
2065            4
2066        }
2067
2068        pub fn reclaimers() -> usize {
2069            4
2070        }
2071
2072        pub fn recover_concurrency() -> usize {
2073            8
2074        }
2075
2076        pub fn insert_rate_limit_mb() -> usize {
2077            0
2078        }
2079
2080        pub fn indexer_shards() -> usize {
2081            64
2082        }
2083
2084        pub fn compression() -> Compression {
2085            Compression::None
2086        }
2087
2088        pub fn flush_buffer_threshold_mb() -> Option<usize> {
2089            None
2090        }
2091
2092        pub fn fifo_probation_ratio() -> f64 {
2093            0.1
2094        }
2095
2096        pub fn recover_mode() -> RecoverMode {
2097            RecoverMode::Quiet
2098        }
2099
2100        pub fn runtime_config() -> RuntimeOptions {
2101            RuntimeOptions::Unified(TokioRuntimeOptions::default())
2102        }
2103
2104        pub fn throttle() -> Throttle {
2105            Throttle::new()
2106                .with_iops_counter(foyer::IopsCounter::PerIoSize(
2107                    NonZeroUsize::new(128 * 1024).unwrap(),
2108                ))
2109                .with_read_iops(100000)
2110                .with_write_iops(100000)
2111                .with_write_throughput(1024 * 1024 * 1024)
2112                .with_read_throughput(1024 * 1024 * 1024)
2113        }
2114    }
2115
2116    pub mod cache_refill {
2117        pub fn data_refill_levels() -> Vec<u32> {
2118            vec![]
2119        }
2120
2121        pub fn timeout_ms() -> u64 {
2122            6000
2123        }
2124
2125        pub fn concurrency() -> usize {
2126            10
2127        }
2128
2129        pub fn unit() -> usize {
2130            64
2131        }
2132
2133        pub fn threshold() -> f64 {
2134            0.5
2135        }
2136
2137        pub fn recent_filter_layers() -> usize {
2138            6
2139        }
2140
2141        pub fn recent_filter_rotate_interval_ms() -> usize {
2142            10000
2143        }
2144    }
2145
2146    pub mod heap_profiling {
2147        pub fn enable_auto() -> bool {
2148            true
2149        }
2150
2151        pub fn threshold_auto() -> f32 {
2152            0.9
2153        }
2154
2155        pub fn dir() -> String {
2156            "./".to_owned()
2157        }
2158    }
2159
2160    pub mod developer {
2161        pub fn meta_cached_traces_num() -> u32 {
2162            256
2163        }
2164
2165        pub fn meta_cached_traces_memory_limit_bytes() -> usize {
2166            1 << 27 // 128 MiB
2167        }
2168
2169        pub fn batch_output_channel_size() -> usize {
2170            64
2171        }
2172
2173        pub fn batch_receiver_channel_size() -> usize {
2174            1000
2175        }
2176
2177        pub fn batch_root_stage_channel_size() -> usize {
2178            100
2179        }
2180
2181        pub fn batch_chunk_size() -> usize {
2182            1024
2183        }
2184
2185        pub fn batch_local_execute_buffer_size() -> usize {
2186            64
2187        }
2188
2189        /// Default to unset to be compatible with the behavior before this config is introduced,
2190        /// that is, follow the value of `server.connection_pool_size`.
2191        pub fn batch_exchange_connection_pool_size() -> Option<u16> {
2192            None
2193        }
2194
2195        pub fn stream_enable_executor_row_count() -> bool {
2196            false
2197        }
2198
2199        pub fn connector_message_buffer_size() -> usize {
2200            16
2201        }
2202
2203        pub fn unsafe_stream_extreme_cache_size() -> usize {
2204            10
2205        }
2206
2207        pub fn stream_chunk_size() -> usize {
2208            256
2209        }
2210
2211        pub fn stream_exchange_initial_permits() -> usize {
2212            2048
2213        }
2214
2215        pub fn stream_exchange_batched_permits() -> usize {
2216            256
2217        }
2218
2219        pub fn stream_exchange_concurrent_barriers() -> usize {
2220            1
2221        }
2222
2223        pub fn stream_exchange_concurrent_dispatchers() -> usize {
2224            0
2225        }
2226
2227        pub fn stream_dml_channel_initial_permits() -> usize {
2228            32768
2229        }
2230
2231        pub fn stream_max_barrier_batch_size() -> u32 {
2232            1024
2233        }
2234
2235        pub fn stream_hash_agg_max_dirty_groups_heap_size() -> usize {
2236            64 << 20 // 64MB
2237        }
2238
2239        pub fn enable_trivial_move() -> bool {
2240            true
2241        }
2242
2243        pub fn enable_check_task_level_overlap() -> bool {
2244            false
2245        }
2246
2247        pub fn max_trivial_move_task_count_per_loop() -> usize {
2248            256
2249        }
2250
2251        pub fn max_get_task_probe_times() -> usize {
2252            5
2253        }
2254
2255        pub fn actor_cnt_per_worker_parallelism_soft_limit() -> usize {
2256            100
2257        }
2258
2259        pub fn actor_cnt_per_worker_parallelism_hard_limit() -> usize {
2260            400
2261        }
2262
2263        pub fn hummock_time_travel_sst_info_fetch_batch_size() -> usize {
2264            10_000
2265        }
2266
2267        pub fn hummock_time_travel_sst_info_insert_batch_size() -> usize {
2268            100
2269        }
2270
2271        pub fn time_travel_vacuum_interval_sec() -> u64 {
2272            30
2273        }
2274        pub fn hummock_time_travel_epoch_version_insert_batch_size() -> usize {
2275            1000
2276        }
2277
2278        pub fn hummock_gc_history_insert_batch_size() -> usize {
2279            1000
2280        }
2281
2282        pub fn hummock_time_travel_filter_out_objects_batch_size() -> usize {
2283            1000
2284        }
2285
2286        pub fn hummock_time_travel_filter_out_objects_v1() -> bool {
2287            false
2288        }
2289
2290        pub fn hummock_time_travel_filter_out_objects_list_version_batch_size() -> usize {
2291            10
2292        }
2293
2294        pub fn hummock_time_travel_filter_out_objects_list_delta_batch_size() -> usize {
2295            1000
2296        }
2297
2298        pub fn memory_controller_threshold_aggressive() -> f64 {
2299            0.9
2300        }
2301
2302        pub fn memory_controller_threshold_graceful() -> f64 {
2303            0.81
2304        }
2305
2306        pub fn memory_controller_threshold_stable() -> f64 {
2307            0.72
2308        }
2309
2310        pub fn memory_controller_eviction_factor_aggressive() -> f64 {
2311            2.0
2312        }
2313
2314        pub fn memory_controller_eviction_factor_graceful() -> f64 {
2315            1.5
2316        }
2317
2318        pub fn memory_controller_eviction_factor_stable() -> f64 {
2319            1.0
2320        }
2321
2322        pub fn memory_controller_update_interval_ms() -> usize {
2323            100
2324        }
2325
2326        pub fn memory_controller_sequence_tls_step() -> u64 {
2327            128
2328        }
2329
2330        pub fn memory_controller_sequence_tls_lag() -> u64 {
2331            32
2332        }
2333
2334        pub fn stream_enable_arrangement_backfill() -> bool {
2335            true
2336        }
2337
2338        pub fn enable_shared_source() -> bool {
2339            true
2340        }
2341
2342        pub fn stream_high_join_amplification_threshold() -> usize {
2343            2048
2344        }
2345
2346        /// Default to 1 to be compatible with the behavior before this config is introduced.
2347        pub fn stream_exchange_connection_pool_size() -> Option<u16> {
2348            Some(1)
2349        }
2350
2351        pub fn enable_actor_tokio_metrics() -> bool {
2352            false
2353        }
2354
2355        pub fn stream_enable_auto_schema_change() -> bool {
2356            true
2357        }
2358
2359        pub fn switch_jdbc_pg_to_native() -> bool {
2360            false
2361        }
2362
2363        pub fn streaming_hash_join_entry_state_max_rows() -> usize {
2364            // NOTE(kwannoel): This is just an arbitrary number.
2365            30000
2366        }
2367
2368        pub fn enable_explain_analyze_stats() -> bool {
2369            true
2370        }
2371
2372        pub fn rpc_client_connect_timeout_secs() -> u64 {
2373            5
2374        }
2375
2376        pub fn iceberg_list_interval_sec() -> u64 {
2377            1
2378        }
2379
2380        pub fn iceberg_fetch_batch_size() -> u64 {
2381            1024
2382        }
2383
2384        pub fn iceberg_sink_positional_delete_cache_size() -> usize {
2385            1024
2386        }
2387    }
2388
2389    pub use crate::system_param::default as system;
2390
2391    pub mod batch {
2392        pub fn enable_barrier_read() -> bool {
2393            false
2394        }
2395
2396        pub fn enable_spill() -> bool {
2397            true
2398        }
2399
2400        pub fn statement_timeout_in_sec() -> u32 {
2401            // 1 hour
2402            60 * 60
2403        }
2404
2405        pub fn frontend_compute_runtime_worker_threads() -> usize {
2406            4
2407        }
2408
2409        pub fn mask_worker_temporary_secs() -> usize {
2410            30
2411        }
2412
2413        pub fn redact_sql_option_keywords() -> Vec<String> {
2414            [
2415                "credential",
2416                "key",
2417                "password",
2418                "private",
2419                "secret",
2420                "token",
2421            ]
2422            .into_iter()
2423            .map(str::to_string)
2424            .collect()
2425        }
2426    }
2427
2428    pub mod frontend {
2429        pub fn max_total_query_size_bytes() -> u64 {
2430            1024 * 1024 * 1024
2431        }
2432
2433        pub fn min_single_query_size_bytes() -> u64 {
2434            1024 * 1024
2435        }
2436
2437        pub fn max_single_query_size_bytes() -> u64 {
2438            1024 * 1024 * 1024
2439        }
2440    }
2441
2442    pub mod udf {
2443        pub fn enable_embedded_python_udf() -> bool {
2444            false
2445        }
2446
2447        pub fn enable_embedded_javascript_udf() -> bool {
2448            true
2449        }
2450
2451        pub fn enable_embedded_wasm_udf() -> bool {
2452            true
2453        }
2454    }
2455
2456    pub mod compaction_config {
2457        const MB: u64 = 1024 * 1024;
2458        const GB: u64 = 1024 * 1024 * 1024;
2459        const DEFAULT_MAX_COMPACTION_BYTES: u64 = 2 * GB; // 2GB
2460        const DEFAULT_MIN_COMPACTION_BYTES: u64 = 128 * MB; // 128MB
2461        const DEFAULT_MAX_BYTES_FOR_LEVEL_BASE: u64 = 512 * MB; // 512MB
2462
2463        // decrease this configure when the generation of checkpoint barrier is not frequent.
2464        const DEFAULT_TIER_COMPACT_TRIGGER_NUMBER: u64 = 12;
2465        const DEFAULT_TARGET_FILE_SIZE_BASE: u64 = 32 * MB;
2466        // 32MB
2467        const DEFAULT_MAX_SUB_COMPACTION: u32 = 4;
2468        const DEFAULT_LEVEL_MULTIPLIER: u64 = 5;
2469        const DEFAULT_MAX_SPACE_RECLAIM_BYTES: u64 = 512 * MB; // 512MB;
2470        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_SUB_LEVEL_NUMBER: u64 = 300;
2471        const DEFAULT_MAX_COMPACTION_FILE_COUNT: u64 = 100;
2472        const DEFAULT_MIN_SUB_LEVEL_COMPACT_LEVEL_COUNT: u32 = 3;
2473        const DEFAULT_MIN_OVERLAPPING_SUB_LEVEL_COMPACT_LEVEL_COUNT: u32 = 12;
2474        const DEFAULT_TOMBSTONE_RATIO_PERCENT: u32 = 40;
2475        const DEFAULT_EMERGENCY_PICKER: bool = true;
2476        const DEFAULT_MAX_LEVEL: u32 = 6;
2477        const DEFAULT_MAX_L0_COMPACT_LEVEL_COUNT: u32 = 42;
2478        const DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MIN_SIZE: u64 = 4 * MB;
2479        const DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MAX_COUNT: u32 = 64;
2480        const DEFAULT_EMERGENCY_LEVEL0_SST_FILE_COUNT: u32 = 2000; // > 50G / 32M = 1600
2481        const DEFAULT_EMERGENCY_LEVEL0_SUB_LEVEL_PARTITION: u32 = 256;
2482        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SST_COUNT: u32 = 10000; // 10000 * 32M = 320G
2483        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SIZE: u64 = 300 * 1024 * MB; // 300GB
2484
2485        use crate::catalog::hummock::CompactionFilterFlag;
2486
2487        pub fn max_bytes_for_level_base() -> u64 {
2488            DEFAULT_MAX_BYTES_FOR_LEVEL_BASE
2489        }
2490
2491        pub fn max_bytes_for_level_multiplier() -> u64 {
2492            DEFAULT_LEVEL_MULTIPLIER
2493        }
2494
2495        pub fn max_compaction_bytes() -> u64 {
2496            DEFAULT_MAX_COMPACTION_BYTES
2497        }
2498
2499        pub fn sub_level_max_compaction_bytes() -> u64 {
2500            DEFAULT_MIN_COMPACTION_BYTES
2501        }
2502
2503        pub fn level0_tier_compact_file_number() -> u64 {
2504            DEFAULT_TIER_COMPACT_TRIGGER_NUMBER
2505        }
2506
2507        pub fn target_file_size_base() -> u64 {
2508            DEFAULT_TARGET_FILE_SIZE_BASE
2509        }
2510
2511        pub fn compaction_filter_mask() -> u32 {
2512            (CompactionFilterFlag::STATE_CLEAN | CompactionFilterFlag::TTL).into()
2513        }
2514
2515        pub fn max_sub_compaction() -> u32 {
2516            DEFAULT_MAX_SUB_COMPACTION
2517        }
2518
2519        pub fn level0_stop_write_threshold_sub_level_number() -> u64 {
2520            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_SUB_LEVEL_NUMBER
2521        }
2522
2523        pub fn level0_sub_level_compact_level_count() -> u32 {
2524            DEFAULT_MIN_SUB_LEVEL_COMPACT_LEVEL_COUNT
2525        }
2526
2527        pub fn level0_overlapping_sub_level_compact_level_count() -> u32 {
2528            DEFAULT_MIN_OVERLAPPING_SUB_LEVEL_COMPACT_LEVEL_COUNT
2529        }
2530
2531        pub fn max_space_reclaim_bytes() -> u64 {
2532            DEFAULT_MAX_SPACE_RECLAIM_BYTES
2533        }
2534
2535        pub fn level0_max_compact_file_number() -> u64 {
2536            DEFAULT_MAX_COMPACTION_FILE_COUNT
2537        }
2538
2539        pub fn tombstone_reclaim_ratio() -> u32 {
2540            DEFAULT_TOMBSTONE_RATIO_PERCENT
2541        }
2542
2543        pub fn enable_emergency_picker() -> bool {
2544            DEFAULT_EMERGENCY_PICKER
2545        }
2546
2547        pub fn max_level() -> u32 {
2548            DEFAULT_MAX_LEVEL
2549        }
2550
2551        pub fn max_l0_compact_level_count() -> u32 {
2552            DEFAULT_MAX_L0_COMPACT_LEVEL_COUNT
2553        }
2554
2555        pub fn sst_allowed_trivial_move_min_size() -> u64 {
2556            DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MIN_SIZE
2557        }
2558
2559        pub fn disable_auto_group_scheduling() -> bool {
2560            false
2561        }
2562
2563        pub fn max_overlapping_level_size() -> u64 {
2564            256 * MB
2565        }
2566
2567        pub fn sst_allowed_trivial_move_max_count() -> u32 {
2568            DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MAX_COUNT
2569        }
2570
2571        pub fn emergency_level0_sst_file_count() -> u32 {
2572            DEFAULT_EMERGENCY_LEVEL0_SST_FILE_COUNT
2573        }
2574
2575        pub fn emergency_level0_sub_level_partition() -> u32 {
2576            DEFAULT_EMERGENCY_LEVEL0_SUB_LEVEL_PARTITION
2577        }
2578
2579        pub fn level0_stop_write_threshold_max_sst_count() -> u32 {
2580            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SST_COUNT
2581        }
2582
2583        pub fn level0_stop_write_threshold_max_size() -> u64 {
2584            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SIZE
2585        }
2586
2587        pub fn enable_optimize_l0_interval_selection() -> bool {
2588            false
2589        }
2590    }
2591
2592    pub mod object_store_config {
2593        const DEFAULT_REQ_BACKOFF_INTERVAL_MS: u64 = 1000; // 1s
2594        const DEFAULT_REQ_BACKOFF_MAX_DELAY_MS: u64 = 10 * 1000; // 10s
2595        const DEFAULT_REQ_MAX_RETRY_ATTEMPTS: usize = 3;
2596
2597        pub fn set_atomic_write_dir() -> bool {
2598            false
2599        }
2600
2601        pub fn object_store_req_backoff_interval_ms() -> u64 {
2602            DEFAULT_REQ_BACKOFF_INTERVAL_MS
2603        }
2604
2605        pub fn object_store_req_backoff_max_delay_ms() -> u64 {
2606            DEFAULT_REQ_BACKOFF_MAX_DELAY_MS // 10s
2607        }
2608
2609        pub fn object_store_req_backoff_factor() -> u64 {
2610            2
2611        }
2612
2613        pub fn object_store_upload_attempt_timeout_ms() -> u64 {
2614            8 * 1000 // 8s
2615        }
2616
2617        pub fn object_store_upload_retry_attempts() -> usize {
2618            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2619        }
2620
2621        // init + upload_part + finish
2622        pub fn object_store_streaming_upload_attempt_timeout_ms() -> u64 {
2623            5 * 1000 // 5s
2624        }
2625
2626        pub fn object_store_streaming_upload_retry_attempts() -> usize {
2627            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2628        }
2629
2630        // tips: depend on block_size
2631        pub fn object_store_read_attempt_timeout_ms() -> u64 {
2632            8 * 1000 // 8s
2633        }
2634
2635        pub fn object_store_read_retry_attempts() -> usize {
2636            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2637        }
2638
2639        pub fn object_store_streaming_read_attempt_timeout_ms() -> u64 {
2640            3 * 1000 // 3s
2641        }
2642
2643        pub fn object_store_streaming_read_retry_attempts() -> usize {
2644            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2645        }
2646
2647        pub fn object_store_metadata_attempt_timeout_ms() -> u64 {
2648            60 * 1000 // 1min
2649        }
2650
2651        pub fn object_store_metadata_retry_attempts() -> usize {
2652            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2653        }
2654
2655        pub fn object_store_delete_attempt_timeout_ms() -> u64 {
2656            5 * 1000
2657        }
2658
2659        pub fn object_store_delete_retry_attempts() -> usize {
2660            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2661        }
2662
2663        // tips: depend on batch size
2664        pub fn object_store_delete_objects_attempt_timeout_ms() -> u64 {
2665            5 * 1000
2666        }
2667
2668        pub fn object_store_delete_objects_retry_attempts() -> usize {
2669            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2670        }
2671
2672        pub fn object_store_list_attempt_timeout_ms() -> u64 {
2673            10 * 60 * 1000
2674        }
2675
2676        pub fn object_store_list_retry_attempts() -> usize {
2677            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2678        }
2679
2680        pub fn opendal_upload_concurrency() -> usize {
2681            256
2682        }
2683
2684        pub fn upload_part_size() -> usize {
2685            // 16m
2686            16 * 1024 * 1024
2687        }
2688
2689        pub mod s3 {
2690            const DEFAULT_IDENTITY_RESOLUTION_TIMEOUT_S: u64 = 5;
2691
2692            const DEFAULT_KEEPALIVE_MS: u64 = 600 * 1000; // 10min
2693
2694            pub fn keepalive_ms() -> Option<u64> {
2695                Some(DEFAULT_KEEPALIVE_MS) // 10min
2696            }
2697
2698            pub fn recv_buffer_size() -> Option<usize> {
2699                Some(1 << 21) // 2m
2700            }
2701
2702            pub fn send_buffer_size() -> Option<usize> {
2703                None
2704            }
2705
2706            pub fn nodelay() -> Option<bool> {
2707                Some(true)
2708            }
2709
2710            pub fn identity_resolution_timeout_s() -> u64 {
2711                DEFAULT_IDENTITY_RESOLUTION_TIMEOUT_S
2712            }
2713
2714            pub mod developer {
2715                pub fn retry_unknown_service_error() -> bool {
2716                    false
2717                }
2718
2719                pub fn retryable_service_error_codes() -> Vec<String> {
2720                    vec!["SlowDown".into(), "TooManyRequests".into()]
2721                }
2722
2723                pub fn use_opendal() -> bool {
2724                    true
2725                }
2726            }
2727        }
2728    }
2729
2730    pub mod meta_store_config {
2731        const DEFAULT_MAX_CONNECTIONS: u32 = 10;
2732        const DEFAULT_MIN_CONNECTIONS: u32 = 1;
2733        const DEFAULT_CONNECTION_TIMEOUT_SEC: u64 = 10;
2734        const DEFAULT_IDLE_TIMEOUT_SEC: u64 = 30;
2735        const DEFAULT_ACQUIRE_TIMEOUT_SEC: u64 = 30;
2736
2737        pub fn max_connections() -> u32 {
2738            DEFAULT_MAX_CONNECTIONS
2739        }
2740
2741        pub fn min_connections() -> u32 {
2742            DEFAULT_MIN_CONNECTIONS
2743        }
2744
2745        pub fn connection_timeout_sec() -> u64 {
2746            DEFAULT_CONNECTION_TIMEOUT_SEC
2747        }
2748
2749        pub fn idle_timeout_sec() -> u64 {
2750            DEFAULT_IDLE_TIMEOUT_SEC
2751        }
2752
2753        pub fn acquire_timeout_sec() -> u64 {
2754            DEFAULT_ACQUIRE_TIMEOUT_SEC
2755        }
2756    }
2757}
2758
2759#[derive(Debug, Clone)]
2760pub enum EvictionConfig {
2761    Lru(LruConfig),
2762    Lfu(LfuConfig),
2763    S3Fifo(S3FifoConfig),
2764}
2765
2766impl EvictionConfig {
2767    pub fn for_test() -> Self {
2768        Self::Lru(LruConfig {
2769            high_priority_pool_ratio: 0.0,
2770        })
2771    }
2772}
2773
2774impl From<EvictionConfig> for foyer::EvictionConfig {
2775    fn from(value: EvictionConfig) -> Self {
2776        match value {
2777            EvictionConfig::Lru(lru) => foyer::EvictionConfig::Lru(lru),
2778            EvictionConfig::Lfu(lfu) => foyer::EvictionConfig::Lfu(lfu),
2779            EvictionConfig::S3Fifo(s3fifo) => foyer::EvictionConfig::S3Fifo(s3fifo),
2780        }
2781    }
2782}
2783
2784pub struct StorageMemoryConfig {
2785    pub block_cache_capacity_mb: usize,
2786    pub block_cache_shard_num: usize,
2787    pub meta_cache_capacity_mb: usize,
2788    pub meta_cache_shard_num: usize,
2789    pub shared_buffer_capacity_mb: usize,
2790    pub compactor_memory_limit_mb: usize,
2791    pub prefetch_buffer_capacity_mb: usize,
2792    pub block_cache_eviction_config: EvictionConfig,
2793    pub meta_cache_eviction_config: EvictionConfig,
2794    pub block_file_cache_flush_buffer_threshold_mb: usize,
2795    pub meta_file_cache_flush_buffer_threshold_mb: usize,
2796}
2797
2798pub const MAX_META_CACHE_SHARD_BITS: usize = 4;
2799pub const MIN_BUFFER_SIZE_PER_SHARD: usize = 256;
2800pub const MAX_BLOCK_CACHE_SHARD_BITS: usize = 6; // It means that there will be 64 shards lru-cache to avoid lock conflict.
2801
2802pub fn extract_storage_memory_config(s: &RwConfig) -> StorageMemoryConfig {
2803    let block_cache_capacity_mb = s.storage.cache.block_cache_capacity_mb.unwrap_or(
2804        // adapt to old version
2805        s.storage
2806            .block_cache_capacity_mb
2807            .unwrap_or(default::storage::block_cache_capacity_mb()),
2808    );
2809    let meta_cache_capacity_mb = s.storage.cache.meta_cache_capacity_mb.unwrap_or(
2810        // adapt to old version
2811        s.storage
2812            .block_cache_capacity_mb
2813            .unwrap_or(default::storage::meta_cache_capacity_mb()),
2814    );
2815    let shared_buffer_capacity_mb = s
2816        .storage
2817        .shared_buffer_capacity_mb
2818        .unwrap_or(default::storage::shared_buffer_capacity_mb());
2819    let meta_cache_shard_num = s.storage.cache.meta_cache_shard_num.unwrap_or_else(|| {
2820        let mut shard_bits = MAX_META_CACHE_SHARD_BITS;
2821        while (meta_cache_capacity_mb >> shard_bits) < MIN_BUFFER_SIZE_PER_SHARD && shard_bits > 0 {
2822            shard_bits -= 1;
2823        }
2824        shard_bits
2825    });
2826    let block_cache_shard_num = s.storage.cache.block_cache_shard_num.unwrap_or_else(|| {
2827        let mut shard_bits = MAX_BLOCK_CACHE_SHARD_BITS;
2828        while (block_cache_capacity_mb >> shard_bits) < MIN_BUFFER_SIZE_PER_SHARD && shard_bits > 0
2829        {
2830            shard_bits -= 1;
2831        }
2832        shard_bits
2833    });
2834    let compactor_memory_limit_mb = s
2835        .storage
2836        .compactor_memory_limit_mb
2837        .unwrap_or(default::storage::compactor_memory_limit_mb());
2838
2839    let get_eviction_config = |c: &CacheEvictionConfig| {
2840        match c {
2841            CacheEvictionConfig::Lru {
2842                high_priority_ratio_in_percent,
2843            } => EvictionConfig::Lru(LruConfig {
2844                high_priority_pool_ratio: high_priority_ratio_in_percent.unwrap_or(
2845                    // adapt to old version
2846                    s.storage
2847                        .high_priority_ratio_in_percent
2848                        .unwrap_or(default::storage::high_priority_ratio_in_percent()),
2849                ) as f64
2850                    / 100.0,
2851            }),
2852            CacheEvictionConfig::Lfu {
2853                window_capacity_ratio_in_percent,
2854                protected_capacity_ratio_in_percent,
2855                cmsketch_eps,
2856                cmsketch_confidence,
2857            } => EvictionConfig::Lfu(LfuConfig {
2858                window_capacity_ratio: window_capacity_ratio_in_percent
2859                    .unwrap_or(default::storage::window_capacity_ratio_in_percent())
2860                    as f64
2861                    / 100.0,
2862                protected_capacity_ratio: protected_capacity_ratio_in_percent
2863                    .unwrap_or(default::storage::protected_capacity_ratio_in_percent())
2864                    as f64
2865                    / 100.0,
2866                cmsketch_eps: cmsketch_eps.unwrap_or(default::storage::cmsketch_eps()),
2867                cmsketch_confidence: cmsketch_confidence
2868                    .unwrap_or(default::storage::cmsketch_confidence()),
2869            }),
2870            CacheEvictionConfig::S3Fifo {
2871                small_queue_capacity_ratio_in_percent,
2872                ghost_queue_capacity_ratio_in_percent,
2873                small_to_main_freq_threshold,
2874            } => EvictionConfig::S3Fifo(S3FifoConfig {
2875                small_queue_capacity_ratio: small_queue_capacity_ratio_in_percent
2876                    .unwrap_or(default::storage::small_queue_capacity_ratio_in_percent())
2877                    as f64
2878                    / 100.0,
2879                ghost_queue_capacity_ratio: ghost_queue_capacity_ratio_in_percent
2880                    .unwrap_or(default::storage::ghost_queue_capacity_ratio_in_percent())
2881                    as f64
2882                    / 100.0,
2883                small_to_main_freq_threshold: small_to_main_freq_threshold
2884                    .unwrap_or(default::storage::small_to_main_freq_threshold()),
2885            }),
2886        }
2887    };
2888
2889    let block_cache_eviction_config = get_eviction_config(&s.storage.cache.block_cache_eviction);
2890    let meta_cache_eviction_config = get_eviction_config(&s.storage.cache.meta_cache_eviction);
2891
2892    let prefetch_buffer_capacity_mb =
2893        s.storage
2894            .shared_buffer_capacity_mb
2895            .unwrap_or(match &block_cache_eviction_config {
2896                EvictionConfig::Lru(lru) => {
2897                    ((1.0 - lru.high_priority_pool_ratio) * block_cache_capacity_mb as f64) as usize
2898                }
2899                EvictionConfig::Lfu(lfu) => {
2900                    ((1.0 - lfu.protected_capacity_ratio) * block_cache_capacity_mb as f64) as usize
2901                }
2902                EvictionConfig::S3Fifo(s3fifo) => {
2903                    (s3fifo.small_queue_capacity_ratio * block_cache_capacity_mb as f64) as usize
2904                }
2905            });
2906
2907    let block_file_cache_flush_buffer_threshold_mb = s
2908        .storage
2909        .data_file_cache
2910        .flush_buffer_threshold_mb
2911        .unwrap_or(default::storage::block_file_cache_flush_buffer_threshold_mb());
2912    let meta_file_cache_flush_buffer_threshold_mb = s
2913        .storage
2914        .meta_file_cache
2915        .flush_buffer_threshold_mb
2916        .unwrap_or(default::storage::block_file_cache_flush_buffer_threshold_mb());
2917
2918    StorageMemoryConfig {
2919        block_cache_capacity_mb,
2920        block_cache_shard_num,
2921        meta_cache_capacity_mb,
2922        meta_cache_shard_num,
2923        shared_buffer_capacity_mb,
2924        compactor_memory_limit_mb,
2925        prefetch_buffer_capacity_mb,
2926        block_cache_eviction_config,
2927        meta_cache_eviction_config,
2928        block_file_cache_flush_buffer_threshold_mb,
2929        meta_file_cache_flush_buffer_threshold_mb,
2930    }
2931}
2932
2933#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
2934pub struct CompactionConfig {
2935    #[serde(default = "default::compaction_config::max_bytes_for_level_base")]
2936    pub max_bytes_for_level_base: u64,
2937    #[serde(default = "default::compaction_config::max_bytes_for_level_multiplier")]
2938    pub max_bytes_for_level_multiplier: u64,
2939    #[serde(default = "default::compaction_config::max_compaction_bytes")]
2940    pub max_compaction_bytes: u64,
2941    #[serde(default = "default::compaction_config::sub_level_max_compaction_bytes")]
2942    pub sub_level_max_compaction_bytes: u64,
2943    #[serde(default = "default::compaction_config::level0_tier_compact_file_number")]
2944    pub level0_tier_compact_file_number: u64,
2945    #[serde(default = "default::compaction_config::target_file_size_base")]
2946    pub target_file_size_base: u64,
2947    #[serde(default = "default::compaction_config::compaction_filter_mask")]
2948    pub compaction_filter_mask: u32,
2949    #[serde(default = "default::compaction_config::max_sub_compaction")]
2950    pub max_sub_compaction: u32,
2951    #[serde(default = "default::compaction_config::level0_stop_write_threshold_sub_level_number")]
2952    pub level0_stop_write_threshold_sub_level_number: u64,
2953    #[serde(default = "default::compaction_config::level0_sub_level_compact_level_count")]
2954    pub level0_sub_level_compact_level_count: u32,
2955    #[serde(
2956        default = "default::compaction_config::level0_overlapping_sub_level_compact_level_count"
2957    )]
2958    pub level0_overlapping_sub_level_compact_level_count: u32,
2959    #[serde(default = "default::compaction_config::max_space_reclaim_bytes")]
2960    pub max_space_reclaim_bytes: u64,
2961    #[serde(default = "default::compaction_config::level0_max_compact_file_number")]
2962    pub level0_max_compact_file_number: u64,
2963    #[serde(default = "default::compaction_config::tombstone_reclaim_ratio")]
2964    pub tombstone_reclaim_ratio: u32,
2965    #[serde(default = "default::compaction_config::enable_emergency_picker")]
2966    pub enable_emergency_picker: bool,
2967    #[serde(default = "default::compaction_config::max_level")]
2968    pub max_level: u32,
2969    #[serde(default = "default::compaction_config::sst_allowed_trivial_move_min_size")]
2970    pub sst_allowed_trivial_move_min_size: u64,
2971    #[serde(default = "default::compaction_config::sst_allowed_trivial_move_max_count")]
2972    pub sst_allowed_trivial_move_max_count: u32,
2973    #[serde(default = "default::compaction_config::max_l0_compact_level_count")]
2974    pub max_l0_compact_level_count: u32,
2975    #[serde(default = "default::compaction_config::disable_auto_group_scheduling")]
2976    pub disable_auto_group_scheduling: bool,
2977    #[serde(default = "default::compaction_config::max_overlapping_level_size")]
2978    pub max_overlapping_level_size: u64,
2979    #[serde(default = "default::compaction_config::emergency_level0_sst_file_count")]
2980    pub emergency_level0_sst_file_count: u32,
2981    #[serde(default = "default::compaction_config::emergency_level0_sub_level_partition")]
2982    pub emergency_level0_sub_level_partition: u32,
2983    #[serde(default = "default::compaction_config::level0_stop_write_threshold_max_sst_count")]
2984    pub level0_stop_write_threshold_max_sst_count: u32,
2985    #[serde(default = "default::compaction_config::level0_stop_write_threshold_max_size")]
2986    pub level0_stop_write_threshold_max_size: u64,
2987    #[serde(default = "default::compaction_config::enable_optimize_l0_interval_selection")]
2988    pub enable_optimize_l0_interval_selection: bool,
2989}
2990
2991/// Note: only applies to meta store backends other than `SQLite`.
2992#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
2993pub struct MetaStoreConfig {
2994    /// Maximum number of connections for the meta store connection pool.
2995    #[serde(default = "default::meta_store_config::max_connections")]
2996    pub max_connections: u32,
2997    /// Minimum number of connections for the meta store connection pool.
2998    #[serde(default = "default::meta_store_config::min_connections")]
2999    pub min_connections: u32,
3000    /// Connection timeout in seconds for a meta store connection.
3001    #[serde(default = "default::meta_store_config::connection_timeout_sec")]
3002    pub connection_timeout_sec: u64,
3003    /// Idle timeout in seconds for a meta store connection.
3004    #[serde(default = "default::meta_store_config::idle_timeout_sec")]
3005    pub idle_timeout_sec: u64,
3006    /// Acquire timeout in seconds for a meta store connection.
3007    #[serde(default = "default::meta_store_config::acquire_timeout_sec")]
3008    pub acquire_timeout_sec: u64,
3009}
3010
3011#[cfg(test)]
3012mod tests {
3013    use risingwave_license::LicenseKey;
3014
3015    use super::*;
3016
3017    fn default_config_for_docs() -> RwConfig {
3018        let mut config = RwConfig::default();
3019        // Set `license_key` to empty in the docs to avoid any confusion.
3020        config.system.license_key = Some(LicenseKey::empty());
3021        config
3022    }
3023
3024    /// This test ensures that `config/example.toml` is up-to-date with the default values specified
3025    /// in this file. Developer should run `./risedev generate-example-config` to update it if this
3026    /// test fails.
3027    #[test]
3028    fn test_example_up_to_date() {
3029        const HEADER: &str = "# This file is generated by ./risedev generate-example-config
3030# Check detailed comments in src/common/src/config.rs";
3031
3032        let actual = expect_test::expect_file!["../../config/example.toml"];
3033        let default = toml::to_string(&default_config_for_docs()).expect("failed to serialize");
3034
3035        let expected = format!("{HEADER}\n\n{default}");
3036        actual.assert_eq(&expected);
3037
3038        let expected = rw_config_to_markdown();
3039        let actual = expect_test::expect_file!["../../config/docs.md"];
3040        actual.assert_eq(&expected);
3041    }
3042
3043    #[derive(Debug)]
3044    struct ConfigItemDoc {
3045        desc: String,
3046        default: String,
3047    }
3048
3049    fn rw_config_to_markdown() -> String {
3050        let mut config_rustdocs = BTreeMap::<String, Vec<(String, String)>>::new();
3051        RwConfig::config_docs("".to_owned(), &mut config_rustdocs);
3052
3053        // Section -> Config Name -> ConfigItemDoc
3054        let mut configs: BTreeMap<String, BTreeMap<String, ConfigItemDoc>> = config_rustdocs
3055            .into_iter()
3056            .map(|(k, v)| {
3057                let docs: BTreeMap<String, ConfigItemDoc> = v
3058                    .into_iter()
3059                    .map(|(name, desc)| {
3060                        (
3061                            name,
3062                            ConfigItemDoc {
3063                                desc,
3064                                default: "".to_owned(), // unset
3065                            },
3066                        )
3067                    })
3068                    .collect();
3069                (k, docs)
3070            })
3071            .collect();
3072
3073        let toml_doc: BTreeMap<String, toml::Value> =
3074            toml::from_str(&toml::to_string(&default_config_for_docs()).unwrap()).unwrap();
3075        toml_doc.into_iter().for_each(|(name, value)| {
3076            set_default_values("".to_owned(), name, value, &mut configs);
3077        });
3078
3079        let mut markdown = "# RisingWave System Configurations\n\n".to_owned()
3080            + "This page is automatically generated by `./risedev generate-example-config`\n";
3081        for (section, configs) in configs {
3082            if configs.is_empty() {
3083                continue;
3084            }
3085            markdown.push_str(&format!("\n## {}\n\n", section));
3086            markdown.push_str("| Config | Description | Default |\n");
3087            markdown.push_str("|--------|-------------|---------|\n");
3088            for (config, doc) in configs {
3089                markdown.push_str(&format!(
3090                    "| {} | {} | {} |\n",
3091                    config, doc.desc, doc.default
3092                ));
3093            }
3094        }
3095        markdown
3096    }
3097
3098    fn set_default_values(
3099        section: String,
3100        name: String,
3101        value: toml::Value,
3102        configs: &mut BTreeMap<String, BTreeMap<String, ConfigItemDoc>>,
3103    ) {
3104        // Set the default value if it's a config name-value pair, otherwise it's a sub-section (Table) that should be recursively processed.
3105        if let toml::Value::Table(table) = value {
3106            let section_configs: BTreeMap<String, toml::Value> =
3107                table.clone().into_iter().collect();
3108            let sub_section = if section.is_empty() {
3109                name
3110            } else {
3111                format!("{}.{}", section, name)
3112            };
3113            section_configs
3114                .into_iter()
3115                .for_each(|(k, v)| set_default_values(sub_section.clone(), k, v, configs))
3116        } else if let Some(t) = configs.get_mut(&section) {
3117            if let Some(item_doc) = t.get_mut(&name) {
3118                item_doc.default = format!("{}", value);
3119            }
3120        }
3121    }
3122
3123    #[test]
3124    fn test_object_store_configs_backward_compatibility() {
3125        // Define configs with the old name and make sure it still works
3126        {
3127            let config: RwConfig = toml::from_str(
3128                r#"
3129            [storage.object_store]
3130            object_store_set_atomic_write_dir = true
3131
3132            [storage.object_store.s3]
3133            object_store_keepalive_ms = 1
3134            object_store_send_buffer_size = 1
3135            object_store_recv_buffer_size = 1
3136            object_store_nodelay = false
3137
3138            [storage.object_store.s3.developer]
3139            object_store_retry_unknown_service_error = true
3140            object_store_retryable_service_error_codes = ['dummy']
3141
3142
3143            "#,
3144            )
3145            .unwrap();
3146
3147            assert!(config.storage.object_store.set_atomic_write_dir);
3148            assert_eq!(config.storage.object_store.s3.keepalive_ms, Some(1));
3149            assert_eq!(config.storage.object_store.s3.send_buffer_size, Some(1));
3150            assert_eq!(config.storage.object_store.s3.recv_buffer_size, Some(1));
3151            assert_eq!(config.storage.object_store.s3.nodelay, Some(false));
3152            assert!(
3153                config
3154                    .storage
3155                    .object_store
3156                    .s3
3157                    .developer
3158                    .retry_unknown_service_error
3159            );
3160            assert_eq!(
3161                config
3162                    .storage
3163                    .object_store
3164                    .s3
3165                    .developer
3166                    .retryable_service_error_codes,
3167                vec!["dummy".to_owned()]
3168            );
3169        }
3170
3171        // Define configs with the new name and make sure it works
3172        {
3173            let config: RwConfig = toml::from_str(
3174                r#"
3175            [storage.object_store]
3176            set_atomic_write_dir = true
3177
3178            [storage.object_store.s3]
3179            keepalive_ms = 1
3180            send_buffer_size = 1
3181            recv_buffer_size = 1
3182            nodelay = false
3183
3184            [storage.object_store.s3.developer]
3185            retry_unknown_service_error = true
3186            retryable_service_error_codes = ['dummy']
3187
3188
3189            "#,
3190            )
3191            .unwrap();
3192
3193            assert!(config.storage.object_store.set_atomic_write_dir);
3194            assert_eq!(config.storage.object_store.s3.keepalive_ms, Some(1));
3195            assert_eq!(config.storage.object_store.s3.send_buffer_size, Some(1));
3196            assert_eq!(config.storage.object_store.s3.recv_buffer_size, Some(1));
3197            assert_eq!(config.storage.object_store.s3.nodelay, Some(false));
3198            assert!(
3199                config
3200                    .storage
3201                    .object_store
3202                    .s3
3203                    .developer
3204                    .retry_unknown_service_error
3205            );
3206            assert_eq!(
3207                config
3208                    .storage
3209                    .object_store
3210                    .s3
3211                    .developer
3212                    .retryable_service_error_codes,
3213                vec!["dummy".to_owned()]
3214            );
3215        }
3216    }
3217
3218    #[test]
3219    fn test_meta_configs_backward_compatibility() {
3220        // Test periodic_space_reclaim_compaction_interval_sec
3221        {
3222            let config: RwConfig = toml::from_str(
3223                r#"
3224            [meta]
3225            periodic_split_compact_group_interval_sec = 1
3226            table_write_throughput_threshold = 10
3227            min_table_split_write_throughput = 5
3228            "#,
3229            )
3230            .unwrap();
3231
3232            assert_eq!(
3233                config
3234                    .meta
3235                    .periodic_scheduling_compaction_group_split_interval_sec,
3236                1
3237            );
3238            assert_eq!(config.meta.table_high_write_throughput_threshold, 10);
3239            assert_eq!(config.meta.table_low_write_throughput_threshold, 5);
3240        }
3241    }
3242}