Skip to main content

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}