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