1use crate::{
6 BlockStoreConfig, BloomBlockStore, BloomConfig, CachedBlockStore, MemoryBlockStore,
7 MetricsBlockStore, SledBlockStore,
8};
9use crate::{ChunkingConfig, DedupBlockStore};
10#[cfg(feature = "encryption")]
11use crate::{Cipher, EncryptedBlockStore, EncryptionConfig};
12use crate::{CoalesceConfig, CoalescingBlockStore};
13#[cfg(feature = "compression")]
14use crate::{CompressionAlgorithm, CompressionBlockStore, CompressionConfig};
15use crate::{TtlBlockStore, TtlConfig};
16use ipfrs_core::Result;
17use std::path::PathBuf;
18use std::time::Duration;
19
20type FullStack = BloomBlockStore<CachedBlockStore<SledBlockStore>>;
22type MonitoredFullStack = MetricsBlockStore<FullStack>;
23
24#[cfg(feature = "compression")]
25type CompressedStack = CompressionBlockStore<FullStack>;
26#[cfg(feature = "compression")]
27type MonitoredCompressedStack = MetricsBlockStore<CompressedStack>;
28
29#[cfg(feature = "encryption")]
30type EncryptedStack = EncryptedBlockStore<FullStack>;
31#[cfg(feature = "encryption")]
32type MonitoredEncryptedStack = MetricsBlockStore<EncryptedStack>;
33
34type DedupStack = DedupBlockStore<FullStack>;
35type MonitoredDedupStack = MetricsBlockStore<DedupStack>;
36
37#[cfg(feature = "compression")]
38type UltimateStack = DedupBlockStore<CompressedStack>;
39#[cfg(feature = "compression")]
40type MonitoredUltimateStack = MetricsBlockStore<UltimateStack>;
41
42pub struct StorageStackBuilder {
44 config: BlockStoreConfig,
45 enable_cache: bool,
46 cache_size_mb: usize,
47 enable_bloom: bool,
48 bloom_expected_items: usize,
49 enable_tiering: bool,
50}
51
52impl Default for StorageStackBuilder {
53 fn default() -> Self {
54 Self {
55 config: BlockStoreConfig::default(),
56 enable_cache: true,
57 cache_size_mb: 100,
58 enable_bloom: true,
59 bloom_expected_items: 100_000,
60 enable_tiering: false,
61 }
62 }
63}
64
65impl StorageStackBuilder {
66 pub fn new() -> Self {
68 Self::default()
69 }
70
71 pub fn with_config(mut self, config: BlockStoreConfig) -> Self {
73 self.config = config;
74 self
75 }
76
77 pub fn with_path(mut self, path: PathBuf) -> Self {
79 self.config.path = path;
80 self
81 }
82
83 pub fn with_cache(mut self, size_mb: usize) -> Self {
85 self.enable_cache = true;
86 self.cache_size_mb = size_mb;
87 self
88 }
89
90 pub fn without_cache(mut self) -> Self {
92 self.enable_cache = false;
93 self
94 }
95
96 pub fn with_bloom(mut self, expected_items: usize) -> Self {
98 self.enable_bloom = true;
99 self.bloom_expected_items = expected_items;
100 self
101 }
102
103 pub fn without_bloom(mut self) -> Self {
105 self.enable_bloom = false;
106 self
107 }
108
109 pub fn with_tiering(mut self) -> Self {
111 self.enable_tiering = true;
112 self
113 }
114
115 pub fn build_simple(self) -> Result<SledBlockStore> {
117 SledBlockStore::new(self.config)
118 }
119
120 pub fn build_cached(self) -> Result<CachedBlockStore<SledBlockStore>> {
122 let base = SledBlockStore::new(self.config)?;
123 let cache_size = self.cache_size_mb * 1024 * 1024;
124 Ok(CachedBlockStore::new(base, cache_size))
125 }
126
127 pub fn build_full(self) -> Result<BloomBlockStore<CachedBlockStore<SledBlockStore>>> {
129 let base = SledBlockStore::new(self.config)?;
130
131 let cache_size = if self.enable_cache {
132 self.cache_size_mb * 1024 * 1024
133 } else {
134 1024 };
136 let cached = CachedBlockStore::new(base, cache_size);
137
138 if self.enable_bloom {
139 let bloom_config = BloomConfig::new(self.bloom_expected_items, 0.01);
140 Ok(BloomBlockStore::with_config(cached, bloom_config))
141 } else {
142 let bloom_config = BloomConfig::new(100, 0.01);
144 Ok(BloomBlockStore::with_config(cached, bloom_config))
145 }
146 }
147}
148
149pub fn development_stack() -> Result<BloomBlockStore<CachedBlockStore<SledBlockStore>>> {
156 StorageStackBuilder::new()
157 .with_config(BlockStoreConfig::development())
158 .with_cache(50)
159 .with_bloom(10_000)
160 .build_full()
161}
162
163pub fn production_stack(path: PathBuf) -> Result<FullStack> {
169 StorageStackBuilder::new()
170 .with_config(BlockStoreConfig::production(path))
171 .with_cache(500)
172 .with_bloom(1_000_000)
173 .build_full()
174}
175
176pub fn embedded_stack(path: PathBuf) -> Result<BloomBlockStore<CachedBlockStore<SledBlockStore>>> {
182 StorageStackBuilder::new()
183 .with_config(BlockStoreConfig::embedded(path))
184 .with_cache(10)
185 .with_bloom(5_000)
186 .build_full()
187}
188
189pub fn testing_stack() -> Result<BloomBlockStore<CachedBlockStore<SledBlockStore>>> {
195 StorageStackBuilder::new()
196 .with_config(BlockStoreConfig::testing())
197 .with_cache(5)
198 .with_bloom(1_000)
199 .build_full()
200}
201
202pub fn monitored_production_stack(path: PathBuf) -> Result<MonitoredFullStack> {
207 let base = production_stack(path)?;
208 Ok(MetricsBlockStore::new(base))
209}
210
211pub fn memory_stack() -> MetricsBlockStore<BloomBlockStore<MemoryBlockStore>> {
218 let base = MemoryBlockStore::new();
219 let bloom_config = BloomConfig::new(100_000, 0.01);
220 let bloom = BloomBlockStore::with_config(base, bloom_config);
221 MetricsBlockStore::new(bloom)
222}
223
224#[cfg(feature = "compression")]
229pub fn compressed_production_stack(path: PathBuf) -> Result<MonitoredCompressedStack> {
230 let base = production_stack(path)?;
231 let compression_config = CompressionConfig {
232 algorithm: CompressionAlgorithm::Zstd,
233 level: 3, threshold: 1024, max_ratio: 0.9, };
237 let compressed = CompressionBlockStore::new(base, compression_config);
238 Ok(MetricsBlockStore::new(compressed))
239}
240
241#[cfg(feature = "encryption")]
246pub fn encrypted_production_stack(
247 path: PathBuf,
248 password: &str,
249) -> Result<MonitoredEncryptedStack> {
250 use crate::EncryptionKey;
251
252 let base = production_stack(path)?;
253 let (key, _salt) =
254 EncryptionKey::derive_from_password(Cipher::ChaCha20Poly1305, password.as_bytes(), None)?;
255 let config = EncryptionConfig {
256 cipher: Cipher::ChaCha20Poly1305,
257 };
258 let encrypted = EncryptedBlockStore::new(base, key, config);
259 Ok(MetricsBlockStore::new(encrypted))
260}
261
262pub fn deduplicated_production_stack(path: PathBuf) -> Result<MonitoredDedupStack> {
267 let base = production_stack(path)?;
268 let chunking_config = ChunkingConfig::default();
269 let dedup = DedupBlockStore::new(base, chunking_config);
270 Ok(MetricsBlockStore::new(dedup))
271}
272
273#[cfg(feature = "compression")]
284pub fn ultimate_production_stack(path: PathBuf) -> Result<MonitoredUltimateStack> {
285 let base = compressed_production_stack(path)?;
286 let inner = base.into_inner();
288 let chunking_config = ChunkingConfig::default();
289 let dedup = DedupBlockStore::new(inner, chunking_config);
290 Ok(MetricsBlockStore::new(dedup))
291}
292
293pub fn ttl_production_stack(
304 path: PathBuf,
305 default_ttl: Duration,
306) -> Result<MetricsBlockStore<TtlBlockStore<FullStack>>> {
307 let base = production_stack(path)?;
308 let ttl_config = TtlConfig {
309 default_ttl,
310 auto_cleanup: true,
311 cleanup_interval: Duration::from_secs(300), max_tracked_blocks: 1_000_000,
313 };
314 let ttl_store = TtlBlockStore::new(base, ttl_config);
315 Ok(MetricsBlockStore::new(ttl_store))
316}
317
318pub fn cache_stack(path: PathBuf) -> Result<MetricsBlockStore<TtlBlockStore<FullStack>>> {
328 ttl_production_stack(path, Duration::from_secs(3600)) }
330
331pub fn coalescing_memory_stack() -> MetricsBlockStore<CoalescingBlockStore<MemoryBlockStore>> {
341 let base = MemoryBlockStore::new();
342 let coalesce_config = CoalesceConfig::new(1000, Duration::from_millis(100));
343 let coalescing = CoalescingBlockStore::new(base, coalesce_config);
344 MetricsBlockStore::new(coalescing)
345}
346
347pub fn read_optimized_stack(path: PathBuf) -> Result<FullStack> {
356 StorageStackBuilder::new()
357 .with_config(BlockStoreConfig::production(path))
358 .with_cache(1024) .with_bloom(2_000_000) .build_full()
361}
362
363pub fn write_optimized_stack(path: PathBuf) -> Result<MonitoredDedupStack> {
373 let base = StorageStackBuilder::new()
374 .with_config(BlockStoreConfig::production(path))
375 .with_cache(100) .with_bloom(1_000_000)
377 .build_full()?;
378
379 let chunking_config = ChunkingConfig::default();
380 let dedup = DedupBlockStore::new(base, chunking_config);
381 Ok(MetricsBlockStore::new(dedup))
382}
383
384pub fn iot_stack(path: PathBuf) -> Result<FullStack> {
393 StorageStackBuilder::new()
394 .with_config(BlockStoreConfig::embedded(path))
395 .with_cache(5) .with_bloom(1_000) .build_full()
398}
399
400pub fn resilient_stack(path: PathBuf) -> Result<MetricsBlockStore<TtlBlockStore<FullStack>>> {
410 ttl_production_stack(path, Duration::from_secs(86400)) }
412
413pub fn ingestion_stack(path: PathBuf) -> Result<MonitoredDedupStack> {
423 let base = StorageStackBuilder::new()
424 .with_config(BlockStoreConfig::production(path))
425 .with_cache(200) .with_bloom(2_000_000)
427 .build_full()?;
428
429 let chunking_config = ChunkingConfig::default();
430 let dedup = DedupBlockStore::new(base, chunking_config);
431
432 Ok(MetricsBlockStore::new(dedup))
433}
434
435pub fn cdn_edge_stack(path: PathBuf) -> Result<MetricsBlockStore<TtlBlockStore<FullStack>>> {
445 let base = StorageStackBuilder::new()
446 .with_config(BlockStoreConfig::production(path))
447 .with_cache(2048) .with_bloom(5_000_000) .build_full()?;
450
451 let ttl_config = TtlConfig {
452 default_ttl: Duration::from_secs(3600), auto_cleanup: true,
454 cleanup_interval: Duration::from_secs(600), max_tracked_blocks: 5_000_000,
456 };
457 let ttl_store = TtlBlockStore::new(base, ttl_config);
458
459 Ok(MetricsBlockStore::new(ttl_store))
460}
461
462#[cfg(feature = "compression")]
472pub fn scientific_archive_stack(path: PathBuf) -> Result<MonitoredUltimateStack> {
473 let base = StorageStackBuilder::new()
474 .with_config(BlockStoreConfig::production(path))
475 .with_cache(256)
476 .with_bloom(1_000_000)
477 .build_full()?;
478
479 let compression_config = CompressionConfig {
480 algorithm: CompressionAlgorithm::Zstd,
481 level: 5, threshold: 512, max_ratio: 0.95, };
485 let compressed = CompressionBlockStore::new(base, compression_config);
486
487 let chunking_config = ChunkingConfig::default();
488 let dedup = DedupBlockStore::new(compressed, chunking_config);
489
490 Ok(MetricsBlockStore::new(dedup))
491}
492
493pub fn blockchain_stack(path: PathBuf) -> Result<MonitoredDedupStack> {
504 let base = StorageStackBuilder::new()
505 .with_config(BlockStoreConfig::production(path))
506 .with_cache(512) .with_bloom(10_000_000) .build_full()?;
509
510 let chunking_config = ChunkingConfig::default();
511 let dedup = DedupBlockStore::new(base, chunking_config);
512
513 Ok(MetricsBlockStore::new(dedup))
514}
515
516pub fn ml_model_stack(path: PathBuf) -> Result<MonitoredFullStack> {
525 let base = StorageStackBuilder::new()
526 .with_config(BlockStoreConfig::production(path))
527 .with_cache(1024) .with_bloom(100_000) .build_full()?;
530
531 Ok(MetricsBlockStore::new(base))
532}
533
534pub fn media_streaming_stack(path: PathBuf) -> Result<MetricsBlockStore<TtlBlockStore<FullStack>>> {
543 let base = StorageStackBuilder::new()
544 .with_config(BlockStoreConfig::production(path))
545 .with_cache(3072) .with_bloom(1_000_000)
547 .build_full()?;
548
549 let ttl_config = TtlConfig {
550 default_ttl: Duration::from_secs(7200), auto_cleanup: true,
552 cleanup_interval: Duration::from_secs(300), max_tracked_blocks: 1_000_000,
554 };
555 let ttl_store = TtlBlockStore::new(base, ttl_config);
556
557 Ok(MetricsBlockStore::new(ttl_store))
558}
559
560#[cfg(feature = "compression")]
570pub fn distributed_fs_stack(path: PathBuf) -> Result<MonitoredUltimateStack> {
571 let base = StorageStackBuilder::new()
572 .with_config(BlockStoreConfig::production(path))
573 .with_cache(1536) .with_bloom(5_000_000)
575 .build_full()?;
576
577 let compression_config = CompressionConfig {
578 algorithm: CompressionAlgorithm::Lz4, level: 1, threshold: 4096, max_ratio: 0.9,
582 };
583 let compressed = CompressionBlockStore::new(base, compression_config);
584
585 let chunking_config = ChunkingConfig::default();
586 let dedup = DedupBlockStore::new(compressed, chunking_config);
587
588 Ok(MetricsBlockStore::new(dedup))
589}
590
591#[cfg(test)]
592mod tests {
593 use super::*;
594
595 #[test]
596 fn test_builder_simple() {
597 let _stack = StorageStackBuilder::new()
598 .with_path(PathBuf::from("/tmp/test-simple"))
599 .build_simple();
600 assert!(_stack.is_ok());
601 }
602
603 #[test]
604 fn test_builder_cached() {
605 let _stack = StorageStackBuilder::new()
606 .with_path(PathBuf::from("/tmp/test-cached"))
607 .with_cache(10)
608 .build_cached();
609 assert!(_stack.is_ok());
610 }
611
612 #[test]
613 fn test_builder_full() {
614 let _stack = StorageStackBuilder::new()
615 .with_path(PathBuf::from("/tmp/test-full"))
616 .with_cache(10)
617 .with_bloom(1000)
618 .build_full();
619 assert!(_stack.is_ok());
620 }
621
622 #[test]
623 fn test_development_stack() {
624 let _stack = development_stack();
625 assert!(_stack.is_ok());
626 }
627
628 #[test]
629 fn test_testing_stack() {
630 let _stack = testing_stack();
631 assert!(_stack.is_ok());
632 }
633}