Split src/engine/mod.rs into handle/message/snapshot submodules
Pure code-motion refactor, no logic changes. Follows the repo convention of one struct/enum + its impl per module file: - engine/handle.rs: the left-right write/read plumbing (EngineOp, IndexWriter, IndexReadHandle, IndexReader, EngineHandle) and the actor loop (spawn/run) that owns EngineSnapshot. - engine/message.rs: EngineQuery/EngineMessage/EngineResponse. - engine/snapshot/: EngineSnapshot itself, split by concern into params.rs (declaration + auto-detect), metrics.rs (declare/apply/ backfill), filter.rs (search-bar filter compilation/eval), sort.rs (sort-helper indexes), and query.rs (handle_query_inner + PromQL evaluation), with mod.rs holding the struct and the accessors shared across all of them. - engine/tests.rs: the inline test module, kept as one file (per the task's own escape hatch) since most tests exercise ingest -> declare -> query across several of the new submodules at once rather than one in isolation. Visibility was narrowed per call site: pub(super) where only sibling snapshot submodules need an item, pub(crate) where engine::handle or engine::tests (outside the snapshot subtree) also need it. cargo build --all-targets and cargo test are green (291 passed, 1 ignored, same as before the split). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1ZJ3SrayzLzVndhVq9BmS
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3b3ace146a
commit
f19fa50a25
@@ -0,0 +1,163 @@
|
||||
//! `EngineSnapshot` is the actor's live state: ingested log lines, declared params/metrics,
|
||||
//! computed metric buckets, and the sort-helper indexes built on demand — all stored in one
|
||||
//! flat `BTreeMap<IndexKey, DataValue>` and read/written through the left-right index in
|
||||
//! `super::handle`. Its impl is split across the submodules below by concern; this file holds
|
||||
//! the struct itself plus the accessors every submodule builds on.
|
||||
|
||||
pub(crate) mod filter;
|
||||
pub(crate) mod metrics;
|
||||
pub(crate) mod params;
|
||||
pub(crate) mod query;
|
||||
pub(crate) mod sort;
|
||||
|
||||
pub(crate) use filter::eval_json_comparison;
|
||||
|
||||
use crate::engine::data_value::{DataValue, MetricPrimitiveKind, ParamDeclaration};
|
||||
use crate::engine::index_key::IndexKey;
|
||||
use crate::engine::message::{EngineQuery, EngineResponse};
|
||||
use crate::engine::timestamp::Timestamp;
|
||||
use query::handle_query_inner;
|
||||
use sort::{SortHelperAccess, SortHelperIndexEntry};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct EngineSnapshot {
|
||||
pub(crate) index: BTreeMap<IndexKey, DataValue>,
|
||||
pub(crate) sort_helper_indexes: HashMap<String, SortHelperIndexEntry>,
|
||||
pub(crate) log_count: usize,
|
||||
pub(crate) approx_bytes_total: u64,
|
||||
pub(crate) ingest_lag_high_watermark_ms: i64,
|
||||
}
|
||||
|
||||
impl EngineSnapshot {
|
||||
pub(crate) fn metric_declarations_range(
|
||||
&self,
|
||||
) -> impl Iterator<
|
||||
Item = (
|
||||
&str,
|
||||
&str,
|
||||
&[String],
|
||||
Option<&str>,
|
||||
Option<&BTreeMap<String, String>>,
|
||||
Option<&BTreeMap<String, String>>,
|
||||
),
|
||||
> {
|
||||
self.index
|
||||
.range(IndexKey::ParamMetricSplit..IndexKey::MetricBucketSplit)
|
||||
.filter_map(|(key, value)| match (key, value) {
|
||||
(
|
||||
IndexKey::MetricDeclaration { name },
|
||||
DataValue::MetricDeclaration {
|
||||
message_match_regex,
|
||||
label_params,
|
||||
value_param,
|
||||
matched_labels,
|
||||
unmatched_labels,
|
||||
},
|
||||
) => Some((
|
||||
name.as_str(),
|
||||
message_match_regex.as_str(),
|
||||
label_params.as_slice(),
|
||||
value_param.as_deref(),
|
||||
matched_labels.as_ref(),
|
||||
unmatched_labels.as_ref(),
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn param_declarations_range(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&str, &str, &str, Option<&str>, MetricPrimitiveKind, bool, bool, bool)> {
|
||||
self.index
|
||||
.range(IndexKey::LogParamSplit..IndexKey::ParamMetricSplit)
|
||||
.filter_map(|(key, value)| match (key, value) {
|
||||
(
|
||||
IndexKey::ParamDeclaration { name },
|
||||
DataValue::ParamDeclaration(ParamDeclaration {
|
||||
name: _,
|
||||
message_match_regex,
|
||||
capture_group,
|
||||
json_field_path,
|
||||
kind,
|
||||
elapsed_since_last,
|
||||
auto_derived,
|
||||
log_stream_gated,
|
||||
}),
|
||||
) => Some((
|
||||
name.as_str(),
|
||||
message_match_regex.as_str(),
|
||||
capture_group.as_str(),
|
||||
json_field_path.as_deref(),
|
||||
*kind,
|
||||
*elapsed_since_last,
|
||||
*auto_derived,
|
||||
*log_stream_gated,
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn approx_log_bytes(text: &str) -> u64 {
|
||||
text.len() as u64
|
||||
}
|
||||
|
||||
impl EngineSnapshot {
|
||||
pub(crate) fn from_index(index: BTreeMap<IndexKey, DataValue>) -> Self {
|
||||
EngineSnapshot { index, ..Default::default() }
|
||||
}
|
||||
|
||||
pub(crate) fn evict_excess_logs(&mut self, max_logs: Option<usize>) {
|
||||
let Some(max_logs) = max_logs else { return };
|
||||
while self.log_count > max_logs {
|
||||
let Some(oldest_key) = self
|
||||
.index
|
||||
.range(IndexKey::Start..IndexKey::LogParamSplit)
|
||||
.next()
|
||||
.map(|(key, _)| key.clone())
|
||||
else {
|
||||
break;
|
||||
};
|
||||
if let Some(DataValue::LogLiteral { text }) = self.index.get(&oldest_key) {
|
||||
self.approx_bytes_total = self.approx_bytes_total.saturating_sub(approx_log_bytes(text));
|
||||
}
|
||||
self.index.remove(&oldest_key);
|
||||
self.log_count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn logs_range(&self) -> impl Iterator<Item = (u64, Timestamp, &str)> {
|
||||
self.index.range(IndexKey::Start..IndexKey::LogParamSplit).filter_map(|(key, value)| {
|
||||
match (key, value) {
|
||||
(IndexKey::IngestedLog { sequence, timestamp }, DataValue::LogLiteral { text }) => {
|
||||
Some((*sequence, *timestamp, text.as_str()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn logs_since(
|
||||
&self,
|
||||
before_sequence: u64,
|
||||
since_ms: i64,
|
||||
now_ms: i64,
|
||||
) -> impl Iterator<Item = (u64, Timestamp, &str)> {
|
||||
self.logs_range().filter(move |(sequence, timestamp, _)| {
|
||||
*sequence < before_sequence
|
||||
&& timestamp.as_millis() > since_ms
|
||||
&& timestamp.as_millis() <= now_ms
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EngineSnapshot {
|
||||
pub(crate) fn handle_query_ro(&self, query: EngineQuery) -> EngineResponse {
|
||||
handle_query_inner(self, query, SortHelperAccess::Immutable(&self.sort_helper_indexes))
|
||||
}
|
||||
|
||||
pub(crate) fn has_sort_helper_index(&self, sort_by: &str) -> bool {
|
||||
self.sort_helper_indexes.contains_key(sort_by)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user