use super::{
DoViewChange, Promise, PromiseTicket, RecoveredState, ViewChange, ViewChangeError,
validate_report,
};
use crate::{
Configuration, JournalGeneration, NormalReplica, PipelineLimits, ReplicationError, Scope,
};
use ozzy_proto::NodeId;
impl ViewChange {
pub(crate) fn after_abandon(
mut normal: NormalReplica,
previous: PromiseTicket,
requested_view: u64,
) -> Result<Self, ViewChangeError> {
normal.restore_fenced(previous.generation(), previous.log());
let mut changing = normal.into_view_change(requested_view)?;
changing.promise = Promise::Completed(previous);
Ok(changing)
}
pub fn recover_intact(
configuration: Configuration,
local: NodeId,
generation: JournalGeneration,
recovered: RecoveredState,
limits: PipelineLimits,
) -> Result<Self, ViewChangeError> {
if recovered.scope
!= (Scope {
view: recovered.scope.view,
..configuration.scope()
})
{
return Err(ReplicationError::ScopeMismatch.into());
}
if recovered.log.last_normal_view > recovered.scope.view {
return Err(ViewChangeError::InvalidReport);
}
let view = if recovered.scope.view > recovered.log.last_normal_view {
recovered.scope.view
} else {
recovered
.scope
.view
.checked_add(1)
.ok_or(ViewChangeError::ViewExhausted)?
};
validate_report(DoViewChange {
scope: Scope {
view,
..recovered.scope
},
generation,
log: recovered.log,
})?;
let normal =
NormalReplica::recover_fenced(configuration, local, generation, recovered.log, limits)?;
let mut changing = normal.into_view_change(view)?;
changing.promise = if recovered.scope.view == view {
changing.starts.insert(changing.local); Promise::Completed(PromiseTicket {
scope: changing.scope(),
generation,
log: recovered.log,
})
} else {
Promise::Prior(recovered.scope.view)
};
Ok(changing)
}
}