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
983#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
984pub struct CacheRefillConfig {
985    /// `SSTable` levels to refill.
986    #[serde(default = "default::cache_refill::data_refill_levels")]
987    pub data_refill_levels: Vec<u32>,
988
989    /// Cache refill maximum timeout to apply version delta.
990    #[serde(default = "default::cache_refill::timeout_ms")]
991    pub timeout_ms: u64,
992
993    /// Inflight data cache refill tasks.
994    #[serde(default = "default::cache_refill::concurrency")]
995    pub concurrency: usize,
996
997    /// Block count that a data cache refill request fetches.
998    #[serde(default = "default::cache_refill::unit")]
999    pub unit: usize,
1000
1001    /// Data cache refill unit admission ratio.
1002    ///
1003    /// Only unit whose blocks are admitted above the ratio will be refilled.
1004    #[serde(default = "default::cache_refill::threshold")]
1005    pub threshold: f64,
1006
1007    /// Recent filter layer count.
1008    #[serde(default = "default::cache_refill::recent_filter_layers")]
1009    pub recent_filter_layers: usize,
1010
1011    /// Recent filter layer rotate interval.
1012    #[serde(default = "default::cache_refill::recent_filter_rotate_interval_ms")]
1013    pub recent_filter_rotate_interval_ms: usize,
1014
1015    #[serde(default, flatten)]
1016    #[config_doc(omitted)]
1017    pub unrecognized: Unrecognized<Self>,
1018}
1019
1020/// The subsection `[storage.data_file_cache]` and `[storage.meta_file_cache]` in `risingwave.toml`.
1021///
1022/// It's put at [`StorageConfig::data_file_cache`] and  [`StorageConfig::meta_file_cache`].
1023#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1024pub struct FileCacheConfig {
1025    #[serde(default = "default::file_cache::dir")]
1026    pub dir: String,
1027
1028    #[serde(default = "default::file_cache::capacity_mb")]
1029    pub capacity_mb: usize,
1030
1031    #[serde(default = "default::file_cache::file_capacity_mb")]
1032    pub file_capacity_mb: usize,
1033
1034    #[serde(default = "default::file_cache::flushers")]
1035    pub flushers: usize,
1036
1037    #[serde(default = "default::file_cache::reclaimers")]
1038    pub reclaimers: usize,
1039
1040    #[serde(default = "default::file_cache::recover_concurrency")]
1041    pub recover_concurrency: usize,
1042
1043    /// Deprecated soon. Please use `throttle` to do I/O throttling instead.
1044    #[serde(default = "default::file_cache::insert_rate_limit_mb")]
1045    pub insert_rate_limit_mb: usize,
1046
1047    #[serde(default = "default::file_cache::indexer_shards")]
1048    pub indexer_shards: usize,
1049
1050    #[serde(default = "default::file_cache::compression")]
1051    pub compression: Compression,
1052
1053    #[serde(default = "default::file_cache::flush_buffer_threshold_mb")]
1054    pub flush_buffer_threshold_mb: Option<usize>,
1055
1056    #[serde(default = "default::file_cache::throttle")]
1057    pub throttle: Throttle,
1058
1059    #[serde(default = "default::file_cache::fifo_probation_ratio")]
1060    pub fifo_probation_ratio: f64,
1061
1062    /// Recover mode.
1063    ///
1064    /// Options:
1065    ///
1066    /// - "None": Do not recover disk cache.
1067    /// - "Quiet": Recover disk cache and skip errors.
1068    /// - "Strict": Recover disk cache and panic on errors.
1069    ///
1070    /// More details, see [`RecoverMode::None`], [`RecoverMode::Quiet`] and [`RecoverMode::Strict`],
1071    #[serde(default = "default::file_cache::recover_mode")]
1072    pub recover_mode: RecoverMode,
1073
1074    #[serde(default = "default::file_cache::runtime_config")]
1075    pub runtime_config: RuntimeOptions,
1076
1077    #[serde(default, flatten)]
1078    #[config_doc(omitted)]
1079    pub unrecognized: Unrecognized<Self>,
1080}
1081
1082#[derive(Debug, Default, Clone, Copy, ValueEnum, Serialize, Deserialize)]
1083pub enum AsyncStackTraceOption {
1084    /// Disabled.
1085    Off,
1086    /// Enabled with basic instruments.
1087    On,
1088    /// Enabled with extra verbose instruments in release build.
1089    /// Behaves the same as `on` in debug build due to performance concern.
1090    #[default]
1091    #[clap(alias = "verbose")]
1092    ReleaseVerbose,
1093}
1094
1095impl AsyncStackTraceOption {
1096    pub fn is_verbose(self) -> Option<bool> {
1097        match self {
1098            Self::Off => None,
1099            Self::On => Some(false),
1100            Self::ReleaseVerbose => Some(!cfg!(debug_assertions)),
1101        }
1102    }
1103}
1104
1105#[derive(Debug, Default, Clone, Copy, ValueEnum)]
1106pub enum CompactorMode {
1107    #[default]
1108    #[clap(alias = "dedicated")]
1109    Dedicated,
1110
1111    #[clap(alias = "shared")]
1112    Shared,
1113
1114    #[clap(alias = "dedicated_iceberg")]
1115    DedicatedIceberg,
1116
1117    #[clap(alias = "shared_iceberg")]
1118    SharedIceberg,
1119}
1120
1121#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1122pub struct HeapProfilingConfig {
1123    /// Enable to auto dump heap profile when memory usage is high
1124    #[serde(default = "default::heap_profiling::enable_auto")]
1125    pub enable_auto: bool,
1126
1127    /// The proportion (number between 0 and 1) of memory usage to trigger heap profile dump
1128    #[serde(default = "default::heap_profiling::threshold_auto")]
1129    pub threshold_auto: f32,
1130
1131    /// The directory to dump heap profile. If empty, the prefix in `MALLOC_CONF` will be used
1132    #[serde(default = "default::heap_profiling::dir")]
1133    pub dir: String,
1134}
1135
1136/// The subsections `[streaming.developer]`.
1137///
1138/// It is put at [`StreamingConfig::developer`].
1139#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1140pub struct StreamingDeveloperConfig {
1141    /// Set to true to enable per-executor row count metrics. This will produce a lot of timeseries
1142    /// and might affect the prometheus performance. If you only need actor input and output
1143    /// rows data, see `stream_actor_in_record_cnt` and `stream_actor_out_record_cnt` instead.
1144    #[serde(default = "default::developer::stream_enable_executor_row_count")]
1145    pub enable_executor_row_count: bool,
1146
1147    /// The capacity of the chunks in the channel that connects between `ConnectorSource` and
1148    /// `SourceExecutor`.
1149    #[serde(default = "default::developer::connector_message_buffer_size")]
1150    pub connector_message_buffer_size: usize,
1151
1152    /// Limit number of the cached entries in an extreme aggregation call.
1153    #[serde(default = "default::developer::unsafe_stream_extreme_cache_size")]
1154    pub unsafe_extreme_cache_size: usize,
1155
1156    /// The maximum size of the chunk produced by executor at a time.
1157    #[serde(default = "default::developer::stream_chunk_size")]
1158    pub chunk_size: usize,
1159
1160    /// The initial permits that a channel holds, i.e., the maximum row count can be buffered in
1161    /// the channel.
1162    #[serde(default = "default::developer::stream_exchange_initial_permits")]
1163    pub exchange_initial_permits: usize,
1164
1165    /// The permits that are batched to add back, for reducing the backward `AddPermits` messages
1166    /// in remote exchange.
1167    #[serde(default = "default::developer::stream_exchange_batched_permits")]
1168    pub exchange_batched_permits: usize,
1169
1170    /// The maximum number of concurrent barriers in an exchange channel.
1171    #[serde(default = "default::developer::stream_exchange_concurrent_barriers")]
1172    pub exchange_concurrent_barriers: usize,
1173
1174    /// The concurrency for dispatching messages to different downstream jobs.
1175    ///
1176    /// - `1` means no concurrency, i.e., dispatch messages to downstream jobs one by one.
1177    /// - `0` means unlimited concurrency.
1178    #[serde(default = "default::developer::stream_exchange_concurrent_dispatchers")]
1179    pub exchange_concurrent_dispatchers: usize,
1180
1181    /// The initial permits for a dml channel, i.e., the maximum row count can be buffered in
1182    /// the channel.
1183    #[serde(default = "default::developer::stream_dml_channel_initial_permits")]
1184    pub dml_channel_initial_permits: usize,
1185
1186    /// The max heap size of dirty groups of `HashAggExecutor`.
1187    #[serde(default = "default::developer::stream_hash_agg_max_dirty_groups_heap_size")]
1188    pub hash_agg_max_dirty_groups_heap_size: usize,
1189
1190    #[serde(default = "default::developer::memory_controller_threshold_aggressive")]
1191    pub memory_controller_threshold_aggressive: f64,
1192
1193    #[serde(default = "default::developer::memory_controller_threshold_graceful")]
1194    pub memory_controller_threshold_graceful: f64,
1195
1196    #[serde(default = "default::developer::memory_controller_threshold_stable")]
1197    pub memory_controller_threshold_stable: f64,
1198
1199    #[serde(default = "default::developer::memory_controller_eviction_factor_aggressive")]
1200    pub memory_controller_eviction_factor_aggressive: f64,
1201
1202    #[serde(default = "default::developer::memory_controller_eviction_factor_graceful")]
1203    pub memory_controller_eviction_factor_graceful: f64,
1204
1205    #[serde(default = "default::developer::memory_controller_eviction_factor_stable")]
1206    pub memory_controller_eviction_factor_stable: f64,
1207
1208    #[serde(default = "default::developer::memory_controller_update_interval_ms")]
1209    pub memory_controller_update_interval_ms: usize,
1210
1211    #[serde(default = "default::developer::memory_controller_sequence_tls_step")]
1212    pub memory_controller_sequence_tls_step: u64,
1213
1214    #[serde(default = "default::developer::memory_controller_sequence_tls_lag")]
1215    pub memory_controller_sequence_tls_lag: u64,
1216
1217    #[serde(default = "default::developer::stream_enable_arrangement_backfill")]
1218    /// Enable arrangement backfill
1219    /// If false, the arrangement backfill will be disabled,
1220    /// even if session variable set.
1221    /// If true, it's decided by session variable `streaming_use_arrangement_backfill` (default true)
1222    pub enable_arrangement_backfill: bool,
1223
1224    #[serde(default = "default::developer::stream_high_join_amplification_threshold")]
1225    /// If number of hash join matches exceeds this threshold number,
1226    /// it will be logged.
1227    pub high_join_amplification_threshold: usize,
1228
1229    /// Actor tokio metrics is enabled if `enable_actor_tokio_metrics` is set or metrics level >= Debug.
1230    #[serde(default = "default::developer::enable_actor_tokio_metrics")]
1231    pub enable_actor_tokio_metrics: bool,
1232
1233    /// The number of the connections for streaming remote exchange between two nodes.
1234    /// If not specified, the value of `server.connection_pool_size` will be used.
1235    #[serde(default = "default::developer::stream_exchange_connection_pool_size")]
1236    pub exchange_connection_pool_size: Option<u16>,
1237
1238    /// A flag to allow disabling the auto schema change handling
1239    #[serde(default = "default::developer::stream_enable_auto_schema_change")]
1240    pub enable_auto_schema_change: bool,
1241
1242    #[serde(default = "default::developer::enable_shared_source")]
1243    /// Enable shared source
1244    /// If false, the shared source will be disabled,
1245    /// even if session variable set.
1246    /// If true, it's decided by session variable `streaming_use_shared_source` (default true)
1247    pub enable_shared_source: bool,
1248
1249    #[serde(default = "default::developer::switch_jdbc_pg_to_native")]
1250    /// When true, all jdbc sinks with connector='jdbc' and jdbc.url="jdbc:postgresql://..."
1251    /// will be switched from jdbc postgresql sinks to rust native (connector='postgres') sinks.
1252    pub switch_jdbc_pg_to_native: bool,
1253
1254    /// The maximum number of consecutive barriers allowed in a message when sent between actors.
1255    #[serde(default = "default::developer::stream_max_barrier_batch_size")]
1256    pub max_barrier_batch_size: u32,
1257
1258    /// Configure the system-wide cache row cardinality of hash join.
1259    /// For example, if this is set to 1000, it means we can have at most 1000 rows in cache.
1260    #[serde(default = "default::developer::streaming_hash_join_entry_state_max_rows")]
1261    pub hash_join_entry_state_max_rows: usize,
1262
1263    /// Enable / Disable profiling stats used by `EXPLAIN ANALYZE`
1264    #[serde(default = "default::developer::enable_explain_analyze_stats")]
1265    pub enable_explain_analyze_stats: bool,
1266
1267    #[serde(default)]
1268    pub compute_client_config: RpcClientConfig,
1269
1270    /// `IcebergListExecutor`: The interval in seconds for Iceberg source to list new files.
1271    #[serde(default = "default::developer::iceberg_list_interval_sec")]
1272    pub iceberg_list_interval_sec: u64,
1273
1274    /// `IcebergFetchExecutor`: The number of files the executor will fetch concurrently in a batch.
1275    #[serde(default = "default::developer::iceberg_fetch_batch_size")]
1276    pub iceberg_fetch_batch_size: u64,
1277
1278    /// `IcebergSink`: The size of the cache for positional delete in the sink.
1279    #[serde(default = "default::developer::iceberg_sink_positional_delete_cache_size")]
1280    pub iceberg_sink_positional_delete_cache_size: usize,
1281}
1282
1283/// The subsections `[batch.developer]`.
1284///
1285/// It is put at [`BatchConfig::developer`].
1286#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1287pub struct BatchDeveloperConfig {
1288    /// The capacity of the chunks in the channel that connects between `ConnectorSource` and
1289    /// `SourceExecutor`.
1290    #[serde(default = "default::developer::connector_message_buffer_size")]
1291    pub connector_message_buffer_size: usize,
1292
1293    /// The size of the channel used for output to exchange/shuffle.
1294    #[serde(default = "default::developer::batch_output_channel_size")]
1295    pub output_channel_size: usize,
1296
1297    #[serde(default = "default::developer::batch_receiver_channel_size")]
1298    pub receiver_channel_size: usize,
1299
1300    #[serde(default = "default::developer::batch_root_stage_channel_size")]
1301    pub root_stage_channel_size: usize,
1302
1303    /// The size of a chunk produced by `RowSeqScanExecutor`
1304    #[serde(default = "default::developer::batch_chunk_size")]
1305    pub chunk_size: usize,
1306
1307    /// The number of the connections for batch remote exchange between two nodes.
1308    /// If not specified, the value of `server.connection_pool_size` will be used.
1309    #[serde(default = "default::developer::batch_exchange_connection_pool_size")]
1310    exchange_connection_pool_size: Option<u16>,
1311
1312    #[serde(default)]
1313    pub compute_client_config: RpcClientConfig,
1314
1315    #[serde(default = "default::developer::batch_local_execute_buffer_size")]
1316    pub local_execute_buffer_size: usize,
1317}
1318
1319macro_rules! define_system_config {
1320    ($({ $field:ident, $type:ty, $default:expr, $is_mutable:expr, $doc:literal, $($rest:tt)* },)*) => {
1321        paste::paste!(
1322            /// The section `[system]` in `risingwave.toml`. All these fields are used to initialize the system
1323            /// parameters persisted in Meta store. Most fields are for testing purpose only and should not be
1324            /// documented.
1325            #[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
1326            pub struct SystemConfig {
1327                $(
1328                    #[doc = $doc]
1329                    #[serde(default = "default::system::" $field "_opt")]
1330                    pub $field: Option<$type>,
1331                )*
1332            }
1333        );
1334    };
1335}
1336
1337for_all_params!(define_system_config);
1338
1339/// The subsections `[storage.object_store]`.
1340#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1341pub struct ObjectStoreConfig {
1342    // alias is for backward compatibility
1343    #[serde(
1344        default = "default::object_store_config::set_atomic_write_dir",
1345        alias = "object_store_set_atomic_write_dir"
1346    )]
1347    pub set_atomic_write_dir: bool,
1348
1349    /// Retry and timeout configuration
1350    /// Description retry strategy driven by exponential back-off
1351    /// 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.
1352    #[serde(default)]
1353    pub retry: ObjectStoreRetryConfig,
1354
1355    /// Some special configuration of S3 Backend
1356    #[serde(default)]
1357    pub s3: S3ObjectStoreConfig,
1358
1359    // TODO: the following field will be deprecated after opendal is stabilized
1360    #[serde(default = "default::object_store_config::opendal_upload_concurrency")]
1361    pub opendal_upload_concurrency: usize,
1362
1363    // TODO: the following field will be deprecated after opendal is stabilized
1364    #[serde(default)]
1365    pub opendal_writer_abort_on_err: bool,
1366
1367    #[serde(default = "default::object_store_config::upload_part_size")]
1368    pub upload_part_size: usize,
1369}
1370
1371impl ObjectStoreConfig {
1372    pub fn set_atomic_write_dir(&mut self) {
1373        self.set_atomic_write_dir = true;
1374    }
1375}
1376
1377/// The subsections `[storage.object_store.s3]`.
1378#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1379pub struct S3ObjectStoreConfig {
1380    // alias is for backward compatibility
1381    #[serde(
1382        default = "default::object_store_config::s3::keepalive_ms",
1383        alias = "object_store_keepalive_ms"
1384    )]
1385    pub keepalive_ms: Option<u64>,
1386    #[serde(
1387        default = "default::object_store_config::s3::recv_buffer_size",
1388        alias = "object_store_recv_buffer_size"
1389    )]
1390    pub recv_buffer_size: Option<usize>,
1391    #[serde(
1392        default = "default::object_store_config::s3::send_buffer_size",
1393        alias = "object_store_send_buffer_size"
1394    )]
1395    pub send_buffer_size: Option<usize>,
1396    #[serde(
1397        default = "default::object_store_config::s3::nodelay",
1398        alias = "object_store_nodelay"
1399    )]
1400    pub nodelay: Option<bool>,
1401    /// For backwards compatibility, users should use `S3ObjectStoreDeveloperConfig` instead.
1402    #[serde(default = "default::object_store_config::s3::developer::retry_unknown_service_error")]
1403    pub retry_unknown_service_error: bool,
1404    #[serde(default = "default::object_store_config::s3::identity_resolution_timeout_s")]
1405    pub identity_resolution_timeout_s: u64,
1406    #[serde(default)]
1407    pub developer: S3ObjectStoreDeveloperConfig,
1408}
1409
1410/// The subsections `[storage.object_store.s3.developer]`.
1411#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1412pub struct S3ObjectStoreDeveloperConfig {
1413    /// Whether to retry s3 sdk error from which no error metadata is provided.
1414    #[serde(
1415        default = "default::object_store_config::s3::developer::retry_unknown_service_error",
1416        alias = "object_store_retry_unknown_service_error"
1417    )]
1418    pub retry_unknown_service_error: bool,
1419    /// An array of error codes that should be retried.
1420    /// e.g. `["SlowDown", "TooManyRequests"]`
1421    #[serde(
1422        default = "default::object_store_config::s3::developer::retryable_service_error_codes",
1423        alias = "object_store_retryable_service_error_codes"
1424    )]
1425    pub retryable_service_error_codes: Vec<String>,
1426
1427    // TODO: deprecate this config when we are completely deprecate aws sdk.
1428    #[serde(default = "default::object_store_config::s3::developer::use_opendal")]
1429    pub use_opendal: bool,
1430}
1431
1432#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde)]
1433pub struct ObjectStoreRetryConfig {
1434    // A retry strategy driven by exponential back-off.
1435    // The retry strategy is used for all object store operations.
1436    /// Given a base duration for retry strategy in milliseconds.
1437    #[serde(default = "default::object_store_config::object_store_req_backoff_interval_ms")]
1438    pub req_backoff_interval_ms: u64,
1439
1440    /// The max delay interval for the retry strategy. No retry delay will be longer than this `Duration`.
1441    #[serde(default = "default::object_store_config::object_store_req_backoff_max_delay_ms")]
1442    pub req_backoff_max_delay_ms: u64,
1443
1444    /// A multiplicative factor that will be applied to the exponential back-off retry delay.
1445    #[serde(default = "default::object_store_config::object_store_req_backoff_factor")]
1446    pub req_backoff_factor: u64,
1447
1448    /// Maximum timeout for `upload` operation
1449    #[serde(default = "default::object_store_config::object_store_upload_attempt_timeout_ms")]
1450    pub upload_attempt_timeout_ms: u64,
1451
1452    /// Total counts of `upload` operation retries
1453    #[serde(default = "default::object_store_config::object_store_upload_retry_attempts")]
1454    pub upload_retry_attempts: usize,
1455
1456    /// Maximum timeout for `streaming_upload_init` and `streaming_upload`
1457    #[serde(
1458        default = "default::object_store_config::object_store_streaming_upload_attempt_timeout_ms"
1459    )]
1460    pub streaming_upload_attempt_timeout_ms: u64,
1461
1462    /// Total counts of `streaming_upload` operation retries
1463    #[serde(
1464        default = "default::object_store_config::object_store_streaming_upload_retry_attempts"
1465    )]
1466    pub streaming_upload_retry_attempts: usize,
1467
1468    /// Maximum timeout for `read` operation
1469    #[serde(default = "default::object_store_config::object_store_read_attempt_timeout_ms")]
1470    pub read_attempt_timeout_ms: u64,
1471
1472    /// Total counts of `read` operation retries
1473    #[serde(default = "default::object_store_config::object_store_read_retry_attempts")]
1474    pub read_retry_attempts: usize,
1475
1476    /// Maximum timeout for `streaming_read_init` and `streaming_read` operation
1477    #[serde(
1478        default = "default::object_store_config::object_store_streaming_read_attempt_timeout_ms"
1479    )]
1480    pub streaming_read_attempt_timeout_ms: u64,
1481
1482    /// Total counts of `streaming_read operation` retries
1483    #[serde(default = "default::object_store_config::object_store_streaming_read_retry_attempts")]
1484    pub streaming_read_retry_attempts: usize,
1485
1486    /// Maximum timeout for `metadata` operation
1487    #[serde(default = "default::object_store_config::object_store_metadata_attempt_timeout_ms")]
1488    pub metadata_attempt_timeout_ms: u64,
1489
1490    /// Total counts of `metadata` operation retries
1491    #[serde(default = "default::object_store_config::object_store_metadata_retry_attempts")]
1492    pub metadata_retry_attempts: usize,
1493
1494    /// Maximum timeout for `delete` operation
1495    #[serde(default = "default::object_store_config::object_store_delete_attempt_timeout_ms")]
1496    pub delete_attempt_timeout_ms: u64,
1497
1498    /// Total counts of `delete` operation retries
1499    #[serde(default = "default::object_store_config::object_store_delete_retry_attempts")]
1500    pub delete_retry_attempts: usize,
1501
1502    /// Maximum timeout for `delete_object` operation
1503    #[serde(
1504        default = "default::object_store_config::object_store_delete_objects_attempt_timeout_ms"
1505    )]
1506    pub delete_objects_attempt_timeout_ms: u64,
1507
1508    /// Total counts of `delete_object` operation retries
1509    #[serde(default = "default::object_store_config::object_store_delete_objects_retry_attempts")]
1510    pub delete_objects_retry_attempts: usize,
1511
1512    /// Maximum timeout for `list` operation
1513    #[serde(default = "default::object_store_config::object_store_list_attempt_timeout_ms")]
1514    pub list_attempt_timeout_ms: u64,
1515
1516    /// Total counts of `list` operation retries
1517    #[serde(default = "default::object_store_config::object_store_list_retry_attempts")]
1518    pub list_retry_attempts: usize,
1519}
1520
1521impl SystemConfig {
1522    #![allow(deprecated)]
1523    pub fn into_init_system_params(self) -> SystemParams {
1524        macro_rules! fields {
1525            ($({ $field:ident, $($rest:tt)* },)*) => {
1526                SystemParams {
1527                    $($field: self.$field.map(Into::into),)*
1528                    ..Default::default() // deprecated fields
1529                }
1530            };
1531        }
1532
1533        let mut system_params = for_all_params!(fields);
1534
1535        // Initialize backup_storage_url and backup_storage_directory if not set.
1536        if let Some(state_store) = &system_params.state_store
1537            && let Some(data_directory) = &system_params.data_directory
1538        {
1539            if system_params.backup_storage_url.is_none() {
1540                if let Some(hummock_state_store) = state_store.strip_prefix("hummock+") {
1541                    system_params.backup_storage_url = Some(hummock_state_store.to_owned());
1542                } else {
1543                    system_params.backup_storage_url = Some("memory".to_owned());
1544                }
1545                tracing::info!("initialize backup_storage_url based on state_store");
1546            }
1547            if system_params.backup_storage_directory.is_none() {
1548                system_params.backup_storage_directory = Some(format!("{data_directory}/backup"));
1549                tracing::info!("initialize backup_storage_directory based on data_directory");
1550            }
1551        }
1552        system_params
1553    }
1554}
1555
1556impl RwConfig {
1557    pub const fn default_connection_pool_size(&self) -> u16 {
1558        self.server.connection_pool_size
1559    }
1560
1561    /// Returns [`StreamingDeveloperConfig::exchange_connection_pool_size`] if set,
1562    /// otherwise [`ServerConfig::connection_pool_size`].
1563    pub fn streaming_exchange_connection_pool_size(&self) -> u16 {
1564        self.streaming
1565            .developer
1566            .exchange_connection_pool_size
1567            .unwrap_or_else(|| self.default_connection_pool_size())
1568    }
1569
1570    /// Returns [`BatchDeveloperConfig::exchange_connection_pool_size`] if set,
1571    /// otherwise [`ServerConfig::connection_pool_size`].
1572    pub fn batch_exchange_connection_pool_size(&self) -> u16 {
1573        self.batch
1574            .developer
1575            .exchange_connection_pool_size
1576            .unwrap_or_else(|| self.default_connection_pool_size())
1577    }
1578}
1579
1580pub mod default {
1581    pub mod meta {
1582        use crate::config::{DefaultParallelism, MetaBackend};
1583
1584        pub fn min_sst_retention_time_sec() -> u64 {
1585            3600 * 6
1586        }
1587
1588        pub fn gc_history_retention_time_sec() -> u64 {
1589            3600 * 6
1590        }
1591
1592        pub fn full_gc_interval_sec() -> u64 {
1593            3600
1594        }
1595
1596        pub fn full_gc_object_limit() -> u64 {
1597            100_000
1598        }
1599
1600        pub fn max_inflight_time_travel_query() -> u64 {
1601            1000
1602        }
1603
1604        pub fn periodic_compaction_interval_sec() -> u64 {
1605            60
1606        }
1607
1608        pub fn vacuum_interval_sec() -> u64 {
1609            30
1610        }
1611
1612        pub fn vacuum_spin_interval_ms() -> u64 {
1613            100
1614        }
1615
1616        pub fn hummock_version_checkpoint_interval_sec() -> u64 {
1617            30
1618        }
1619
1620        pub fn enable_hummock_data_archive() -> bool {
1621            false
1622        }
1623
1624        pub fn hummock_time_travel_snapshot_interval() -> u64 {
1625            100
1626        }
1627
1628        pub fn min_delta_log_num_for_hummock_version_checkpoint() -> u64 {
1629            10
1630        }
1631
1632        pub fn max_heartbeat_interval_sec() -> u32 {
1633            60
1634        }
1635
1636        pub fn meta_leader_lease_secs() -> u64 {
1637            30
1638        }
1639
1640        pub fn default_parallelism() -> DefaultParallelism {
1641            DefaultParallelism::Full
1642        }
1643
1644        pub fn node_num_monitor_interval_sec() -> u64 {
1645            10
1646        }
1647
1648        pub fn backend() -> MetaBackend {
1649            MetaBackend::Mem
1650        }
1651
1652        pub fn periodic_space_reclaim_compaction_interval_sec() -> u64 {
1653            3600 // 60min
1654        }
1655
1656        pub fn periodic_ttl_reclaim_compaction_interval_sec() -> u64 {
1657            1800 // 30mi
1658        }
1659
1660        pub fn periodic_scheduling_compaction_group_split_interval_sec() -> u64 {
1661            10 // 10s
1662        }
1663
1664        pub fn periodic_tombstone_reclaim_compaction_interval_sec() -> u64 {
1665            600
1666        }
1667
1668        // limit the size of state table to trigger split by high throughput
1669        pub fn move_table_size_limit() -> u64 {
1670            10 * 1024 * 1024 * 1024 // 10GB
1671        }
1672
1673        // limit the size of group to trigger split by group_size and avoid too many small groups
1674        pub fn split_group_size_limit() -> u64 {
1675            64 * 1024 * 1024 * 1024 // 64GB
1676        }
1677
1678        pub fn partition_vnode_count() -> u32 {
1679            16
1680        }
1681
1682        pub fn table_high_write_throughput_threshold() -> u64 {
1683            16 * 1024 * 1024 // 16MB
1684        }
1685
1686        pub fn table_low_write_throughput_threshold() -> u64 {
1687            4 * 1024 * 1024 // 4MB
1688        }
1689
1690        pub fn compaction_task_max_heartbeat_interval_secs() -> u64 {
1691            30 // 30s
1692        }
1693
1694        pub fn compaction_task_max_progress_interval_secs() -> u64 {
1695            60 * 10 // 10min
1696        }
1697
1698        pub fn cut_table_size_limit() -> u64 {
1699            1024 * 1024 * 1024 // 1GB
1700        }
1701
1702        pub fn hybrid_partition_vnode_count() -> u32 {
1703            4
1704        }
1705
1706        pub fn compact_task_table_size_partition_threshold_low() -> u64 {
1707            128 * 1024 * 1024 // 128MB
1708        }
1709
1710        pub fn compact_task_table_size_partition_threshold_high() -> u64 {
1711            512 * 1024 * 1024 // 512MB
1712        }
1713
1714        pub fn event_log_enabled() -> bool {
1715            true
1716        }
1717
1718        pub fn event_log_channel_max_size() -> u32 {
1719            10
1720        }
1721
1722        pub fn parallelism_control_batch_size() -> usize {
1723            10
1724        }
1725
1726        pub fn parallelism_control_trigger_period_sec() -> u64 {
1727            10
1728        }
1729
1730        pub fn parallelism_control_trigger_first_delay_sec() -> u64 {
1731            30
1732        }
1733
1734        pub fn enable_dropped_column_reclaim() -> bool {
1735            false
1736        }
1737
1738        pub fn split_group_size_ratio() -> f64 {
1739            0.9
1740        }
1741
1742        pub fn table_stat_high_write_throughput_ratio_for_split() -> f64 {
1743            0.5
1744        }
1745
1746        pub fn table_stat_low_write_throughput_ratio_for_merge() -> f64 {
1747            0.7
1748        }
1749
1750        pub fn table_stat_throuput_window_seconds_for_split() -> usize {
1751            60
1752        }
1753
1754        pub fn table_stat_throuput_window_seconds_for_merge() -> usize {
1755            240
1756        }
1757
1758        pub fn periodic_scheduling_compaction_group_merge_interval_sec() -> u64 {
1759            60 * 10 // 10min
1760        }
1761
1762        pub fn compaction_group_merge_dimension_threshold() -> f64 {
1763            1.2
1764        }
1765    }
1766
1767    pub mod server {
1768        use crate::config::MetricLevel;
1769
1770        pub fn heartbeat_interval_ms() -> u32 {
1771            1000
1772        }
1773
1774        pub fn connection_pool_size() -> u16 {
1775            16
1776        }
1777
1778        pub fn metrics_level() -> MetricLevel {
1779            MetricLevel::Info
1780        }
1781
1782        pub fn telemetry_enabled() -> bool {
1783            true
1784        }
1785
1786        pub fn grpc_max_reset_stream_size() -> u32 {
1787            200
1788        }
1789    }
1790
1791    pub mod storage {
1792        pub fn share_buffers_sync_parallelism() -> u32 {
1793            1
1794        }
1795
1796        pub fn share_buffer_compaction_worker_threads_number() -> u32 {
1797            4
1798        }
1799
1800        pub fn shared_buffer_capacity_mb() -> usize {
1801            1024
1802        }
1803
1804        pub fn shared_buffer_flush_ratio() -> f32 {
1805            0.8
1806        }
1807
1808        pub fn shared_buffer_min_batch_flush_size_mb() -> usize {
1809            800
1810        }
1811
1812        pub fn imm_merge_threshold() -> usize {
1813            0 // disable
1814        }
1815
1816        pub fn write_conflict_detection_enabled() -> bool {
1817            cfg!(debug_assertions)
1818        }
1819
1820        pub fn max_cached_recent_versions_number() -> usize {
1821            60
1822        }
1823
1824        pub fn block_cache_capacity_mb() -> usize {
1825            512
1826        }
1827
1828        pub fn high_priority_ratio_in_percent() -> usize {
1829            70
1830        }
1831
1832        pub fn window_capacity_ratio_in_percent() -> usize {
1833            10
1834        }
1835
1836        pub fn protected_capacity_ratio_in_percent() -> usize {
1837            80
1838        }
1839
1840        pub fn cmsketch_eps() -> f64 {
1841            0.002
1842        }
1843
1844        pub fn cmsketch_confidence() -> f64 {
1845            0.95
1846        }
1847
1848        pub fn small_queue_capacity_ratio_in_percent() -> usize {
1849            10
1850        }
1851
1852        pub fn ghost_queue_capacity_ratio_in_percent() -> usize {
1853            1000
1854        }
1855
1856        pub fn small_to_main_freq_threshold() -> u8 {
1857            1
1858        }
1859
1860        pub fn meta_cache_capacity_mb() -> usize {
1861            128
1862        }
1863
1864        pub fn disable_remote_compactor() -> bool {
1865            false
1866        }
1867
1868        pub fn share_buffer_upload_concurrency() -> usize {
1869            8
1870        }
1871
1872        pub fn compactor_memory_limit_mb() -> usize {
1873            512
1874        }
1875
1876        pub fn compactor_max_task_multiplier() -> f32 {
1877            3.0000
1878        }
1879
1880        pub fn compactor_memory_available_proportion() -> f64 {
1881            0.8
1882        }
1883
1884        pub fn sstable_id_remote_fetch_number() -> u32 {
1885            10
1886        }
1887
1888        pub fn min_sstable_size_mb() -> u32 {
1889            32
1890        }
1891
1892        pub fn min_sst_size_for_streaming_upload() -> u64 {
1893            // 32MB
1894            32 * 1024 * 1024
1895        }
1896
1897        pub fn max_concurrent_compaction_task_number() -> u64 {
1898            16
1899        }
1900
1901        pub fn max_preload_wait_time_mill() -> u64 {
1902            0
1903        }
1904
1905        pub fn max_version_pinning_duration_sec() -> u64 {
1906            3 * 3600
1907        }
1908
1909        pub fn compactor_max_sst_key_count() -> u64 {
1910            2 * 1024 * 1024 // 200w
1911        }
1912
1913        pub fn compact_iter_recreate_timeout_ms() -> u64 {
1914            10 * 60 * 1000
1915        }
1916
1917        pub fn compactor_iter_max_io_retry_times() -> usize {
1918            8
1919        }
1920
1921        pub fn compactor_max_sst_size() -> u64 {
1922            512 * 1024 * 1024 // 512m
1923        }
1924
1925        pub fn enable_fast_compaction() -> bool {
1926            true
1927        }
1928
1929        pub fn check_compaction_result() -> bool {
1930            false
1931        }
1932
1933        pub fn max_preload_io_retry_times() -> usize {
1934            3
1935        }
1936
1937        pub fn mem_table_spill_threshold() -> usize {
1938            4 << 20
1939        }
1940
1941        pub fn compactor_fast_max_compact_delete_ratio() -> u32 {
1942            40
1943        }
1944
1945        pub fn compactor_fast_max_compact_task_size() -> u64 {
1946            2 * 1024 * 1024 * 1024 // 2g
1947        }
1948
1949        pub fn max_prefetch_block_number() -> usize {
1950            16
1951        }
1952
1953        pub fn compactor_concurrent_uploading_sst_count() -> Option<usize> {
1954            None
1955        }
1956
1957        pub fn compactor_max_overlap_sst_count() -> usize {
1958            64
1959        }
1960
1961        pub fn compactor_max_preload_meta_file_count() -> usize {
1962            32
1963        }
1964
1965        // deprecated
1966        pub fn table_info_statistic_history_times() -> usize {
1967            240
1968        }
1969
1970        pub fn block_file_cache_flush_buffer_threshold_mb() -> usize {
1971            256
1972        }
1973
1974        pub fn meta_file_cache_flush_buffer_threshold_mb() -> usize {
1975            64
1976        }
1977
1978        pub fn time_travel_version_cache_capacity() -> u64 {
1979            10
1980        }
1981    }
1982
1983    pub mod streaming {
1984        use crate::config::AsyncStackTraceOption;
1985
1986        pub fn in_flight_barrier_nums() -> usize {
1987            // quick fix
1988            // TODO: remove this limitation from code
1989            10000
1990        }
1991
1992        pub fn async_stack_trace() -> AsyncStackTraceOption {
1993            AsyncStackTraceOption::default()
1994        }
1995
1996        pub fn unique_user_stream_errors() -> usize {
1997            10
1998        }
1999
2000        pub fn unsafe_enable_strict_consistency() -> bool {
2001            true
2002        }
2003    }
2004
2005    pub mod file_cache {
2006        use std::num::NonZeroUsize;
2007
2008        use foyer::{Compression, RecoverMode, RuntimeOptions, Throttle, TokioRuntimeOptions};
2009
2010        pub fn dir() -> String {
2011            "".to_owned()
2012        }
2013
2014        pub fn capacity_mb() -> usize {
2015            1024
2016        }
2017
2018        pub fn file_capacity_mb() -> usize {
2019            64
2020        }
2021
2022        pub fn flushers() -> usize {
2023            4
2024        }
2025
2026        pub fn reclaimers() -> usize {
2027            4
2028        }
2029
2030        pub fn recover_concurrency() -> usize {
2031            8
2032        }
2033
2034        pub fn insert_rate_limit_mb() -> usize {
2035            0
2036        }
2037
2038        pub fn indexer_shards() -> usize {
2039            64
2040        }
2041
2042        pub fn compression() -> Compression {
2043            Compression::None
2044        }
2045
2046        pub fn flush_buffer_threshold_mb() -> Option<usize> {
2047            None
2048        }
2049
2050        pub fn fifo_probation_ratio() -> f64 {
2051            0.1
2052        }
2053
2054        pub fn recover_mode() -> RecoverMode {
2055            RecoverMode::Quiet
2056        }
2057
2058        pub fn runtime_config() -> RuntimeOptions {
2059            RuntimeOptions::Unified(TokioRuntimeOptions::default())
2060        }
2061
2062        pub fn throttle() -> Throttle {
2063            Throttle::new()
2064                .with_iops_counter(foyer::IopsCounter::PerIoSize(
2065                    NonZeroUsize::new(128 * 1024).unwrap(),
2066                ))
2067                .with_read_iops(100000)
2068                .with_write_iops(100000)
2069                .with_write_throughput(1024 * 1024 * 1024)
2070                .with_read_throughput(1024 * 1024 * 1024)
2071        }
2072    }
2073
2074    pub mod cache_refill {
2075        pub fn data_refill_levels() -> Vec<u32> {
2076            vec![]
2077        }
2078
2079        pub fn timeout_ms() -> u64 {
2080            6000
2081        }
2082
2083        pub fn concurrency() -> usize {
2084            10
2085        }
2086
2087        pub fn unit() -> usize {
2088            64
2089        }
2090
2091        pub fn threshold() -> f64 {
2092            0.5
2093        }
2094
2095        pub fn recent_filter_layers() -> usize {
2096            6
2097        }
2098
2099        pub fn recent_filter_rotate_interval_ms() -> usize {
2100            10000
2101        }
2102    }
2103
2104    pub mod heap_profiling {
2105        pub fn enable_auto() -> bool {
2106            true
2107        }
2108
2109        pub fn threshold_auto() -> f32 {
2110            0.9
2111        }
2112
2113        pub fn dir() -> String {
2114            "./".to_owned()
2115        }
2116    }
2117
2118    pub mod developer {
2119        pub fn meta_cached_traces_num() -> u32 {
2120            256
2121        }
2122
2123        pub fn meta_cached_traces_memory_limit_bytes() -> usize {
2124            1 << 27 // 128 MiB
2125        }
2126
2127        pub fn batch_output_channel_size() -> usize {
2128            64
2129        }
2130
2131        pub fn batch_receiver_channel_size() -> usize {
2132            1000
2133        }
2134
2135        pub fn batch_root_stage_channel_size() -> usize {
2136            100
2137        }
2138
2139        pub fn batch_chunk_size() -> usize {
2140            1024
2141        }
2142
2143        pub fn batch_local_execute_buffer_size() -> usize {
2144            64
2145        }
2146
2147        /// Default to unset to be compatible with the behavior before this config is introduced,
2148        /// that is, follow the value of `server.connection_pool_size`.
2149        pub fn batch_exchange_connection_pool_size() -> Option<u16> {
2150            None
2151        }
2152
2153        pub fn stream_enable_executor_row_count() -> bool {
2154            false
2155        }
2156
2157        pub fn connector_message_buffer_size() -> usize {
2158            16
2159        }
2160
2161        pub fn unsafe_stream_extreme_cache_size() -> usize {
2162            10
2163        }
2164
2165        pub fn stream_chunk_size() -> usize {
2166            256
2167        }
2168
2169        pub fn stream_exchange_initial_permits() -> usize {
2170            2048
2171        }
2172
2173        pub fn stream_exchange_batched_permits() -> usize {
2174            256
2175        }
2176
2177        pub fn stream_exchange_concurrent_barriers() -> usize {
2178            1
2179        }
2180
2181        pub fn stream_exchange_concurrent_dispatchers() -> usize {
2182            0
2183        }
2184
2185        pub fn stream_dml_channel_initial_permits() -> usize {
2186            32768
2187        }
2188
2189        pub fn stream_max_barrier_batch_size() -> u32 {
2190            1024
2191        }
2192
2193        pub fn stream_hash_agg_max_dirty_groups_heap_size() -> usize {
2194            64 << 20 // 64MB
2195        }
2196
2197        pub fn enable_trivial_move() -> bool {
2198            true
2199        }
2200
2201        pub fn enable_check_task_level_overlap() -> bool {
2202            false
2203        }
2204
2205        pub fn max_trivial_move_task_count_per_loop() -> usize {
2206            256
2207        }
2208
2209        pub fn max_get_task_probe_times() -> usize {
2210            5
2211        }
2212
2213        pub fn actor_cnt_per_worker_parallelism_soft_limit() -> usize {
2214            100
2215        }
2216
2217        pub fn actor_cnt_per_worker_parallelism_hard_limit() -> usize {
2218            400
2219        }
2220
2221        pub fn hummock_time_travel_sst_info_fetch_batch_size() -> usize {
2222            10_000
2223        }
2224
2225        pub fn hummock_time_travel_sst_info_insert_batch_size() -> usize {
2226            100
2227        }
2228
2229        pub fn time_travel_vacuum_interval_sec() -> u64 {
2230            30
2231        }
2232        pub fn hummock_time_travel_epoch_version_insert_batch_size() -> usize {
2233            1000
2234        }
2235
2236        pub fn hummock_gc_history_insert_batch_size() -> usize {
2237            1000
2238        }
2239
2240        pub fn hummock_time_travel_filter_out_objects_batch_size() -> usize {
2241            1000
2242        }
2243
2244        pub fn hummock_time_travel_filter_out_objects_v1() -> bool {
2245            false
2246        }
2247
2248        pub fn hummock_time_travel_filter_out_objects_list_version_batch_size() -> usize {
2249            10
2250        }
2251
2252        pub fn hummock_time_travel_filter_out_objects_list_delta_batch_size() -> usize {
2253            1000
2254        }
2255
2256        pub fn memory_controller_threshold_aggressive() -> f64 {
2257            0.9
2258        }
2259
2260        pub fn memory_controller_threshold_graceful() -> f64 {
2261            0.81
2262        }
2263
2264        pub fn memory_controller_threshold_stable() -> f64 {
2265            0.72
2266        }
2267
2268        pub fn memory_controller_eviction_factor_aggressive() -> f64 {
2269            2.0
2270        }
2271
2272        pub fn memory_controller_eviction_factor_graceful() -> f64 {
2273            1.5
2274        }
2275
2276        pub fn memory_controller_eviction_factor_stable() -> f64 {
2277            1.0
2278        }
2279
2280        pub fn memory_controller_update_interval_ms() -> usize {
2281            100
2282        }
2283
2284        pub fn memory_controller_sequence_tls_step() -> u64 {
2285            128
2286        }
2287
2288        pub fn memory_controller_sequence_tls_lag() -> u64 {
2289            32
2290        }
2291
2292        pub fn stream_enable_arrangement_backfill() -> bool {
2293            true
2294        }
2295
2296        pub fn enable_shared_source() -> bool {
2297            true
2298        }
2299
2300        pub fn stream_high_join_amplification_threshold() -> usize {
2301            2048
2302        }
2303
2304        /// Default to 1 to be compatible with the behavior before this config is introduced.
2305        pub fn stream_exchange_connection_pool_size() -> Option<u16> {
2306            Some(1)
2307        }
2308
2309        pub fn enable_actor_tokio_metrics() -> bool {
2310            false
2311        }
2312
2313        pub fn stream_enable_auto_schema_change() -> bool {
2314            true
2315        }
2316
2317        pub fn switch_jdbc_pg_to_native() -> bool {
2318            false
2319        }
2320
2321        pub fn streaming_hash_join_entry_state_max_rows() -> usize {
2322            // NOTE(kwannoel): This is just an arbitrary number.
2323            30000
2324        }
2325
2326        pub fn enable_explain_analyze_stats() -> bool {
2327            true
2328        }
2329
2330        pub fn rpc_client_connect_timeout_secs() -> u64 {
2331            5
2332        }
2333
2334        pub fn iceberg_list_interval_sec() -> u64 {
2335            1
2336        }
2337
2338        pub fn iceberg_fetch_batch_size() -> u64 {
2339            1024
2340        }
2341
2342        pub fn iceberg_sink_positional_delete_cache_size() -> usize {
2343            1024
2344        }
2345    }
2346
2347    pub use crate::system_param::default as system;
2348
2349    pub mod batch {
2350        pub fn enable_barrier_read() -> bool {
2351            false
2352        }
2353
2354        pub fn enable_spill() -> bool {
2355            true
2356        }
2357
2358        pub fn statement_timeout_in_sec() -> u32 {
2359            // 1 hour
2360            60 * 60
2361        }
2362
2363        pub fn frontend_compute_runtime_worker_threads() -> usize {
2364            4
2365        }
2366
2367        pub fn mask_worker_temporary_secs() -> usize {
2368            30
2369        }
2370
2371        pub fn redact_sql_option_keywords() -> Vec<String> {
2372            [
2373                "credential",
2374                "key",
2375                "password",
2376                "private",
2377                "secret",
2378                "token",
2379            ]
2380            .into_iter()
2381            .map(str::to_string)
2382            .collect()
2383        }
2384    }
2385
2386    pub mod frontend {
2387        pub fn max_total_query_size_bytes() -> u64 {
2388            1024 * 1024 * 1024
2389        }
2390
2391        pub fn min_single_query_size_bytes() -> u64 {
2392            1024 * 1024
2393        }
2394
2395        pub fn max_single_query_size_bytes() -> u64 {
2396            1024 * 1024 * 1024
2397        }
2398    }
2399
2400    pub mod udf {
2401        pub fn enable_embedded_python_udf() -> bool {
2402            false
2403        }
2404
2405        pub fn enable_embedded_javascript_udf() -> bool {
2406            true
2407        }
2408
2409        pub fn enable_embedded_wasm_udf() -> bool {
2410            true
2411        }
2412    }
2413
2414    pub mod compaction_config {
2415        const MB: u64 = 1024 * 1024;
2416        const GB: u64 = 1024 * 1024 * 1024;
2417        const DEFAULT_MAX_COMPACTION_BYTES: u64 = 2 * GB; // 2GB
2418        const DEFAULT_MIN_COMPACTION_BYTES: u64 = 128 * MB; // 128MB
2419        const DEFAULT_MAX_BYTES_FOR_LEVEL_BASE: u64 = 512 * MB; // 512MB
2420
2421        // decrease this configure when the generation of checkpoint barrier is not frequent.
2422        const DEFAULT_TIER_COMPACT_TRIGGER_NUMBER: u64 = 12;
2423        const DEFAULT_TARGET_FILE_SIZE_BASE: u64 = 32 * MB;
2424        // 32MB
2425        const DEFAULT_MAX_SUB_COMPACTION: u32 = 4;
2426        const DEFAULT_LEVEL_MULTIPLIER: u64 = 5;
2427        const DEFAULT_MAX_SPACE_RECLAIM_BYTES: u64 = 512 * MB; // 512MB;
2428        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_SUB_LEVEL_NUMBER: u64 = 300;
2429        const DEFAULT_MAX_COMPACTION_FILE_COUNT: u64 = 100;
2430        const DEFAULT_MIN_SUB_LEVEL_COMPACT_LEVEL_COUNT: u32 = 3;
2431        const DEFAULT_MIN_OVERLAPPING_SUB_LEVEL_COMPACT_LEVEL_COUNT: u32 = 12;
2432        const DEFAULT_TOMBSTONE_RATIO_PERCENT: u32 = 40;
2433        const DEFAULT_EMERGENCY_PICKER: bool = true;
2434        const DEFAULT_MAX_LEVEL: u32 = 6;
2435        const DEFAULT_MAX_L0_COMPACT_LEVEL_COUNT: u32 = 42;
2436        const DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MIN_SIZE: u64 = 4 * MB;
2437        const DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MAX_COUNT: u32 = 64;
2438        const DEFAULT_EMERGENCY_LEVEL0_SST_FILE_COUNT: u32 = 2000; // > 50G / 32M = 1600
2439        const DEFAULT_EMERGENCY_LEVEL0_SUB_LEVEL_PARTITION: u32 = 256;
2440        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SST_COUNT: u32 = 10000; // 10000 * 32M = 320G
2441        const DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SIZE: u64 = 300 * 1024 * MB; // 300GB
2442
2443        use crate::catalog::hummock::CompactionFilterFlag;
2444
2445        pub fn max_bytes_for_level_base() -> u64 {
2446            DEFAULT_MAX_BYTES_FOR_LEVEL_BASE
2447        }
2448
2449        pub fn max_bytes_for_level_multiplier() -> u64 {
2450            DEFAULT_LEVEL_MULTIPLIER
2451        }
2452
2453        pub fn max_compaction_bytes() -> u64 {
2454            DEFAULT_MAX_COMPACTION_BYTES
2455        }
2456
2457        pub fn sub_level_max_compaction_bytes() -> u64 {
2458            DEFAULT_MIN_COMPACTION_BYTES
2459        }
2460
2461        pub fn level0_tier_compact_file_number() -> u64 {
2462            DEFAULT_TIER_COMPACT_TRIGGER_NUMBER
2463        }
2464
2465        pub fn target_file_size_base() -> u64 {
2466            DEFAULT_TARGET_FILE_SIZE_BASE
2467        }
2468
2469        pub fn compaction_filter_mask() -> u32 {
2470            (CompactionFilterFlag::STATE_CLEAN | CompactionFilterFlag::TTL).into()
2471        }
2472
2473        pub fn max_sub_compaction() -> u32 {
2474            DEFAULT_MAX_SUB_COMPACTION
2475        }
2476
2477        pub fn level0_stop_write_threshold_sub_level_number() -> u64 {
2478            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_SUB_LEVEL_NUMBER
2479        }
2480
2481        pub fn level0_sub_level_compact_level_count() -> u32 {
2482            DEFAULT_MIN_SUB_LEVEL_COMPACT_LEVEL_COUNT
2483        }
2484
2485        pub fn level0_overlapping_sub_level_compact_level_count() -> u32 {
2486            DEFAULT_MIN_OVERLAPPING_SUB_LEVEL_COMPACT_LEVEL_COUNT
2487        }
2488
2489        pub fn max_space_reclaim_bytes() -> u64 {
2490            DEFAULT_MAX_SPACE_RECLAIM_BYTES
2491        }
2492
2493        pub fn level0_max_compact_file_number() -> u64 {
2494            DEFAULT_MAX_COMPACTION_FILE_COUNT
2495        }
2496
2497        pub fn tombstone_reclaim_ratio() -> u32 {
2498            DEFAULT_TOMBSTONE_RATIO_PERCENT
2499        }
2500
2501        pub fn enable_emergency_picker() -> bool {
2502            DEFAULT_EMERGENCY_PICKER
2503        }
2504
2505        pub fn max_level() -> u32 {
2506            DEFAULT_MAX_LEVEL
2507        }
2508
2509        pub fn max_l0_compact_level_count() -> u32 {
2510            DEFAULT_MAX_L0_COMPACT_LEVEL_COUNT
2511        }
2512
2513        pub fn sst_allowed_trivial_move_min_size() -> u64 {
2514            DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MIN_SIZE
2515        }
2516
2517        pub fn disable_auto_group_scheduling() -> bool {
2518            false
2519        }
2520
2521        pub fn max_overlapping_level_size() -> u64 {
2522            256 * MB
2523        }
2524
2525        pub fn sst_allowed_trivial_move_max_count() -> u32 {
2526            DEFAULT_SST_ALLOWED_TRIVIAL_MOVE_MAX_COUNT
2527        }
2528
2529        pub fn emergency_level0_sst_file_count() -> u32 {
2530            DEFAULT_EMERGENCY_LEVEL0_SST_FILE_COUNT
2531        }
2532
2533        pub fn emergency_level0_sub_level_partition() -> u32 {
2534            DEFAULT_EMERGENCY_LEVEL0_SUB_LEVEL_PARTITION
2535        }
2536
2537        pub fn level0_stop_write_threshold_max_sst_count() -> u32 {
2538            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SST_COUNT
2539        }
2540
2541        pub fn level0_stop_write_threshold_max_size() -> u64 {
2542            DEFAULT_LEVEL0_STOP_WRITE_THRESHOLD_MAX_SIZE
2543        }
2544
2545        pub fn enable_optimize_l0_interval_selection() -> bool {
2546            false
2547        }
2548    }
2549
2550    pub mod object_store_config {
2551        const DEFAULT_REQ_BACKOFF_INTERVAL_MS: u64 = 1000; // 1s
2552        const DEFAULT_REQ_BACKOFF_MAX_DELAY_MS: u64 = 10 * 1000; // 10s
2553        const DEFAULT_REQ_MAX_RETRY_ATTEMPTS: usize = 3;
2554
2555        pub fn set_atomic_write_dir() -> bool {
2556            false
2557        }
2558
2559        pub fn object_store_req_backoff_interval_ms() -> u64 {
2560            DEFAULT_REQ_BACKOFF_INTERVAL_MS
2561        }
2562
2563        pub fn object_store_req_backoff_max_delay_ms() -> u64 {
2564            DEFAULT_REQ_BACKOFF_MAX_DELAY_MS // 10s
2565        }
2566
2567        pub fn object_store_req_backoff_factor() -> u64 {
2568            2
2569        }
2570
2571        pub fn object_store_upload_attempt_timeout_ms() -> u64 {
2572            8 * 1000 // 8s
2573        }
2574
2575        pub fn object_store_upload_retry_attempts() -> usize {
2576            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2577        }
2578
2579        // init + upload_part + finish
2580        pub fn object_store_streaming_upload_attempt_timeout_ms() -> u64 {
2581            5 * 1000 // 5s
2582        }
2583
2584        pub fn object_store_streaming_upload_retry_attempts() -> usize {
2585            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2586        }
2587
2588        // tips: depend on block_size
2589        pub fn object_store_read_attempt_timeout_ms() -> u64 {
2590            8 * 1000 // 8s
2591        }
2592
2593        pub fn object_store_read_retry_attempts() -> usize {
2594            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2595        }
2596
2597        pub fn object_store_streaming_read_attempt_timeout_ms() -> u64 {
2598            3 * 1000 // 3s
2599        }
2600
2601        pub fn object_store_streaming_read_retry_attempts() -> usize {
2602            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2603        }
2604
2605        pub fn object_store_metadata_attempt_timeout_ms() -> u64 {
2606            60 * 1000 // 1min
2607        }
2608
2609        pub fn object_store_metadata_retry_attempts() -> usize {
2610            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2611        }
2612
2613        pub fn object_store_delete_attempt_timeout_ms() -> u64 {
2614            5 * 1000
2615        }
2616
2617        pub fn object_store_delete_retry_attempts() -> usize {
2618            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2619        }
2620
2621        // tips: depend on batch size
2622        pub fn object_store_delete_objects_attempt_timeout_ms() -> u64 {
2623            5 * 1000
2624        }
2625
2626        pub fn object_store_delete_objects_retry_attempts() -> usize {
2627            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2628        }
2629
2630        pub fn object_store_list_attempt_timeout_ms() -> u64 {
2631            10 * 60 * 1000
2632        }
2633
2634        pub fn object_store_list_retry_attempts() -> usize {
2635            DEFAULT_REQ_MAX_RETRY_ATTEMPTS
2636        }
2637
2638        pub fn opendal_upload_concurrency() -> usize {
2639            256
2640        }
2641
2642        pub fn upload_part_size() -> usize {
2643            // 16m
2644            16 * 1024 * 1024
2645        }
2646
2647        pub mod s3 {
2648            const DEFAULT_IDENTITY_RESOLUTION_TIMEOUT_S: u64 = 5;
2649
2650            const DEFAULT_KEEPALIVE_MS: u64 = 600 * 1000; // 10min
2651
2652            pub fn keepalive_ms() -> Option<u64> {
2653                Some(DEFAULT_KEEPALIVE_MS) // 10min
2654            }
2655
2656            pub fn recv_buffer_size() -> Option<usize> {
2657                Some(1 << 21) // 2m
2658            }
2659
2660            pub fn send_buffer_size() -> Option<usize> {
2661                None
2662            }
2663
2664            pub fn nodelay() -> Option<bool> {
2665                Some(true)
2666            }
2667
2668            pub fn identity_resolution_timeout_s() -> u64 {
2669                DEFAULT_IDENTITY_RESOLUTION_TIMEOUT_S
2670            }
2671
2672            pub mod developer {
2673                pub fn retry_unknown_service_error() -> bool {
2674                    false
2675                }
2676
2677                pub fn retryable_service_error_codes() -> Vec<String> {
2678                    vec!["SlowDown".into(), "TooManyRequests".into()]
2679                }
2680
2681                pub fn use_opendal() -> bool {
2682                    true
2683                }
2684            }
2685        }
2686    }
2687
2688    pub mod meta_store_config {
2689        const DEFAULT_MAX_CONNECTIONS: u32 = 10;
2690        const DEFAULT_MIN_CONNECTIONS: u32 = 1;
2691        const DEFAULT_CONNECTION_TIMEOUT_SEC: u64 = 10;
2692        const DEFAULT_IDLE_TIMEOUT_SEC: u64 = 30;
2693        const DEFAULT_ACQUIRE_TIMEOUT_SEC: u64 = 30;
2694
2695        pub fn max_connections() -> u32 {
2696            DEFAULT_MAX_CONNECTIONS
2697        }
2698
2699        pub fn min_connections() -> u32 {
2700            DEFAULT_MIN_CONNECTIONS
2701        }
2702
2703        pub fn connection_timeout_sec() -> u64 {
2704            DEFAULT_CONNECTION_TIMEOUT_SEC
2705        }
2706
2707        pub fn idle_timeout_sec() -> u64 {
2708            DEFAULT_IDLE_TIMEOUT_SEC
2709        }
2710
2711        pub fn acquire_timeout_sec() -> u64 {
2712            DEFAULT_ACQUIRE_TIMEOUT_SEC
2713        }
2714    }
2715}
2716
2717#[derive(Debug, Clone)]
2718pub enum EvictionConfig {
2719    Lru(LruConfig),
2720    Lfu(LfuConfig),
2721    S3Fifo(S3FifoConfig),
2722}
2723
2724impl EvictionConfig {
2725    pub fn for_test() -> Self {
2726        Self::Lru(LruConfig {
2727            high_priority_pool_ratio: 0.0,
2728        })
2729    }
2730}
2731
2732impl From<EvictionConfig> for foyer::EvictionConfig {
2733    fn from(value: EvictionConfig) -> Self {
2734        match value {
2735            EvictionConfig::Lru(lru) => foyer::EvictionConfig::Lru(lru),
2736            EvictionConfig::Lfu(lfu) => foyer::EvictionConfig::Lfu(lfu),
2737            EvictionConfig::S3Fifo(s3fifo) => foyer::EvictionConfig::S3Fifo(s3fifo),
2738        }
2739    }
2740}
2741
2742pub struct StorageMemoryConfig {
2743    pub block_cache_capacity_mb: usize,
2744    pub block_cache_shard_num: usize,
2745    pub meta_cache_capacity_mb: usize,
2746    pub meta_cache_shard_num: usize,
2747    pub shared_buffer_capacity_mb: usize,
2748    pub compactor_memory_limit_mb: usize,
2749    pub prefetch_buffer_capacity_mb: usize,
2750    pub block_cache_eviction_config: EvictionConfig,
2751    pub meta_cache_eviction_config: EvictionConfig,
2752    pub block_file_cache_flush_buffer_threshold_mb: usize,
2753    pub meta_file_cache_flush_buffer_threshold_mb: usize,
2754}
2755
2756pub const MAX_META_CACHE_SHARD_BITS: usize = 4;
2757pub const MIN_BUFFER_SIZE_PER_SHARD: usize = 256;
2758pub const MAX_BLOCK_CACHE_SHARD_BITS: usize = 6; // It means that there will be 64 shards lru-cache to avoid lock conflict.
2759
2760pub fn extract_storage_memory_config(s: &RwConfig) -> StorageMemoryConfig {
2761    let block_cache_capacity_mb = s.storage.cache.block_cache_capacity_mb.unwrap_or(
2762        // adapt to old version
2763        s.storage
2764            .block_cache_capacity_mb
2765            .unwrap_or(default::storage::block_cache_capacity_mb()),
2766    );
2767    let meta_cache_capacity_mb = s.storage.cache.meta_cache_capacity_mb.unwrap_or(
2768        // adapt to old version
2769        s.storage
2770            .block_cache_capacity_mb
2771            .unwrap_or(default::storage::meta_cache_capacity_mb()),
2772    );
2773    let shared_buffer_capacity_mb = s
2774        .storage
2775        .shared_buffer_capacity_mb
2776        .unwrap_or(default::storage::shared_buffer_capacity_mb());
2777    let meta_cache_shard_num = s.storage.cache.meta_cache_shard_num.unwrap_or_else(|| {
2778        let mut shard_bits = MAX_META_CACHE_SHARD_BITS;
2779        while (meta_cache_capacity_mb >> shard_bits) < MIN_BUFFER_SIZE_PER_SHARD && shard_bits > 0 {
2780            shard_bits -= 1;
2781        }
2782        shard_bits
2783    });
2784    let block_cache_shard_num = s.storage.cache.block_cache_shard_num.unwrap_or_else(|| {
2785        let mut shard_bits = MAX_BLOCK_CACHE_SHARD_BITS;
2786        while (block_cache_capacity_mb >> shard_bits) < MIN_BUFFER_SIZE_PER_SHARD && shard_bits > 0
2787        {
2788            shard_bits -= 1;
2789        }
2790        shard_bits
2791    });
2792    let compactor_memory_limit_mb = s
2793        .storage
2794        .compactor_memory_limit_mb
2795        .unwrap_or(default::storage::compactor_memory_limit_mb());
2796
2797    let get_eviction_config = |c: &CacheEvictionConfig| {
2798        match c {
2799            CacheEvictionConfig::Lru {
2800                high_priority_ratio_in_percent,
2801            } => EvictionConfig::Lru(LruConfig {
2802                high_priority_pool_ratio: high_priority_ratio_in_percent.unwrap_or(
2803                    // adapt to old version
2804                    s.storage
2805                        .high_priority_ratio_in_percent
2806                        .unwrap_or(default::storage::high_priority_ratio_in_percent()),
2807                ) as f64
2808                    / 100.0,
2809            }),
2810            CacheEvictionConfig::Lfu {
2811                window_capacity_ratio_in_percent,
2812                protected_capacity_ratio_in_percent,
2813                cmsketch_eps,
2814                cmsketch_confidence,
2815            } => EvictionConfig::Lfu(LfuConfig {
2816                window_capacity_ratio: window_capacity_ratio_in_percent
2817                    .unwrap_or(default::storage::window_capacity_ratio_in_percent())
2818                    as f64
2819                    / 100.0,
2820                protected_capacity_ratio: protected_capacity_ratio_in_percent
2821                    .unwrap_or(default::storage::protected_capacity_ratio_in_percent())
2822                    as f64
2823                    / 100.0,
2824                cmsketch_eps: cmsketch_eps.unwrap_or(default::storage::cmsketch_eps()),
2825                cmsketch_confidence: cmsketch_confidence
2826                    .unwrap_or(default::storage::cmsketch_confidence()),
2827            }),
2828            CacheEvictionConfig::S3Fifo {
2829                small_queue_capacity_ratio_in_percent,
2830                ghost_queue_capacity_ratio_in_percent,
2831                small_to_main_freq_threshold,
2832            } => EvictionConfig::S3Fifo(S3FifoConfig {
2833                small_queue_capacity_ratio: small_queue_capacity_ratio_in_percent
2834                    .unwrap_or(default::storage::small_queue_capacity_ratio_in_percent())
2835                    as f64
2836                    / 100.0,
2837                ghost_queue_capacity_ratio: ghost_queue_capacity_ratio_in_percent
2838                    .unwrap_or(default::storage::ghost_queue_capacity_ratio_in_percent())
2839                    as f64
2840                    / 100.0,
2841                small_to_main_freq_threshold: small_to_main_freq_threshold
2842                    .unwrap_or(default::storage::small_to_main_freq_threshold()),
2843            }),
2844        }
2845    };
2846
2847    let block_cache_eviction_config = get_eviction_config(&s.storage.cache.block_cache_eviction);
2848    let meta_cache_eviction_config = get_eviction_config(&s.storage.cache.meta_cache_eviction);
2849
2850    let prefetch_buffer_capacity_mb =
2851        s.storage
2852            .shared_buffer_capacity_mb
2853            .unwrap_or(match &block_cache_eviction_config {
2854                EvictionConfig::Lru(lru) => {
2855                    ((1.0 - lru.high_priority_pool_ratio) * block_cache_capacity_mb as f64) as usize
2856                }
2857                EvictionConfig::Lfu(lfu) => {
2858                    ((1.0 - lfu.protected_capacity_ratio) * block_cache_capacity_mb as f64) as usize
2859                }
2860                EvictionConfig::S3Fifo(s3fifo) => {
2861                    (s3fifo.small_queue_capacity_ratio * block_cache_capacity_mb as f64) as usize
2862                }
2863            });
2864
2865    let block_file_cache_flush_buffer_threshold_mb = s
2866        .storage
2867        .data_file_cache
2868        .flush_buffer_threshold_mb
2869        .unwrap_or(default::storage::block_file_cache_flush_buffer_threshold_mb());
2870    let meta_file_cache_flush_buffer_threshold_mb = s
2871        .storage
2872        .meta_file_cache
2873        .flush_buffer_threshold_mb
2874        .unwrap_or(default::storage::block_file_cache_flush_buffer_threshold_mb());
2875
2876    StorageMemoryConfig {
2877        block_cache_capacity_mb,
2878        block_cache_shard_num,
2879        meta_cache_capacity_mb,
2880        meta_cache_shard_num,
2881        shared_buffer_capacity_mb,
2882        compactor_memory_limit_mb,
2883        prefetch_buffer_capacity_mb,
2884        block_cache_eviction_config,
2885        meta_cache_eviction_config,
2886        block_file_cache_flush_buffer_threshold_mb,
2887        meta_file_cache_flush_buffer_threshold_mb,
2888    }
2889}
2890
2891#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
2892pub struct CompactionConfig {
2893    #[serde(default = "default::compaction_config::max_bytes_for_level_base")]
2894    pub max_bytes_for_level_base: u64,
2895    #[serde(default = "default::compaction_config::max_bytes_for_level_multiplier")]
2896    pub max_bytes_for_level_multiplier: u64,
2897    #[serde(default = "default::compaction_config::max_compaction_bytes")]
2898    pub max_compaction_bytes: u64,
2899    #[serde(default = "default::compaction_config::sub_level_max_compaction_bytes")]
2900    pub sub_level_max_compaction_bytes: u64,
2901    #[serde(default = "default::compaction_config::level0_tier_compact_file_number")]
2902    pub level0_tier_compact_file_number: u64,
2903    #[serde(default = "default::compaction_config::target_file_size_base")]
2904    pub target_file_size_base: u64,
2905    #[serde(default = "default::compaction_config::compaction_filter_mask")]
2906    pub compaction_filter_mask: u32,
2907    #[serde(default = "default::compaction_config::max_sub_compaction")]
2908    pub max_sub_compaction: u32,
2909    #[serde(default = "default::compaction_config::level0_stop_write_threshold_sub_level_number")]
2910    pub level0_stop_write_threshold_sub_level_number: u64,
2911    #[serde(default = "default::compaction_config::level0_sub_level_compact_level_count")]
2912    pub level0_sub_level_compact_level_count: u32,
2913    #[serde(
2914        default = "default::compaction_config::level0_overlapping_sub_level_compact_level_count"
2915    )]
2916    pub level0_overlapping_sub_level_compact_level_count: u32,
2917    #[serde(default = "default::compaction_config::max_space_reclaim_bytes")]
2918    pub max_space_reclaim_bytes: u64,
2919    #[serde(default = "default::compaction_config::level0_max_compact_file_number")]
2920    pub level0_max_compact_file_number: u64,
2921    #[serde(default = "default::compaction_config::tombstone_reclaim_ratio")]
2922    pub tombstone_reclaim_ratio: u32,
2923    #[serde(default = "default::compaction_config::enable_emergency_picker")]
2924    pub enable_emergency_picker: bool,
2925    #[serde(default = "default::compaction_config::max_level")]
2926    pub max_level: u32,
2927    #[serde(default = "default::compaction_config::sst_allowed_trivial_move_min_size")]
2928    pub sst_allowed_trivial_move_min_size: u64,
2929    #[serde(default = "default::compaction_config::sst_allowed_trivial_move_max_count")]
2930    pub sst_allowed_trivial_move_max_count: u32,
2931    #[serde(default = "default::compaction_config::max_l0_compact_level_count")]
2932    pub max_l0_compact_level_count: u32,
2933    #[serde(default = "default::compaction_config::disable_auto_group_scheduling")]
2934    pub disable_auto_group_scheduling: bool,
2935    #[serde(default = "default::compaction_config::max_overlapping_level_size")]
2936    pub max_overlapping_level_size: u64,
2937    #[serde(default = "default::compaction_config::emergency_level0_sst_file_count")]
2938    pub emergency_level0_sst_file_count: u32,
2939    #[serde(default = "default::compaction_config::emergency_level0_sub_level_partition")]
2940    pub emergency_level0_sub_level_partition: u32,
2941    #[serde(default = "default::compaction_config::level0_stop_write_threshold_max_sst_count")]
2942    pub level0_stop_write_threshold_max_sst_count: u32,
2943    #[serde(default = "default::compaction_config::level0_stop_write_threshold_max_size")]
2944    pub level0_stop_write_threshold_max_size: u64,
2945    #[serde(default = "default::compaction_config::enable_optimize_l0_interval_selection")]
2946    pub enable_optimize_l0_interval_selection: bool,
2947}
2948
2949/// Note: only applies to meta store backends other than `SQLite`.
2950#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
2951pub struct MetaStoreConfig {
2952    /// Maximum number of connections for the meta store connection pool.
2953    #[serde(default = "default::meta_store_config::max_connections")]
2954    pub max_connections: u32,
2955    /// Minimum number of connections for the meta store connection pool.
2956    #[serde(default = "default::meta_store_config::min_connections")]
2957    pub min_connections: u32,
2958    /// Connection timeout in seconds for a meta store connection.
2959    #[serde(default = "default::meta_store_config::connection_timeout_sec")]
2960    pub connection_timeout_sec: u64,
2961    /// Idle timeout in seconds for a meta store connection.
2962    #[serde(default = "default::meta_store_config::idle_timeout_sec")]
2963    pub idle_timeout_sec: u64,
2964    /// Acquire timeout in seconds for a meta store connection.
2965    #[serde(default = "default::meta_store_config::acquire_timeout_sec")]
2966    pub acquire_timeout_sec: u64,
2967}
2968
2969#[cfg(test)]
2970mod tests {
2971    use risingwave_license::LicenseKey;
2972
2973    use super::*;
2974
2975    fn default_config_for_docs() -> RwConfig {
2976        let mut config = RwConfig::default();
2977        // Set `license_key` to empty in the docs to avoid any confusion.
2978        config.system.license_key = Some(LicenseKey::empty());
2979        config
2980    }
2981
2982    /// This test ensures that `config/example.toml` is up-to-date with the default values specified
2983    /// in this file. Developer should run `./risedev generate-example-config` to update it if this
2984    /// test fails.
2985    #[test]
2986    fn test_example_up_to_date() {
2987        const HEADER: &str = "# This file is generated by ./risedev generate-example-config
2988# Check detailed comments in src/common/src/config.rs";
2989
2990        let actual = expect_test::expect_file!["../../config/example.toml"];
2991        let default = toml::to_string(&default_config_for_docs()).expect("failed to serialize");
2992
2993        let expected = format!("{HEADER}\n\n{default}");
2994        actual.assert_eq(&expected);
2995
2996        let expected = rw_config_to_markdown();
2997        let actual = expect_test::expect_file!["../../config/docs.md"];
2998        actual.assert_eq(&expected);
2999    }
3000
3001    #[derive(Debug)]
3002    struct ConfigItemDoc {
3003        desc: String,
3004        default: String,
3005    }
3006
3007    fn rw_config_to_markdown() -> String {
3008        let mut config_rustdocs = BTreeMap::<String, Vec<(String, String)>>::new();
3009        RwConfig::config_docs("".to_owned(), &mut config_rustdocs);
3010
3011        // Section -> Config Name -> ConfigItemDoc
3012        let mut configs: BTreeMap<String, BTreeMap<String, ConfigItemDoc>> = config_rustdocs
3013            .into_iter()
3014            .map(|(k, v)| {
3015                let docs: BTreeMap<String, ConfigItemDoc> = v
3016                    .into_iter()
3017                    .map(|(name, desc)| {
3018                        (
3019                            name,
3020                            ConfigItemDoc {
3021                                desc,
3022                                default: "".to_owned(), // unset
3023                            },
3024                        )
3025                    })
3026                    .collect();
3027                (k, docs)
3028            })
3029            .collect();
3030
3031        let toml_doc: BTreeMap<String, toml::Value> =
3032            toml::from_str(&toml::to_string(&default_config_for_docs()).unwrap()).unwrap();
3033        toml_doc.into_iter().for_each(|(name, value)| {
3034            set_default_values("".to_owned(), name, value, &mut configs);
3035        });
3036
3037        let mut markdown = "# RisingWave System Configurations\n\n".to_owned()
3038            + "This page is automatically generated by `./risedev generate-example-config`\n";
3039        for (section, configs) in configs {
3040            if configs.is_empty() {
3041                continue;
3042            }
3043            markdown.push_str(&format!("\n## {}\n\n", section));
3044            markdown.push_str("| Config | Description | Default |\n");
3045            markdown.push_str("|--------|-------------|---------|\n");
3046            for (config, doc) in configs {
3047                markdown.push_str(&format!(
3048                    "| {} | {} | {} |\n",
3049                    config, doc.desc, doc.default
3050                ));
3051            }
3052        }
3053        markdown
3054    }
3055
3056    fn set_default_values(
3057        section: String,
3058        name: String,
3059        value: toml::Value,
3060        configs: &mut BTreeMap<String, BTreeMap<String, ConfigItemDoc>>,
3061    ) {
3062        // Set the default value if it's a config name-value pair, otherwise it's a sub-section (Table) that should be recursively processed.
3063        if let toml::Value::Table(table) = value {
3064            let section_configs: BTreeMap<String, toml::Value> =
3065                table.clone().into_iter().collect();
3066            let sub_section = if section.is_empty() {
3067                name
3068            } else {
3069                format!("{}.{}", section, name)
3070            };
3071            section_configs
3072                .into_iter()
3073                .for_each(|(k, v)| set_default_values(sub_section.clone(), k, v, configs))
3074        } else if let Some(t) = configs.get_mut(&section) {
3075            if let Some(item_doc) = t.get_mut(&name) {
3076                item_doc.default = format!("{}", value);
3077            }
3078        }
3079    }
3080
3081    #[test]
3082    fn test_object_store_configs_backward_compatibility() {
3083        // Define configs with the old name and make sure it still works
3084        {
3085            let config: RwConfig = toml::from_str(
3086                r#"
3087            [storage.object_store]
3088            object_store_set_atomic_write_dir = true
3089
3090            [storage.object_store.s3]
3091            object_store_keepalive_ms = 1
3092            object_store_send_buffer_size = 1
3093            object_store_recv_buffer_size = 1
3094            object_store_nodelay = false
3095
3096            [storage.object_store.s3.developer]
3097            object_store_retry_unknown_service_error = true
3098            object_store_retryable_service_error_codes = ['dummy']
3099
3100
3101            "#,
3102            )
3103            .unwrap();
3104
3105            assert!(config.storage.object_store.set_atomic_write_dir);
3106            assert_eq!(config.storage.object_store.s3.keepalive_ms, Some(1));
3107            assert_eq!(config.storage.object_store.s3.send_buffer_size, Some(1));
3108            assert_eq!(config.storage.object_store.s3.recv_buffer_size, Some(1));
3109            assert_eq!(config.storage.object_store.s3.nodelay, Some(false));
3110            assert!(
3111                config
3112                    .storage
3113                    .object_store
3114                    .s3
3115                    .developer
3116                    .retry_unknown_service_error
3117            );
3118            assert_eq!(
3119                config
3120                    .storage
3121                    .object_store
3122                    .s3
3123                    .developer
3124                    .retryable_service_error_codes,
3125                vec!["dummy".to_owned()]
3126            );
3127        }
3128
3129        // Define configs with the new name and make sure it works
3130        {
3131            let config: RwConfig = toml::from_str(
3132                r#"
3133            [storage.object_store]
3134            set_atomic_write_dir = true
3135
3136            [storage.object_store.s3]
3137            keepalive_ms = 1
3138            send_buffer_size = 1
3139            recv_buffer_size = 1
3140            nodelay = false
3141
3142            [storage.object_store.s3.developer]
3143            retry_unknown_service_error = true
3144            retryable_service_error_codes = ['dummy']
3145
3146
3147            "#,
3148            )
3149            .unwrap();
3150
3151            assert!(config.storage.object_store.set_atomic_write_dir);
3152            assert_eq!(config.storage.object_store.s3.keepalive_ms, Some(1));
3153            assert_eq!(config.storage.object_store.s3.send_buffer_size, Some(1));
3154            assert_eq!(config.storage.object_store.s3.recv_buffer_size, Some(1));
3155            assert_eq!(config.storage.object_store.s3.nodelay, Some(false));
3156            assert!(
3157                config
3158                    .storage
3159                    .object_store
3160                    .s3
3161                    .developer
3162                    .retry_unknown_service_error
3163            );
3164            assert_eq!(
3165                config
3166                    .storage
3167                    .object_store
3168                    .s3
3169                    .developer
3170                    .retryable_service_error_codes,
3171                vec!["dummy".to_owned()]
3172            );
3173        }
3174    }
3175
3176    #[test]
3177    fn test_meta_configs_backward_compatibility() {
3178        // Test periodic_space_reclaim_compaction_interval_sec
3179        {
3180            let config: RwConfig = toml::from_str(
3181                r#"
3182            [meta]
3183            periodic_split_compact_group_interval_sec = 1
3184            table_write_throughput_threshold = 10
3185            min_table_split_write_throughput = 5
3186            "#,
3187            )
3188            .unwrap();
3189
3190            assert_eq!(
3191                config
3192                    .meta
3193                    .periodic_scheduling_compaction_group_split_interval_sec,
3194                1
3195            );
3196            assert_eq!(config.meta.table_high_write_throughput_threshold, 10);
3197            assert_eq!(config.meta.table_low_write_throughput_threshold, 5);
3198        }
3199    }
3200}