use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use crate::component::Component;
use crate::labels::Labels;
#[derive(Default)]
pub struct CellMap {
inner: Mutex<HashMap<String, Arc<RwLock<Component>>>>,
}
impl CellMap {
pub fn new() -> Self {
Self {
inner: Mutex::new(HashMap::new()),
}
}
pub fn resolve(
&self,
parent: &Arc<RwLock<Component>>,
coord: &Labels,
) -> Arc<RwLock<Component>> {
let key = coord.to_prometheus();
let mut map = self.inner.lock().unwrap_or_else(|e| e.into_inner());
if let Some(existing) = map.get(&key) {
return existing.clone();
}
let mut component = Component::new(coord.clone(), HashMap::new());
component.set_state(crate::component::ComponentState::Running);
let child = Arc::new(RwLock::new(component));
crate::component::attach(parent, &child);
map.insert(key, child.clone());
child
}
pub fn len(&self) -> usize {
self.inner.lock().unwrap_or_else(|e| e.into_inner()).len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub fn resolve_under(parent: &Arc<RwLock<Component>>, coord: &Labels) -> Arc<RwLock<Component>> {
let cells = parent.read().unwrap_or_else(|e| e.into_inner()).cells();
cells.resolve(parent, coord)
}
#[cfg(test)]
mod tests {
use super::*;
fn parent() -> Arc<RwLock<Component>> {
Arc::new(RwLock::new(Component::new(
Labels::of("phase", "finalize"),
HashMap::new(),
)))
}
#[test]
fn a_coordinate_resolves_to_one_stable_cell() {
let p = parent();
let cells = CellMap::new();
let a = cells.resolve(&p, &Labels::of("tier", "24"));
let b = cells.resolve(&p, &Labels::of("tier", "24"));
assert!(Arc::ptr_eq(&a, &b), "one coordinate must be one cell");
assert_eq!(cells.len(), 1);
}
#[test]
fn distinct_values_are_distinct_cells() {
let p = parent();
let cells = CellMap::new();
let a = cells.resolve(&p, &Labels::of("tier", "24"));
let b = cells.resolve(&p, &Labels::of("tier", "25"));
assert!(!Arc::ptr_eq(&a, &b));
assert_eq!(cells.len(), 2);
for c in [&a, &b] {
let g = c.write().unwrap();
let mut g = g;
g.register_instrument(
"compaction_bytes_out",
crate::component::InstrumentRef::Gauge(Arc::new(
crate::instruments::gauge::ValueGauge::new(Labels::default()),
)),
)
.expect("same family on a different cell must not collide");
}
}
#[test]
fn a_cell_inherits_the_parent_dimensions() {
let p = parent();
let cells = CellMap::new();
let c = cells.resolve(&p, &Labels::of("tier", "24"));
let eff = c.read().unwrap().effective_labels().to_prometheus();
assert!(
eff.contains("phase=") && eff.contains("tier="),
"cell must carry inherited + own dimensions, got {eff}"
);
}
#[test]
fn a_multi_dimension_coordinate_is_a_single_child() {
let p = parent();
let cells = CellMap::new();
let coord = Labels::of("tier", "24").with("keyspace", "baselines");
let c = cells.resolve(&p, &coord);
assert_eq!(
c.read().unwrap().child_count(),
0,
"a coordinate must not nest one dimension inside another"
);
let eff = c.read().unwrap().effective_labels().to_prometheus();
assert!(
eff.contains("tier=") && eff.contains("keyspace="),
"both dimensions belong to one cell, got {eff}"
);
assert_eq!(p.read().unwrap().child_count(), 1);
}
#[test]
fn a_cell_refines_the_parents_identity_rather_than_replacing_it() {
let phase = parent();
let op = Arc::new(RwLock::new(Component::new(
Labels::of("op", "read_history"),
HashMap::new(),
)));
crate::component::attach(&phase, &op);
let cell = resolve_under(&op, &Labels::of("tier", "24"));
let eff = cell.read().unwrap().effective_labels().to_prometheus();
for owned in ["phase=", "op=", "tier="] {
assert!(
eff.contains(owned),
"a cell must carry every dimension its ancestors own; {owned} \
missing from {eff}"
);
}
}
#[test]
#[should_panic(expected = "sibling-identity violation")]
fn concurrent_siblings_cannot_share_a_label_set() {
let p = parent();
let _first = {
let c = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &c);
c };
let second = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &second);
}
#[test]
fn a_label_set_may_be_reused_after_the_previous_component_stops() {
use crate::component::ComponentState;
let p = parent();
let first = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &first);
first.write().unwrap().set_state(ComponentState::Stopped);
let second = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &second); assert_eq!(p.read().unwrap().child_count(), 2);
}
#[test]
fn a_dropped_component_releases_its_claim() {
let p = parent();
{
let c = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &c);
crate::component::detach(&p, &c);
}
let again = Arc::new(RwLock::new(Component::new(
Labels::of("tier", "24"),
HashMap::new(),
)));
crate::component::attach(&p, &again); }
#[test]
fn distinct_siblings_still_attach() {
let p = parent();
for v in ["24", "25", "26"] {
let c = Arc::new(RwLock::new(Component::new(
Labels::of("tier", v),
HashMap::new(),
)));
crate::component::attach(&p, &c);
}
assert_eq!(p.read().unwrap().child_count(), 3);
}
#[test]
fn the_resolver_is_what_prevents_a_duplicated_cell_identity() {
let p = parent();
let coord = Labels::of("tier", "24");
for _ in 0..5 {
resolve_under(&p, &coord);
}
assert_eq!(
p.read().unwrap().child_count(),
1,
"repeated resolution must not multiply cells for one coordinate"
);
}
#[test]
fn repeated_cell_resolution_does_not_trip_the_sibling_check() {
let p = parent();
let coord = Labels::of("tier", "24");
let first = resolve_under(&p, &coord);
let again = resolve_under(&p, &coord);
assert!(
Arc::ptr_eq(&first, &again),
"memoisation must return the existing cell rather than attach a twin"
);
assert_eq!(p.read().unwrap().child_count(), 1);
}
}