1use crate::{TxnFailureCause, TxnFailureRecovery, TxnFailureReport, TxnFailureRollback};
6
7use std::sync::Arc;
8
9impl TxnFailureReport {
10 pub(crate) fn new(name: Arc<str>, typ: &'static str) -> Self {
11 Self {
12 data_conn_name: name,
13 data_conn_type: typ,
14 cause: TxnFailureCause::NoneByUncommitted,
15 rollback: TxnFailureRollback::NoneByNotRolledBack,
16 }
17 }
18
19 pub fn is_cause_of_failure(&self) -> bool {
21 !matches!(
22 self.cause,
23 TxnFailureCause::NoneByCommitted | TxnFailureCause::NoneByUncommitted
24 )
25 }
26
27 pub fn recovery_for_commit(&self) -> TxnFailureRecovery {
29 use TxnFailureCause::*;
30 use TxnFailureRecovery::*;
31 use TxnFailureRollback::*;
32
33 match (&self.cause, &self.rollback) {
34 (NoneByUncommitted, NoneByNotRolledBack) => InvestigateBecauseImpossible,
35 (NoneByUncommitted, NoneByRolledBack) => RerunLogicAndCommit,
36 (NoneByUncommitted, RollbackFailure(_)) => ResolveCauseAndInconsistency,
37
38 (NoneByCommitted, NoneByNotRolledBack) => NoActionRequired,
39 (NoneByCommitted, NoneByRolledBack) => InvestigateBecauseImpossible,
40 (NoneByCommitted, RollbackFailure(_)) => InvestigateBecauseImpossible,
41
42 (LogicFailure(_), NoneByNotRolledBack) => InvestigateBecauseImpossible,
43 (LogicFailure(_), NoneByRolledBack) => ResolveCauseThenRerunLogicAndCommit,
44 (LogicFailure(_), RollbackFailure(_)) => ResolveCauseAndInconsistency,
45
46 (CommitFailure(_), NoneByNotRolledBack) => InvestigateBecauseImpossible,
47 (CommitFailure(_), NoneByRolledBack) => ResolveCauseThenRerunLogicAndCommit,
48 (CommitFailure(_), RollbackFailure(_)) => ResolveCauseAndInconsistency,
49
50 (PostCommitFailure(_), NoneByNotRolledBack) => ResolveCauseThenRerunPostCommit,
51 (PostCommitFailure(_), NoneByRolledBack) => InvestigateBecauseImpossible,
52 (PostCommitFailure(_), RollbackFailure(_)) => InvestigateBecauseImpossible,
53 }
54 }
55
56 pub fn recovery_for_rollback(&self) -> TxnFailureRecovery {
58 use TxnFailureCause::*;
59 use TxnFailureRecovery::*;
60 use TxnFailureRollback::*;
61
62 match (&self.cause, &self.rollback) {
63 (NoneByUncommitted, NoneByNotRolledBack) => InvestigateBecauseImpossible,
64 (NoneByUncommitted, NoneByRolledBack) => NoActionRequired,
65 (NoneByUncommitted, RollbackFailure(_)) => ResolveCauseAndInconsistency,
66
67 (NoneByCommitted, NoneByNotRolledBack) => ManualRollbackRequired,
68 (NoneByCommitted, NoneByRolledBack) => InvestigateBecauseImpossible,
69 (NoneByCommitted, RollbackFailure(_)) => InvestigateBecauseImpossible,
70
71 (LogicFailure(_), NoneByNotRolledBack) => InvestigateBecauseImpossible,
72 (LogicFailure(_), NoneByRolledBack) => NoActionRequired,
73 (LogicFailure(_), RollbackFailure(_)) => ResolveCauseAndInconsistency,
74
75 (CommitFailure(_), NoneByNotRolledBack) => InvestigateBecauseImpossible,
76 (CommitFailure(_), NoneByRolledBack) => NoActionRequired,
77 (CommitFailure(_), RollbackFailure(_)) => ResolveCauseAndInconsistency,
78
79 (PostCommitFailure(_), NoneByNotRolledBack) => ManualRollbackRequired,
80 (PostCommitFailure(_), NoneByRolledBack) => InvestigateBecauseImpossible,
81 (PostCommitFailure(_), RollbackFailure(_)) => InvestigateBecauseImpossible,
82 }
83 }
84}
85
86#[cfg_attr(coverage_nightly, coverage(off))]
87#[cfg(test)]
88mod unit_tests {
89 use super::*;
90 use TxnFailureCause::*;
91 use TxnFailureRecovery::*;
92 use TxnFailureRollback::*;
93
94 #[test]
96 fn test_cause_is_none_by_uncommitted_and_rollback_is_none_by_not_rolled_back() {
97 let report = TxnFailureReport {
98 data_conn_name: "foo".into(),
99 data_conn_type: "A::B::C",
100 cause: NoneByUncommitted,
101 rollback: NoneByNotRolledBack,
102 };
103
104 assert!(!report.is_cause_of_failure());
105 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
106 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
107 }
108
109 #[test]
110 fn test_cause_is_none_by_uncommitted_and_rollback_is_none_by_rolled_back() {
111 let report = TxnFailureReport {
112 data_conn_name: "foo".into(),
113 data_conn_type: "A::B::C",
114 cause: NoneByUncommitted,
115 rollback: NoneByRolledBack,
116 };
117
118 assert!(!report.is_cause_of_failure());
119 assert_eq!(report.recovery_for_commit(), RerunLogicAndCommit);
120 assert_eq!(report.recovery_for_rollback(), NoActionRequired);
121 }
122
123 #[test]
124 fn test_cause_is_none_by_uncommitted_and_rollback_is_rollback_failure() {
125 let report = TxnFailureReport {
126 data_conn_name: "foo".into(),
127 data_conn_type: "A::B::C",
128 cause: NoneByUncommitted,
129 rollback: RollbackFailure(errs::Err::new("fail")),
130 };
131
132 assert!(!report.is_cause_of_failure());
133 assert_eq!(report.recovery_for_commit(), ResolveCauseAndInconsistency);
134 assert_eq!(report.recovery_for_rollback(), ResolveCauseAndInconsistency);
135 }
136
137 #[test]
138 fn test_cause_is_none_by_committed_and_rollback_is_none_by_not_rolled_back() {
139 let report = TxnFailureReport {
140 data_conn_name: "foo".into(),
141 data_conn_type: "A::B::C",
142 cause: NoneByCommitted,
143 rollback: NoneByNotRolledBack,
144 };
145
146 assert!(!report.is_cause_of_failure());
147 assert_eq!(report.recovery_for_commit(), NoActionRequired);
148 assert_eq!(report.recovery_for_rollback(), ManualRollbackRequired);
149 }
150
151 #[test]
153 fn test_cause_is_none_by_committed_and_rollback_is_none_by_rolled_back() {
154 let report = TxnFailureReport {
155 data_conn_name: "foo".into(),
156 data_conn_type: "A::B::C",
157 cause: TxnFailureCause::NoneByCommitted,
158 rollback: TxnFailureRollback::NoneByRolledBack,
159 };
160
161 assert!(!report.is_cause_of_failure());
162 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
163 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
164 }
165
166 #[test]
168 fn test_cause_is_none_by_committed_and_rollback_is_rollback_failure() {
169 let report = TxnFailureReport {
170 data_conn_name: "foo".into(),
171 data_conn_type: "A::B::C",
172 cause: TxnFailureCause::NoneByCommitted,
173 rollback: TxnFailureRollback::RollbackFailure(errs::Err::new("fail")),
174 };
175
176 assert!(!report.is_cause_of_failure());
177 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
178 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
179 }
180
181 #[test]
182 fn test_cause_is_logic_failure_and_rollback_is_none_by_not_rolled_back() {
183 let report = TxnFailureReport {
184 data_conn_name: "foo".into(),
185 data_conn_type: "A::B::C",
186 cause: LogicFailure(errs::Err::new("fail")),
187 rollback: NoneByNotRolledBack,
188 };
189
190 assert!(report.is_cause_of_failure());
191 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
192 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
193 }
194
195 #[test]
196 fn test_cause_is_run_failure_and_rollback_is_none_by_rolled_back() {
197 let report = TxnFailureReport {
198 data_conn_name: "foo".into(),
199 data_conn_type: "A::B::C",
200 cause: LogicFailure(errs::Err::new("fail")),
201 rollback: NoneByRolledBack,
202 };
203
204 assert!(report.is_cause_of_failure());
205 assert_eq!(
206 report.recovery_for_commit(),
207 ResolveCauseThenRerunLogicAndCommit
208 );
209 assert_eq!(report.recovery_for_rollback(), NoActionRequired);
210 }
211
212 #[test]
213 fn test_cause_is_run_failure_and_rollback_is_rollback_failure() {
214 let report = TxnFailureReport {
215 data_conn_name: "foo".into(),
216 data_conn_type: "A::B::C",
217 cause: LogicFailure(errs::Err::new("fail")),
218 rollback: RollbackFailure(errs::Err::new("fail")),
219 };
220
221 assert!(report.is_cause_of_failure());
222 assert_eq!(report.recovery_for_commit(), ResolveCauseAndInconsistency);
223 assert_eq!(report.recovery_for_rollback(), ResolveCauseAndInconsistency);
224 }
225
226 #[test]
227 fn test_cause_is_commit_failure_and_rollback_is_none_by_not_rolled_back() {
228 let report = TxnFailureReport {
229 data_conn_name: "foo".into(),
230 data_conn_type: "A::B::C",
231 cause: CommitFailure(errs::Err::new("fail")),
232 rollback: NoneByNotRolledBack,
233 };
234
235 assert!(report.is_cause_of_failure());
236 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
237 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
238 }
239
240 #[test]
241 fn test_cause_is_commit_failure_and_rollback_is_none_by_rolled_back() {
242 let report = TxnFailureReport {
243 data_conn_name: "foo".into(),
244 data_conn_type: "A::B::C",
245 cause: CommitFailure(errs::Err::new("fail")),
246 rollback: NoneByRolledBack,
247 };
248
249 assert!(report.is_cause_of_failure());
250 assert_eq!(
251 report.recovery_for_commit(),
252 ResolveCauseThenRerunLogicAndCommit
253 );
254 assert_eq!(report.recovery_for_rollback(), NoActionRequired);
255 }
256
257 #[test]
258 fn test_cause_is_commit_failure_and_rollback_is_rollback_failure() {
259 let report = TxnFailureReport {
260 data_conn_name: "foo".into(),
261 data_conn_type: "A::B::C",
262 cause: TxnFailureCause::CommitFailure(errs::Err::new("fail")),
263 rollback: TxnFailureRollback::RollbackFailure(errs::Err::new("fail")),
264 };
265
266 assert!(report.is_cause_of_failure());
267 assert_eq!(report.recovery_for_commit(), ResolveCauseAndInconsistency);
268 assert_eq!(report.recovery_for_rollback(), ResolveCauseAndInconsistency);
269 }
270
271 #[test]
272 fn test_cause_is_post_commit_failure_and_rollback_is_none_by_not_rolled_back() {
273 let report = TxnFailureReport {
274 data_conn_name: "foo".into(),
275 data_conn_type: "A::B::C",
276 cause: PostCommitFailure(errs::Err::new("fail")),
277 rollback: NoneByNotRolledBack,
278 };
279
280 assert!(report.is_cause_of_failure());
281 assert_eq!(
282 report.recovery_for_commit(),
283 ResolveCauseThenRerunPostCommit
284 );
285 assert_eq!(report.recovery_for_rollback(), ManualRollbackRequired);
286 }
287
288 #[test]
289 fn test_cause_is_post_commit_failure_and_rollback_is_none_by_rolled_back() {
290 let report = TxnFailureReport {
291 data_conn_name: "foo".into(),
292 data_conn_type: "A::B::C",
293 cause: PostCommitFailure(errs::Err::new("fail")),
294 rollback: NoneByRolledBack,
295 };
296
297 assert!(report.is_cause_of_failure());
298 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
299 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
300 }
301
302 #[test]
303 fn test_cause_is_post_commit_failure_and_rollback_is_rollback_failure() {
304 let report = TxnFailureReport {
305 data_conn_name: "foo".into(),
306 data_conn_type: "A::B::C",
307 cause: TxnFailureCause::PostCommitFailure(errs::Err::new("fail")),
308 rollback: TxnFailureRollback::RollbackFailure(errs::Err::new("fail")),
309 };
310
311 assert!(report.is_cause_of_failure());
312 assert_eq!(report.recovery_for_commit(), InvestigateBecauseImpossible);
313 assert_eq!(report.recovery_for_rollback(), InvestigateBecauseImpossible);
314 }
315}