ozzy_replication/view_change/
recovery.rs1use super::{
5 DoViewChange, Promise, PromiseTicket, RecoveredState, ViewChange, ViewChangeError,
6 validate_report,
7};
8use crate::{
9 Configuration, JournalGeneration, NormalReplica, PipelineLimits, ReplicationError, Scope,
10};
11use ozzy_proto::NodeId;
12
13impl ViewChange {
14 pub(crate) fn after_abandon(
15 mut normal: NormalReplica,
16 previous: PromiseTicket,
17 requested_view: u64,
18 ) -> Result<Self, ViewChangeError> {
19 normal.restore_fenced(previous.generation(), previous.log());
20 let mut changing = normal.into_view_change(requested_view)?;
21 changing.promise = Promise::Completed(previous);
22 Ok(changing)
23 }
24
25 pub fn recover_intact(
39 configuration: Configuration,
40 local: NodeId,
41 generation: JournalGeneration,
42 recovered: RecoveredState,
43 limits: PipelineLimits,
44 ) -> Result<Self, ViewChangeError> {
45 if recovered.scope
46 != (Scope {
47 view: recovered.scope.view,
48 ..configuration.scope()
49 })
50 {
51 return Err(ReplicationError::ScopeMismatch.into());
52 }
53 if recovered.log.last_normal_view > recovered.scope.view {
54 return Err(ViewChangeError::InvalidReport);
55 }
56 let view = if recovered.scope.view > recovered.log.last_normal_view {
57 recovered.scope.view
58 } else {
59 recovered
60 .scope
61 .view
62 .checked_add(1)
63 .ok_or(ViewChangeError::ViewExhausted)?
64 };
65 validate_report(DoViewChange {
66 scope: Scope {
67 view,
68 ..recovered.scope
69 },
70 generation,
71 log: recovered.log,
72 })?;
73 let normal =
74 NormalReplica::recover_fenced(configuration, local, generation, recovered.log, limits)?;
75 let mut changing = normal.into_view_change(view)?;
76 changing.promise = if recovered.scope.view == view {
77 changing.starts.insert(changing.local); Promise::Completed(PromiseTicket {
79 scope: changing.scope(),
80 generation,
81 log: recovered.log,
82 })
83 } else {
84 Promise::Prior(recovered.scope.view)
85 };
86 Ok(changing)
87 }
88}