redb_extras/partition/
config.rs

1//! Configuration for partitioned tables.
2//!
3//! Contains the configuration structure for generic partitioned storage.
4
5/// Configuration for partitioned tables.
6///
7/// This structure defines how data is distributed across shards and segments,
8/// providing control over write amplification and read performance.
9#[derive(Debug, Clone)]
10pub struct PartitionConfig {
11    /// Number of shards to distribute writes across
12    ///
13    /// Higher values spread writes better for hot keys but increase read fanout.
14    /// Must be between 1 and 65535.
15    pub shard_count: u16,
16
17    /// Maximum size in bytes for a single segment before rolling
18    ///
19    /// When a segment exceeds this size, a new segment is created.
20    /// This controls write amplification - smaller segments rewrite less data
21    /// but increase read overhead.
22    pub segment_max_bytes: usize,
23
24    /// Whether to use a meta table for O(1) head segment discovery
25    ///
26    /// With meta: Faster writes, additional storage overhead
27    /// Without meta: Simpler, but requires scanning to find writable segment
28    pub use_meta: bool,
29}
30
31impl PartitionConfig {
32    /// Creates a new partition configuration with sensible defaults.
33    ///
34    /// # Arguments
35    /// * `shard_count` - Number of shards (1-65535)
36    /// * `segment_max_bytes` - Maximum segment size in bytes
37    /// * `use_meta` - Whether to use meta table
38    ///
39    /// # Returns
40    /// Validated configuration or error
41    pub fn new(shard_count: u16, segment_max_bytes: usize, use_meta: bool) -> crate::Result<Self> {
42        if shard_count == 0 {
43            return Err(crate::error::Error::Partition(
44                crate::partition::PartitionError::InvalidShardCount(shard_count),
45            ));
46        }
47
48        if segment_max_bytes == 0 {
49            return Err(crate::error::Error::Partition(
50                crate::partition::PartitionError::InvalidSegmentSize(segment_max_bytes),
51            ));
52        }
53
54        Ok(Self {
55            shard_count,
56            segment_max_bytes,
57            use_meta,
58        })
59    }
60
61    /// Creates a default configuration suitable for most use cases.
62    pub fn default() -> Self {
63        Self {
64            shard_count: 16,              // Good balance for most workloads
65            segment_max_bytes: 64 * 1024, // 64KB segments match roaring compression
66            use_meta: true,               // Faster writes worth the overhead
67        }
68    }
69}
70
71impl Default for PartitionConfig {
72    fn default() -> Self {
73        Self::default()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_valid_config() {
83        let config = PartitionConfig::new(8, 1024, true);
84        assert!(config.is_ok());
85
86        let config = config.unwrap();
87        assert_eq!(config.shard_count, 8);
88        assert_eq!(config.segment_max_bytes, 1024);
89        assert!(config.use_meta);
90    }
91
92    #[test]
93    fn test_invalid_shard_count() {
94        let config = PartitionConfig::new(0, 1024, true);
95        assert!(config.is_err());
96    }
97
98    #[test]
99    fn test_invalid_segment_size() {
100        let config = PartitionConfig::new(8, 0, true);
101        assert!(config.is_err());
102    }
103
104    #[test]
105    fn test_default_config() {
106        let config = PartitionConfig::default();
107        assert_eq!(config.shard_count, 16);
108        assert_eq!(config.segment_max_bytes, 64 * 1024);
109        assert!(config.use_meta);
110    }
111}