use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct HotUpdateInputs<'a> {
pub collection: &'a str,
pub indexed_columns: &'a HashSet<String>,
pub modified_columns: &'a HashSet<String>,
pub new_tuple_size: usize,
pub page_free_space: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HotUpdateDecision {
pub can_hot: bool,
pub indexed_blocker: Option<String>,
pub page_free_space: usize,
}
pub const DEFAULT_MAX_CHAIN_HOPS: usize = 32;
pub fn follow_chain<F>(
start_id: crate::storage::unified::entity::EntityId,
max_hops: usize,
mut resolve: F,
) -> crate::storage::unified::entity::EntityId
where
F: FnMut(
crate::storage::unified::entity::EntityId,
) -> Option<crate::storage::unified::entity::EntityId>,
{
let hops_cap = max_hops.max(1);
let mut current = start_id;
for _hop in 0..hops_cap {
match resolve(current) {
Some(next) if next != current => current = next,
_ => return current,
}
}
tracing::warn!(
entity_id = current.raw(),
max_hops = hops_cap,
"hot_update chain walker hit hop cap — likely malformed chain"
);
current
}
pub fn decide(inputs: &HotUpdateInputs<'_>) -> HotUpdateDecision {
let blocker = inputs
.modified_columns
.iter()
.find(|col| inputs.indexed_columns.contains(col.as_str()))
.cloned();
let fits_page = inputs.new_tuple_size <= inputs.page_free_space;
HotUpdateDecision {
can_hot: blocker.is_none() && fits_page,
indexed_blocker: blocker,
page_free_space: inputs.page_free_space,
}
}