use std::collections::{BTreeMap, HashMap};
use nodedb_types::timeseries::{SegmentRef, SeriesId, TimeRange};
#[derive(Debug)]
pub struct SegmentIndex {
entries: HashMap<SeriesId, BTreeMap<i64, SegmentRef>>,
total_segments: usize,
total_bytes: u64,
}
impl SegmentIndex {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
total_segments: 0,
total_bytes: 0,
}
}
pub fn add(&mut self, series_id: SeriesId, seg: SegmentRef) {
self.total_bytes += seg.size_bytes;
self.total_segments += 1;
self.entries
.entry(series_id)
.or_default()
.insert(seg.min_ts, seg);
}
pub fn query(&self, series_id: SeriesId, range: &TimeRange) -> Vec<&SegmentRef> {
let Some(tree) = self.entries.get(&series_id) else {
return Vec::new();
};
tree.values()
.filter(|seg| seg.max_ts >= range.start_ms && seg.min_ts <= range.end_ms)
.collect()
}
pub fn segments_older_than(&self, cutoff_ts: i64) -> Vec<(SeriesId, i64, SegmentRef)> {
let mut result = Vec::new();
for (&series_id, tree) in &self.entries {
for (&min_ts, seg) in tree {
if seg.max_ts < cutoff_ts {
result.push((series_id, min_ts, seg.clone()));
}
}
}
result
}
pub fn remove(&mut self, series_id: SeriesId, min_ts: i64) -> Option<SegmentRef> {
let tree = self.entries.get_mut(&series_id)?;
let seg = tree.remove(&min_ts)?;
self.total_bytes = self.total_bytes.saturating_sub(seg.size_bytes);
self.total_segments = self.total_segments.saturating_sub(1);
if tree.is_empty() {
self.entries.remove(&series_id);
}
Some(seg)
}
pub fn series_count(&self) -> usize {
self.entries.len()
}
pub fn total_segments(&self) -> usize {
self.total_segments
}
pub fn total_bytes(&self) -> u64 {
self.total_bytes
}
}
impl Default for SegmentIndex {
fn default() -> Self {
Self::new()
}
}