Skip to main content

reth_node_core/args/
storage.rs

1//! clap [Args](clap::Args) for storage configuration
2
3use clap::Args;
4use std::sync::OnceLock;
5
6/// Global static storage defaults
7static STORAGE_DEFAULTS: OnceLock<DefaultStorageValues> = OnceLock::new();
8
9/// Default values for storage that can be customized
10///
11/// Global defaults can be set via [`DefaultStorageValues::try_init`].
12#[derive(Debug, Clone)]
13pub struct DefaultStorageValues {
14    v2: bool,
15}
16
17impl DefaultStorageValues {
18    /// Initialize the global storage defaults with this configuration
19    pub fn try_init(self) -> Result<(), Self> {
20        STORAGE_DEFAULTS.set(self)
21    }
22
23    /// Get a reference to the global storage defaults
24    pub fn get_global() -> &'static Self {
25        STORAGE_DEFAULTS.get_or_init(Self::default)
26    }
27
28    /// Set the default V2 storage layout flag
29    pub const fn with_v2(mut self, v: bool) -> Self {
30        self.v2 = v;
31        self
32    }
33}
34
35impl Default for DefaultStorageValues {
36    fn default() -> Self {
37        Self { v2: true }
38    }
39}
40
41/// Parameters for storage configuration.
42///
43/// `--storage.v2` controls whether new databases use the hot/cold V2 storage layout.
44/// Defaults to `true`.
45///
46/// Existing databases always use the settings persisted in their metadata.
47#[derive(Debug, Args, PartialEq, Eq, Clone, Copy)]
48#[command(next_help_heading = "Storage")]
49pub struct StorageArgs {
50    /// Enable V2 (hot/cold) storage layout for new databases.
51    ///
52    /// When set, new databases will be initialized with the V2 storage layout that
53    /// separates hot and cold data. Existing databases always use the settings
54    /// persisted in their metadata regardless of this flag.
55    #[arg(
56        long = "storage.v2",
57        default_value_t = DefaultStorageValues::get_global().v2,
58        num_args = 0..=1,
59        default_missing_value = "true",
60    )]
61    pub v2: bool,
62}
63
64impl Default for StorageArgs {
65    fn default() -> Self {
66        let defaults = DefaultStorageValues::get_global();
67        Self { v2: defaults.v2 }
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use clap::Parser;
75
76    /// A helper type to parse Args more easily
77    #[derive(Parser)]
78    struct CommandParser<T: Args> {
79        #[command(flatten)]
80        args: T,
81    }
82
83    #[test]
84    fn test_default_storage_args() {
85        let args = CommandParser::<StorageArgs>::parse_from(["reth"]).args;
86        assert!(args.v2);
87    }
88
89    #[test]
90    fn test_storage_v2_implicit_true() {
91        let args = CommandParser::<StorageArgs>::parse_from(["reth", "--storage.v2"]).args;
92        assert!(args.v2);
93    }
94
95    #[test]
96    fn test_storage_v2_explicit_true() {
97        let args = CommandParser::<StorageArgs>::parse_from(["reth", "--storage.v2=true"]).args;
98        assert!(args.v2);
99    }
100
101    #[test]
102    fn test_storage_v2_explicit_false() {
103        let args = CommandParser::<StorageArgs>::parse_from(["reth", "--storage.v2=false"]).args;
104        assert!(!args.v2);
105    }
106}