use super::{
ArtifactChecksumRecord, BackupLayoutGuard, ExecutionProgressPersistenceError,
ExecutionWorkflowPersistenceError,
ancestry::{acquire_stage, read_admitted_binding, read_current_binding, validate_predecessors},
read_execution_progress, read_execution_stage_occupancy, read_execution_workflow,
};
use crate::view::execution_workflow::{
ExecutionStageProgressState, ExecutionStageProgressView, ExecutionWorkflowProgressView,
};
use thiserror::Error;
pub fn read_execution_workflow_progress(
layout: &BackupLayoutGuard,
expected: &ArtifactChecksumRecord,
) -> Result<ExecutionWorkflowProgressView, ExecutionWorkflowProgressError> {
let workflow = read_execution_workflow(layout, expected)?;
let occupied = read_execution_stage_occupancy(layout, expected)?;
let mut stages = Vec::with_capacity(workflow.stages().len());
for node in workflow.allocation().graph().ordered_nodes() {
let sequence = node.operation_sequence();
let state = if occupied.contains(&sequence) {
let child = acquire_stage(layout, sequence)?;
let (binding, plan) = read_current_binding(&child, &workflow, sequence)?;
validate_predecessors(layout, &workflow, &binding)?;
let progress = read_execution_progress(&child, &plan.digest())?;
read_admitted_binding(layout, &child, &workflow, sequence, &binding.digest())?;
ExecutionStageProgressState::Prepared {
binding: binding.digest(),
progress: Box::new(progress),
}
} else {
ExecutionStageProgressState::Unprepared
};
stages.push(ExecutionStageProgressView {
stage_sequence: sequence,
state,
});
}
if read_execution_stage_occupancy(layout, expected)? != occupied {
return Err(ExecutionWorkflowPersistenceError::DigestMismatch.into());
}
Ok(ExecutionWorkflowProgressView {
workflow: expected.clone(),
stages,
})
}
#[derive(Debug, Error)]
pub enum ExecutionWorkflowProgressError {
#[error(transparent)]
Stage(#[from] ExecutionWorkflowPersistenceError),
#[error(transparent)]
Journals(#[from] ExecutionProgressPersistenceError),
}