use super::*;
use crate::background::{CheckpointWorkContext, CheckpointWorkError};
use std::ops::{Deref, DerefMut};
use std::result::Result;
#[derive(Debug, Clone, Default)]
pub(super) struct BasicStatisticsState {
pub(super) computed_at_commit_epoch: u64,
pub(super) node_count: u64,
pub(super) relationship_count: u64,
pub(super) label_counts: CowSegmentedMap<LabelId, u64>,
pub(super) rel_type_counts: CowSegmentedMap<RelTypeId, u64>,
}
impl From<BasicGraphStatistics> for BasicStatisticsState {
fn from(statistics: BasicGraphStatistics) -> Self {
Self {
computed_at_commit_epoch: statistics.computed_at_commit_epoch,
node_count: statistics.node_count,
relationship_count: statistics.relationship_count,
label_counts: statistics.label_counts.into(),
rel_type_counts: statistics.rel_type_counts.into(),
}
}
}
impl BasicStatisticsState {
pub(super) fn materialize(&self, commit_epoch: u64) -> BasicGraphStatistics {
BasicGraphStatistics {
computed_at_commit_epoch: commit_epoch,
node_count: self.node_count,
relationship_count: self.relationship_count,
label_counts: self
.label_counts
.iter()
.map(|(key, value)| (*key, *value))
.collect(),
rel_type_counts: self
.rel_type_counts
.iter()
.map(|(key, value)| (*key, *value))
.collect(),
}
}
pub(super) fn materialize_with_work_context(
&self,
commit_epoch: u64,
work: &CheckpointWorkContext,
) -> Result<BasicGraphStatistics, CheckpointWorkError> {
let mut statistics = BasicGraphStatistics {
computed_at_commit_epoch: commit_epoch,
node_count: self.node_count,
relationship_count: self.relationship_count,
..BasicGraphStatistics::default()
};
for (label, count) in self.label_counts.iter() {
let unit = work.start_unit()?;
statistics.label_counts.insert(*label, *count);
unit.finish();
}
for (rel_type, count) in self.rel_type_counts.iter() {
let unit = work.start_unit()?;
statistics.rel_type_counts.insert(*rel_type, *count);
unit.finish();
}
work.checkpoint()?;
Ok(statistics)
}
}
#[derive(Debug, Clone, Default)]
pub(super) struct CheckpointStatisticsState {
advanced: CowSegment<GraphStatistics>,
pub(super) index_samples: CowSegmentedMap<IndexId, IndexStatisticsSample>,
}
impl From<GraphStatistics> for CheckpointStatisticsState {
fn from(mut statistics: GraphStatistics) -> Self {
let index_samples = std::mem::take(&mut statistics.index_samples).into();
Self {
advanced: statistics.into(),
index_samples,
}
}
}
impl Deref for CheckpointStatisticsState {
type Target = GraphStatistics;
fn deref(&self) -> &GraphStatistics {
&self.advanced
}
}
impl DerefMut for CheckpointStatisticsState {
fn deref_mut(&mut self) -> &mut GraphStatistics {
&mut self.advanced
}
}
impl CheckpointStatisticsState {
pub(super) fn materialize(&self) -> GraphStatistics {
let mut statistics = (*self.advanced).clone();
statistics.index_samples = self
.index_samples
.iter()
.map(|(key, value)| (*key, *value))
.collect();
statistics
}
pub(super) fn with_work_context(
mut statistics: GraphStatistics,
work: &CheckpointWorkContext,
) -> Result<Self, CheckpointWorkError> {
let mut index_samples = CowSegmentedMap::default();
for (id, sample) in std::mem::take(&mut statistics.index_samples) {
let unit = work.start_unit()?;
index_samples.insert(id, sample);
unit.finish();
}
let unit = work.start_unit()?;
let result = Self {
advanced: statistics.into(),
index_samples,
};
unit.finish();
work.checkpoint()?;
Ok(result)
}
pub(super) fn retain_valid_index_samples(&mut self, catalog: &Catalog) {
self.index_samples
.retain(|id, sample| catalog.supports_index_statistics(*id) && sample.is_valid());
}
}
pub(super) fn decrement_statistic_counter<K: Ord + Clone + crate::cow::CowPageWeight>(
counters: &mut CowSegmentedMap<K, u64>,
key: &K,
) {
let Some(mut count) = counters.get_mut(key) else {
return;
};
*count = count.saturating_sub(1);
let empty = *count == 0;
drop(count);
if empty {
counters.remove(key);
}
}
#[cfg(test)]
#[path = "statistics_state/tests.rs"]
mod tests;