Skip to main content

nodedb_lite/engine/columnar/store/
state.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Columnar engine state and collection metadata.
4
5use crate::storage::engine::StorageEngine;
6#[cfg(not(target_arch = "wasm32"))]
7use crate::sync::outbound::columnar::ColumnarOutbound;
8#[cfg(not(target_arch = "wasm32"))]
9use crate::sync::outbound::timeseries::TimeseriesOutbound;
10use nodedb_columnar::mutation::MutationEngine;
11use nodedb_mem::ScopedMemory;
12use nodedb_types::columnar::ColumnarProfile;
13use std::collections::HashMap;
14use std::sync::{Arc, Mutex, RwLock};
15
16/// Per-collection segment metadata.
17#[derive(
18    Debug,
19    Clone,
20    serde::Serialize,
21    serde::Deserialize,
22    zerompk::ToMessagePack,
23    zerompk::FromMessagePack,
24)]
25pub(in crate::engine::columnar) struct SegmentMeta {
26    pub(in crate::engine::columnar) segment_id: u32,
27    pub(in crate::engine::columnar) row_count: u64,
28    /// Milliseconds since Unix epoch when this segment was first written.
29    /// Used by bitemporal purge to determine which superseded segments are
30    /// eligible for deletion.
31    #[serde(default)]
32    pub(super) system_time_from_ms: i64,
33    /// For bitemporal collections: the millisecond timestamp when the last
34    /// live row in this segment was deleted (compacted away). `None` means
35    /// the segment still has live rows. Segments with `Some(t)` where
36    /// `t < cutoff_ms` are eligible for physical deletion by `purge_bitemporal_before`.
37    #[serde(default)]
38    pub(in crate::engine::columnar) fully_deleted_at_ms: Option<i64>,
39}
40
41/// Per-collection state. Wrapped in `Mutex` inside `ColumnarEngine`.
42pub(in crate::engine::columnar) struct CollectionState {
43    pub(in crate::engine::columnar) mutation: MutationEngine,
44    pub(super) profile: ColumnarProfile,
45    /// Whether this collection has bitemporal system-time tracking.
46    pub(super) bitemporal: bool,
47    /// Ordered list of flushed segments (including fully-deleted tombstones for
48    /// bitemporal collections — they persist until `purge_bitemporal_before` clears them).
49    pub(in crate::engine::columnar) segments: Vec<SegmentMeta>,
50    /// Next segment ID to assign.
51    pub(super) next_segment_id: u32,
52}
53
54pub(super) type CollectionMap = HashMap<String, Arc<Mutex<CollectionState>>>;
55
56/// Manages all columnar collections for a NodeDbLite instance.
57pub struct ColumnarEngine<S: StorageEngine> {
58    pub(in crate::engine::columnar) storage: Arc<S>,
59    pub(super) collections: RwLock<CollectionMap>,
60    /// Optional outbound queue for plain columnar insert sync.
61    /// `None` when sync is disabled or not yet configured.
62    #[cfg(not(target_arch = "wasm32"))]
63    pub(super) outbound: Option<Arc<ColumnarOutbound<S>>>,
64    /// Optional outbound queue for timeseries-profile insert sync.
65    ///
66    /// Timeseries collections must use `TimeseriesPush` frames on Origin
67    /// (the columnar `MutationEngine` and the timeseries engine are separate
68    /// storage paths on Origin).  When this queue is present, inserts into
69    /// collections with `ColumnarProfile::Timeseries` are enqueued here
70    /// instead of `outbound`.
71    #[cfg(not(target_arch = "wasm32"))]
72    pub(super) timeseries_outbound: Option<Arc<TimeseriesOutbound<S>>>,
73    /// Governor handle bound to the columnar engine budget. Cloned into every
74    /// `SegmentWriter` this engine creates.
75    pub(super) memory: ScopedMemory,
76}