chio_kernel/admission_operation/
store.rs1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum AdmissionBeginResult {
5 Created(AdmissionOperationV1),
6 ExactReplay {
7 operation: AdmissionOperationV1,
8 terminal_replay: Option<AdmissionTerminalReplay>,
9 },
10 Conflict {
11 existing_operation_id: AdmissionOperationId,
12 },
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
16pub enum AdmissionOperationStoreError {
17 #[error("admission operation store is unavailable: {0}")]
18 Unavailable(String),
19 #[error("admission operation mutation was fenced")]
20 Fenced,
21 #[error("admission operation was not found")]
22 NotFound,
23 #[error("admission operation invariant failed: {0}")]
24 Invariant(String),
25 #[error("admission operation durable outcome is unknown: {0}")]
26 OutcomeUnknown(String),
27 #[error(transparent)]
28 Operation(#[from] AdmissionOperationError),
29}
30
31pub trait AdmissionOperationStore: Send + Sync {
32 fn begin(
33 &self,
34 operation: &AdmissionOperationV1,
35 fence: &StoreMutationFence,
36 trusted_now_unix_ms: u64,
37 ) -> Result<AdmissionBeginResult, AdmissionOperationStoreError>;
38
39 fn load_by_operation_id(
40 &self,
41 operation_id: &AdmissionOperationId,
42 ) -> Result<Option<AdmissionOperationV1>, AdmissionOperationStoreError>;
43
44 fn load_by_replay_key(
45 &self,
46 replay_key: &AdmissionReplayKey,
47 ) -> Result<Option<AdmissionOperationV1>, AdmissionOperationStoreError>;
48
49 fn compare_and_swap(
50 &self,
51 command: &AdmissionOperationCommand,
52 trusted_now_unix_ms: u64,
53 ) -> Result<AdmissionCommandResult, AdmissionOperationStoreError>;
54
55 fn claim_recovery_untrusted(
59 &self,
60 operation_id: &AdmissionOperationId,
61 expected_version: u64,
62 claimant_id: &AdmissionIdentifier,
63 trusted_now_unix_ms: u64,
64 expires_at_unix_ms: u64,
65 fence: &StoreMutationFence,
66 ) -> Result<UntrustedAdmissionRecoveryClaim, AdmissionOperationStoreError>;
67
68 fn revalidate_recovery_claim(
71 &self,
72 operation: &AdmissionOperationV1,
73 claim: &UntrustedAdmissionRecoveryClaim,
74 trusted_now_unix_ms: u64,
75 current_store_fence: &StoreMutationFence,
76 ) -> Result<(), AdmissionOperationStoreError>;
77
78 fn list_recoverable(
85 &self,
86 not_after_unix_ms: u64,
87 limit: usize,
88 ) -> Result<Vec<AdmissionOperationV1>, AdmissionOperationStoreError>;
89
90 fn load_terminal_replay(
91 &self,
92 replay_key: &AdmissionReplayKey,
93 ) -> Result<Option<AdmissionTerminalReplay>, AdmissionOperationStoreError>;
94}
95
96pub trait QualifiedAdmissionOperationStore: AdmissionOperationStore {}
107
108pub trait QualifiedAdmissionOperationStoreExt: QualifiedAdmissionOperationStore {
110 fn claim_recovery(
111 &self,
112 operation_id: &AdmissionOperationId,
113 expected_version: u64,
114 claimant_id: &AdmissionIdentifier,
115 trusted_now_unix_ms: u64,
116 expires_at_unix_ms: u64,
117 current_store_fence: &StoreMutationFence,
118 ) -> Result<AdmissionRecoveryLease, AdmissionOperationStoreError> {
119 let claim = self.claim_recovery_untrusted(
120 operation_id,
121 expected_version,
122 claimant_id,
123 trusted_now_unix_ms,
124 expires_at_unix_ms,
125 current_store_fence,
126 )?;
127 let operation = self
128 .load_by_operation_id(operation_id)?
129 .ok_or(AdmissionOperationStoreError::NotFound)?;
130 claim.validate_for_qualification(
131 &operation,
132 expected_version,
133 claimant_id,
134 trusted_now_unix_ms,
135 expires_at_unix_ms,
136 current_store_fence,
137 )?;
138 self.revalidate_recovery_claim(
139 &operation,
140 &claim,
141 trusted_now_unix_ms,
142 current_store_fence,
143 )?;
144 Ok(AdmissionRecoveryLease::from_qualified(claim))
145 }
146}
147
148impl<T: QualifiedAdmissionOperationStore + ?Sized> QualifiedAdmissionOperationStoreExt for T {}