Skip to main content

prolly/prolly/
config.rs

1//! Configuration for Prolly Trees
2
3use serde::{Deserialize, Serialize};
4
5use super::encoding::{
6    Encoding, DEFAULT_CHUNKING_FACTOR, DEFAULT_HASH_SEED, DEFAULT_MAX_CHUNK_SIZE,
7    DEFAULT_MIN_CHUNK_SIZE,
8};
9
10/// Tree configuration
11#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
12pub struct Config {
13    /// Min entries before considering boundaries
14    pub min_chunk_size: usize,
15    /// Max entries in a node
16    pub max_chunk_size: usize,
17    /// Chunking factor (higher = larger nodes on average)
18    pub chunking_factor: u32,
19    /// Hash seed for boundary detection
20    pub hash_seed: u64,
21    /// Default value encoding
22    pub encoding: Encoding,
23    /// Optional maximum number of decoded nodes retained in each manager cache.
24    ///
25    /// `None` keeps the cache unbounded, matching the historical behavior.
26    /// `Some(0)` disables node caching.
27    pub node_cache_max_nodes: Option<usize>,
28    /// Optional maximum serialized-node bytes retained in each manager cache.
29    ///
30    /// The byte budget uses each node's compact serialized length as a stable
31    /// approximation of decoded-node cache pressure. `None` keeps the cache
32    /// unbounded by bytes. `Some(0)` disables node caching.
33    pub node_cache_max_bytes: Option<usize>,
34}
35
36impl Default for Config {
37    fn default() -> Self {
38        Self {
39            min_chunk_size: DEFAULT_MIN_CHUNK_SIZE,
40            max_chunk_size: DEFAULT_MAX_CHUNK_SIZE,
41            chunking_factor: DEFAULT_CHUNKING_FACTOR,
42            hash_seed: DEFAULT_HASH_SEED,
43            encoding: Encoding::Raw,
44            node_cache_max_nodes: None,
45            node_cache_max_bytes: None,
46        }
47    }
48}
49
50impl Config {
51    /// Create a new ConfigBuilder
52    pub fn builder() -> ConfigBuilder {
53        ConfigBuilder::default()
54    }
55}
56
57/// Builder for Config
58#[derive(Default)]
59pub struct ConfigBuilder {
60    config: Config,
61}
62
63impl ConfigBuilder {
64    /// Set the minimum chunk size
65    pub fn min_chunk_size(mut self, size: usize) -> Self {
66        self.config.min_chunk_size = size;
67        self
68    }
69
70    /// Set the maximum chunk size
71    pub fn max_chunk_size(mut self, size: usize) -> Self {
72        self.config.max_chunk_size = size;
73        self
74    }
75
76    /// Set the chunking factor
77    pub fn chunking_factor(mut self, factor: u32) -> Self {
78        self.config.chunking_factor = factor;
79        self
80    }
81
82    /// Set the hash seed
83    pub fn hash_seed(mut self, seed: u64) -> Self {
84        self.config.hash_seed = seed;
85        self
86    }
87
88    /// Set the encoding type
89    pub fn encoding(mut self, encoding: Encoding) -> Self {
90        self.config.encoding = encoding;
91        self
92    }
93
94    /// Set the maximum number of decoded nodes retained in each manager cache.
95    ///
96    /// Use `0` to disable node caching. Omit this setting to keep the cache
97    /// unbounded.
98    pub fn node_cache_max_nodes(mut self, max_nodes: usize) -> Self {
99        self.config.node_cache_max_nodes = Some(max_nodes);
100        self
101    }
102
103    /// Set the maximum serialized-node bytes retained in each manager cache.
104    ///
105    /// Use `0` to disable node caching. Omit this setting to keep the cache
106    /// unbounded by bytes.
107    pub fn node_cache_max_bytes(mut self, max_bytes: usize) -> Self {
108        self.config.node_cache_max_bytes = Some(max_bytes);
109        self
110    }
111
112    /// Keep each manager's decoded-node cache unbounded.
113    pub fn unbounded_node_cache(mut self) -> Self {
114        self.config.node_cache_max_nodes = None;
115        self.config.node_cache_max_bytes = None;
116        self
117    }
118
119    /// Build the Config
120    pub fn build(self) -> Config {
121        self.config
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_config_default() {
131        let config = Config::default();
132        assert_eq!(config.min_chunk_size, DEFAULT_MIN_CHUNK_SIZE);
133        assert_eq!(config.max_chunk_size, DEFAULT_MAX_CHUNK_SIZE);
134        assert_eq!(config.chunking_factor, DEFAULT_CHUNKING_FACTOR);
135        assert_eq!(config.hash_seed, DEFAULT_HASH_SEED);
136        assert_eq!(config.encoding, Encoding::Raw);
137        assert_eq!(config.node_cache_max_nodes, None);
138        assert_eq!(config.node_cache_max_bytes, None);
139    }
140
141    #[test]
142    fn test_config_builder() {
143        let config = Config::builder()
144            .min_chunk_size(2)
145            .max_chunk_size(100)
146            .chunking_factor(64)
147            .hash_seed(42)
148            .encoding(Encoding::Cbor)
149            .node_cache_max_nodes(128)
150            .node_cache_max_bytes(1_048_576)
151            .build();
152
153        assert_eq!(config.min_chunk_size, 2);
154        assert_eq!(config.max_chunk_size, 100);
155        assert_eq!(config.chunking_factor, 64);
156        assert_eq!(config.hash_seed, 42);
157        assert_eq!(config.encoding, Encoding::Cbor);
158        assert_eq!(config.node_cache_max_nodes, Some(128));
159        assert_eq!(config.node_cache_max_bytes, Some(1_048_576));
160
161        let config = Config::builder()
162            .node_cache_max_nodes(128)
163            .node_cache_max_bytes(1_048_576)
164            .unbounded_node_cache()
165            .build();
166        assert_eq!(config.node_cache_max_nodes, None);
167        assert_eq!(config.node_cache_max_bytes, None);
168    }
169}