use crate::{
config::schema::IndexPool,
ops::{
runtime::metrics::{
placement_index::{
PlacementIndexMetricOperation as MetricOperation,
PlacementIndexMetricReason as MetricReason,
},
recording::PlacementIndexMetricEvent as MetricEvent,
},
storage::placement::index::{PlacementIndexEntryState, PlacementIndexRegistryOps},
},
workflow::placement::index::{
PlacementIndexWorkflow,
state::{
PlacementIndexEntryClassification, pending_is_stale, validate_bind_target_with_reason,
},
},
};
impl PlacementIndexWorkflow {
pub(super) fn classify_entry(
pool: &str,
key_value: &str,
pool_cfg: &IndexPool,
now: u64,
) -> Option<PlacementIndexEntryClassification> {
let Some(state) = PlacementIndexRegistryOps::lookup_state(pool, key_value) else {
MetricEvent::completed(MetricOperation::Classify, MetricReason::Missing);
return None;
};
if matches!(&state, PlacementIndexEntryState::Bound { .. })
&& !PlacementIndexRegistryOps::binding_is_current(pool, key_value)
{
return Some(PlacementIndexEntryClassification::Unavailable);
}
let classification = match state {
PlacementIndexEntryState::Bound {
instance_pid,
bound_at,
} => PlacementIndexEntryClassification::Bound {
instance_pid,
bound_at,
},
PlacementIndexEntryState::Pending {
claim_id,
owner_pid,
created_at,
provisional_pid,
} if !pending_is_stale(now, created_at) => {
PlacementIndexEntryClassification::PendingFresh {
claim_id,
owner_pid,
created_at,
provisional_pid,
}
}
PlacementIndexEntryState::Pending {
claim_id,
owner_pid,
created_at,
provisional_pid: None,
} => PlacementIndexEntryClassification::Resumable {
claim_id,
owner_pid,
created_at,
},
PlacementIndexEntryState::Pending {
claim_id,
owner_pid,
provisional_pid: Some(pid),
..
} if validate_bind_target_with_reason(pid, &pool_cfg.canister_role).is_ok()
&& crate::ops::storage::children::CanisterChildrenOps::matches_allocation(
pid,
crate::model::placement::allocation::PlacementAllocationIdentity::index(
owner_pid,
pool,
key_value,
claim_id,
&pool_cfg.canister_role,
None,
)
.operation_id
.into_bytes(),
) =>
{
PlacementIndexEntryClassification::Repairable {
claim_id,
owner_pid,
provisional_pid: pid,
}
}
PlacementIndexEntryState::Pending {
claim_id,
owner_pid,
provisional_pid: Some(provisional_pid),
..
} => PlacementIndexEntryClassification::NeedsCleanup {
claim_id,
owner_pid,
provisional_pid,
},
};
MetricEvent::completed(
MetricOperation::Classify,
Self::classification_reason(&classification),
);
Some(classification)
}
const fn classification_reason(
classification: &PlacementIndexEntryClassification,
) -> MetricReason {
match classification {
PlacementIndexEntryClassification::Unavailable => MetricReason::InvalidChild,
PlacementIndexEntryClassification::Bound { .. } => MetricReason::AlreadyBound,
PlacementIndexEntryClassification::PendingFresh { .. } => MetricReason::PendingFresh,
PlacementIndexEntryClassification::Repairable { .. } => MetricReason::StaleRepairable,
PlacementIndexEntryClassification::Resumable { .. } => MetricReason::ResumedPending,
PlacementIndexEntryClassification::NeedsCleanup { .. } => MetricReason::StaleCleanup,
}
}
}