Skip to main content

laminar_db/pipeline/
config.rs

1//! Pipeline configuration.
2
3use std::sync::Arc;
4use std::time::Duration;
5
6use laminar_connectors::connector::DeliveryGuarantee;
7
8use crate::checkpoint_coordinator::committed_reads::CheckpointDemand;
9use crate::config::BackpressurePolicy;
10
11/// Checkpoint triggering configured for the running pipeline.
12///
13/// The three states mirror [`LaminarConfig::checkpoint`](crate::config::LaminarConfig::checkpoint)
14/// without allowing an enabled flag and timer interval to contradict each other.
15#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
16pub enum CheckpointSchedule {
17    /// No durable checkpoint service is configured.
18    #[default]
19    Disabled,
20    /// Checkpoints run only when explicitly requested.
21    Manual,
22    /// Checkpoints normally wait this long after a terminal outcome. Bounded durable-output
23    /// pressure may accelerate the next automatic admission; requests may also be explicit.
24    Periodic(Duration),
25}
26
27impl CheckpointSchedule {
28    /// Whether the durable checkpoint service is configured.
29    #[must_use]
30    pub const fn is_enabled(self) -> bool {
31        !matches!(self, Self::Disabled)
32    }
33
34    /// The periodic cadence, if automatic checkpoints are configured.
35    #[must_use]
36    pub const fn periodic_interval(self) -> Option<Duration> {
37        match self {
38            Self::Periodic(interval) => Some(interval),
39            Self::Disabled | Self::Manual => None,
40        }
41    }
42}
43
44/// Periodic checkpoints that recent reads waiting for a newer committed cut bring forward.
45#[derive(Debug, Clone)]
46pub(crate) struct RecentReadCheckpoints {
47    /// Least time from the end of one checkpoint to the start of one a read asked for.
48    pub(crate) interval: Duration,
49    pub(crate) demand: Arc<CheckpointDemand>,
50}
51
52/// Configuration for the event-driven connector pipeline.
53#[derive(Debug, Clone)]
54pub struct PipelineConfig {
55    /// Maximum records per `poll_batch()` call.
56    pub max_poll_records: usize,
57
58    /// Shared channel capacity for all source senders → coordinator.
59    pub channel_capacity: usize,
60
61    /// Shared Arrow-byte limit for source messages, including parked input (default 64 MiB).
62    /// Each producer may additionally hold one batch up to this limit while waiting for a
63    /// cursor or capacity. Staged/graph buffers and connector decode scratch are excluded.
64    pub source_queue_max_bytes: usize,
65
66    /// Fallback poll interval when a source returns no `data_ready_notify`.
67    pub fallback_poll_interval: Duration,
68
69    /// Whether checkpoints are disabled, manual-only, or periodic.
70    pub checkpoint_schedule: CheckpointSchedule,
71
72    /// Periodic checkpoints that waiting recent reads may bring forward.
73    pub(crate) recent_read_checkpoints: Option<RecentReadCheckpoints>,
74
75    /// Sleep after the first event in a cycle to let more data accumulate.
76    ///
77    /// Bounds SQL executions per second without sacrificing data. The bounded
78    /// channel provides natural backpressure during the window. `ZERO` = no batching.
79    pub batch_window: Duration,
80
81    /// Sole checkpoint-derived control-plane budget. Each connector startup stage and checkpoint
82    /// barrier creates one absolute deadline from this duration; individual connectors cannot
83    /// reset it.
84    pub checkpoint_timeout: Duration,
85
86    /// End-to-end delivery guarantee for the pipeline.
87    pub delivery_guarantee: DeliveryGuarantee,
88
89    /// Maximum wall-clock time for a single processing cycle (nanoseconds). Default: 10ms.
90    pub cycle_budget_ns: u64,
91
92    /// Maximum wall-clock time for the message drain phase (nanoseconds). Default: 1ms.
93    pub drain_budget_ns: u64,
94
95    /// Maximum wall-clock time for per-query execution within a cycle (nanoseconds). Default: 8ms.
96    pub query_budget_ns: u64,
97
98    /// Per-input-port batch cap. Default: 256.
99    pub max_input_buf_batches: usize,
100
101    /// Per-input-port retained Arrow-byte cap, including source priming. `None` = disabled.
102    /// Shared buffers are charged independently on each port; executed output that would
103    /// exceed a limit halts the pipeline before publication under lossless policies.
104    pub max_input_buf_bytes: Option<usize>,
105
106    /// What to do when either cap is exceeded.
107    pub backpressure_policy: BackpressurePolicy,
108
109    /// Isolate queries that share a source into independent failure domains.
110    /// Off: they fault and recover together; on: a fault holds back only its own offset.
111    pub shared_source_isolation: bool,
112
113    /// Per-source cap on the in-memory replay buffer used by `shared_source_isolation`.
114    /// On overflow the engine falls back to whole-pipeline recovery. Ignored when the
115    /// flag is off.
116    pub max_replay_buffer_bytes: usize,
117}
118
119impl Default for PipelineConfig {
120    fn default() -> Self {
121        Self {
122            max_poll_records: 1024,
123            channel_capacity: 64,
124            source_queue_max_bytes: crate::config::DEFAULT_SOURCE_QUEUE_MAX_BYTES,
125            fallback_poll_interval: Duration::from_millis(10),
126            checkpoint_schedule: CheckpointSchedule::Disabled,
127            recent_read_checkpoints: None,
128            batch_window: Duration::from_millis(5),
129            checkpoint_timeout: Duration::from_secs(30),
130            delivery_guarantee: DeliveryGuarantee::default(),
131            cycle_budget_ns: 10_000_000, // 10ms
132            drain_budget_ns: 1_000_000,  // 1ms
133            query_budget_ns: 8_000_000,  // 8ms
134            max_input_buf_batches: 256,
135            max_input_buf_bytes: None,
136            backpressure_policy: BackpressurePolicy::default(),
137            shared_source_isolation: false,
138            max_replay_buffer_bytes: 256 * 1024 * 1024, // 256 MiB per source
139        }
140    }
141}
142
143impl PipelineConfig {
144    /// Private rollback budget for a failed connector startup stage. This is deliberately fixed:
145    /// cleanup is fail-safe implementation policy, not another latency tuning dimension.
146    pub(crate) const CONNECTOR_STARTUP_CLEANUP_TIMEOUT: Duration = Duration::from_secs(15);
147}