use super::apply::Flush;
use crate::TViewResult;
use crate::queue::RefreshKey;
use crate::queue::state;
pub(super) fn flush_pending() -> TViewResult<()> {
let state::Pending {
queue,
patches,
fanout,
} = state::drain();
if queue.is_empty() && fanout.is_empty() {
return Ok(());
}
crate::revision::check();
crate::queue::affected::begin_flush();
let timer = crate::metrics::metrics_api::record_refresh_start();
let mut flush = Flush::new(crate::cache::graph()?, queue, patches);
flush.apply_fanouts(fanout)?;
loop {
while let Some((entity, keys)) = flush.next_entity() {
flush.apply_entity(&entity, keys)?;
flush.iteration += 1;
let max_depth = crate::config::max_propagation_depth();
if flush.iteration > max_depth {
return Err(crate::TViewError::DepthExceeded {
what: "propagation",
depth: flush.iteration,
max_depth,
});
}
}
let late = state::drain();
if late.queue.is_empty() && late.fanout.is_empty() {
break;
}
flush.patches.extend(late.patches);
for key in &late.queue {
flush.processed.remove(key);
}
flush.pending = late.queue;
flush.apply_fanouts(late.fanout)?;
}
let mut counts: std::collections::BTreeMap<&str, i64> = std::collections::BTreeMap::new();
for key in &flush.processed {
*counts.entry(&key.entity).or_insert(0) += 1;
}
for (entity, count) in counts {
crate::audit::log_refresh(entity, count);
}
crate::metrics::metrics_api::record_refresh_complete(
flush.processed.len(),
flush.iteration - 1,
&timer,
);
Ok(())
}
impl Flush {
fn next_entity(&mut self) -> Option<(String, Vec<RefreshKey>)> {
if self.pending.is_empty() {
return None;
}
let sorted = self.graph.sort_keys(self.pending.drain().collect());
let entity = sorted[0].entity.clone();
let mut keys = Vec::new();
for key in sorted {
if key.entity != entity {
self.pending.insert(key);
} else if self.processed.insert(key.clone()) {
keys.push(key);
}
}
Some((entity, keys))
}
}