laminar_db/config.rs
1//! Configuration for `LaminarDB`.
2#![allow(clippy::disallowed_types)] // cold path
3
4use std::collections::HashMap;
5use std::path::PathBuf;
6
7use laminar_connectors::connector::DeliveryGuarantee;
8use laminar_core::streaming::{BackpressureStrategy, StreamCheckpointConfig};
9
10/// SQL identifier case sensitivity mode.
11///
12/// Controls how unquoted SQL identifiers are matched against Arrow
13/// schema field names.
14///
15/// `LaminarDB` defaults to [`CaseSensitive`](IdentifierCaseSensitivity::CaseSensitive)
16/// (normalization disabled) so that mixed-case column names from
17/// external sources (Kafka, CDC, `WebSocket`) work without double-quoting.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub enum IdentifierCaseSensitivity {
20 /// Preserve case as-written, case-sensitive matching (default).
21 ///
22 /// `SELECT tradeId` matches only `tradeId` in the schema.
23 /// This is the recommended mode for financial / `IoT` data sources
24 /// that use `camelCase` or `PascalCase` field names.
25 #[default]
26 CaseSensitive,
27 /// Normalize unquoted identifiers to lowercase (standard SQL behaviour).
28 ///
29 /// `SELECT TradeId` becomes `SELECT tradeid` before schema matching.
30 /// Use this if all your schemas use lowercase column names.
31 Lowercase,
32}
33
34/// S3 storage class tiering configuration.
35///
36/// Controls how checkpoint objects are assigned to S3 storage classes
37/// for cost optimization. Active checkpoints use the hot tier (fast access),
38/// older checkpoints are moved to warm/cold tiers via S3 Lifecycle rules.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct TieringConfig {
41 /// Storage class for active checkpoints (e.g., `"EXPRESS_ONE_ZONE"`, `"STANDARD"`).
42 pub hot_class: String,
43 /// Storage class for older checkpoints (e.g., `"STANDARD"`).
44 pub warm_class: String,
45 /// Storage class for archive checkpoints (e.g., `"GLACIER_IR"`). Empty = no cold tier.
46 pub cold_class: String,
47 /// Time before moving objects from hot to warm tier (seconds).
48 pub hot_retention_secs: u64,
49 /// Time before moving objects from warm to cold tier (seconds). 0 = no cold tier.
50 pub warm_retention_secs: u64,
51}
52
53impl Default for TieringConfig {
54 fn default() -> Self {
55 Self {
56 hot_class: "STANDARD".to_string(),
57 warm_class: "STANDARD".to_string(),
58 cold_class: String::new(),
59 hot_retention_secs: 86400, // 24h
60 warm_retention_secs: 604_800, // 7d
61 }
62 }
63}
64
65/// Thread-per-core runtime configuration.
66///
67/// Controls CPU pinning, core count, and NUMA settings for the TPC
68/// pipeline. When `None` on [`LaminarConfig`], auto-detected defaults
69/// are used.
70#[derive(Debug, Clone)]
71pub struct TpcRuntimeConfig {
72 /// Number of cores (`None` = auto-detect via `available_parallelism`).
73 pub num_cores: Option<usize>,
74 /// Pin core threads to CPUs starting from `cpu_start`.
75 pub cpu_pinning: bool,
76 /// First CPU ID for pinning.
77 pub cpu_start: usize,
78 /// Enable NUMA-aware memory allocation.
79 pub numa_aware: bool,
80}
81
82impl TpcRuntimeConfig {
83 /// Auto-detect system capabilities.
84 #[must_use]
85 pub fn auto() -> Self {
86 Self {
87 num_cores: None,
88 cpu_pinning: cfg!(target_os = "linux"),
89 cpu_start: 0,
90 numa_aware: cfg!(target_os = "linux"),
91 }
92 }
93}
94
95impl Default for TpcRuntimeConfig {
96 fn default() -> Self {
97 Self::auto()
98 }
99}
100
101/// Configuration for a `LaminarDB` instance.
102#[derive(Debug, Clone)]
103pub struct LaminarConfig {
104 /// Default buffer size for streaming channels.
105 pub default_buffer_size: usize,
106 /// Default backpressure strategy.
107 pub default_backpressure: BackpressureStrategy,
108 /// Storage directory for WAL and checkpoints (`None` = in-memory only).
109 pub storage_dir: Option<PathBuf>,
110 /// Streaming checkpoint configuration (`None` = disabled).
111 pub checkpoint: Option<StreamCheckpointConfig>,
112 /// SQL identifier case sensitivity mode.
113 pub identifier_case: IdentifierCaseSensitivity,
114 /// Object store URL for cloud checkpoint storage (e.g., `s3://bucket/prefix`).
115 pub object_store_url: Option<String>,
116 /// Explicit credential/config overrides for the object store builder.
117 pub object_store_options: HashMap<String, String>,
118 /// S3 storage class tiering configuration (`None` = use default STANDARD).
119 pub tiering: Option<TieringConfig>,
120 /// Thread-per-core runtime configuration (`None` = use tokio mode).
121 pub tpc: Option<TpcRuntimeConfig>,
122 /// End-to-end delivery guarantee (default: at-least-once).
123 pub delivery_guarantee: DeliveryGuarantee,
124}
125
126impl Default for LaminarConfig {
127 fn default() -> Self {
128 Self {
129 default_buffer_size: 65536,
130 default_backpressure: BackpressureStrategy::Block,
131 storage_dir: None,
132 checkpoint: None,
133 identifier_case: IdentifierCaseSensitivity::default(),
134 object_store_url: None,
135 object_store_options: HashMap::new(),
136 tiering: None,
137 tpc: None,
138 delivery_guarantee: DeliveryGuarantee::default(),
139 }
140 }
141}