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}