1use super::{DurabilityError, DurableStore, RoutedBatchEntry, RoutedBatchItem};
22
23pub async fn append_settled(
31 store: &dyn DurableStore,
32 stream_key: &str,
33 payload: Vec<u8>,
34 expected_seq: u64,
35) -> Result<u64, DurabilityError> {
36 match store
37 .append(stream_key, payload.clone(), expected_seq)
38 .await
39 {
40 Err(unknown @ DurabilityError::OutcomeUnknown { .. }) => {
41 match own_row(store, stream_key, expected_seq, &payload).await {
42 Err(read) => Err(unread(unknown, stream_key, &read)),
43 Ok(Standing::Own) => Ok(expected_seq),
44 Ok(Standing::Other) => Err(conflict(expected_seq)),
45 Ok(Standing::Empty) => {
46 match store
47 .append(stream_key, payload.clone(), expected_seq)
48 .await
49 {
50 Err(resent @ DurabilityError::SequenceConflict { .. }) => {
51 match own_row(store, stream_key, expected_seq, &payload).await {
52 Ok(Standing::Own) => Ok(expected_seq),
53 Ok(_) => Err(resent),
54 Err(read) => Err(unread(unknown, stream_key, &read)),
55 }
56 }
57 outcome => outcome,
58 }
59 }
60 }
61 }
62 outcome => outcome,
63 }
64}
65
66pub async fn append_all_settled(
73 store: &dyn DurableStore,
74 stream_key: &str,
75 payloads: Vec<Vec<u8>>,
76 expected_seq: u64,
77) -> Result<u64, DurabilityError> {
78 match store
79 .append_all(stream_key, payloads.clone(), expected_seq)
80 .await
81 {
82 Err(unknown @ DurabilityError::OutcomeUnknown { .. }) => {
83 let after = after_batch(stream_key, expected_seq, payloads.len())?;
84 match own_rows(store, stream_key, expected_seq, &payloads).await {
85 Err(read) => Err(unread(unknown, stream_key, &read)),
86 Ok(Standing::Own) => Ok(after),
87 Ok(Standing::Other) => Err(conflict(expected_seq)),
88 Ok(Standing::Empty) => {
89 match store
90 .append_all(stream_key, payloads.clone(), expected_seq)
91 .await
92 {
93 Err(resent @ DurabilityError::SequenceConflict { .. }) => {
94 match own_rows(store, stream_key, expected_seq, &payloads).await {
95 Ok(Standing::Own) => Ok(after),
96 Ok(_) => Err(resent),
97 Err(read) => Err(unread(unknown, stream_key, &read)),
98 }
99 }
100 outcome => outcome,
101 }
102 }
103 }
104 }
105 outcome => outcome,
106 }
107}
108
109pub async fn cas_settled(
120 store: &dyn DurableStore,
121 key: &str,
122 old_value: u64,
123 new_value: u64,
124) -> Result<(), DurabilityError> {
125 match store.cas(key, old_value, new_value).await {
126 Err(unknown @ DurabilityError::OutcomeUnknown { .. }) => {
127 let stored = match store.read_value(key).await {
128 Ok(stored) => stored.unwrap_or(0),
129 Err(read) => return Err(unread(unknown, key, &read)),
130 };
131 if stored == new_value {
132 return Ok(());
133 }
134 if stored != old_value {
135 return Err(DurabilityError::CursorRegression {
136 stored,
137 attempted: old_value,
138 });
139 }
140 match store.cas(key, old_value, new_value).await {
141 Err(resent @ DurabilityError::CursorRegression { .. }) => {
142 match store.read_value(key).await {
143 Ok(stored) if stored.unwrap_or(0) == new_value => Ok(()),
144 Ok(_) => Err(resent),
145 Err(read) => Err(unread(unknown, key, &read)),
146 }
147 }
148 outcome => outcome,
149 }
150 }
151 outcome => outcome,
152 }
153}
154
155pub async fn flush_settled(store: &dyn DurableStore) -> Result<(), DurabilityError> {
161 store.flush().await
162}
163
164pub async fn apply_routed_batch_settled(
178 store: &dyn DurableStore,
179 route_key: &str,
180 items: Vec<RoutedBatchItem>,
181) -> Result<(), DurabilityError> {
182 if items.is_empty() {
185 return Ok(());
186 }
187 match store.apply_routed_batch(route_key, items.clone()).await {
188 Err(unknown @ DurabilityError::OutcomeUnknown { .. }) => {
189 match own_keys(store, route_key, &items).await {
190 Err(read) => Err(unread(unknown, route_key, &read)),
191 Ok(Standing::Own) => Ok(()),
192 Ok(Standing::Other) => Err(unread(
193 unknown,
194 route_key,
195 &DurabilityError::ConfigError(
196 "routed batch keys stand neither as written nor as expected".to_owned(),
197 ),
198 )),
199 Ok(Standing::Empty) => {
200 match store.apply_routed_batch(route_key, items.clone()).await {
201 Err(resent @ DurabilityError::ConfigError(_)) => {
202 match own_keys(store, route_key, &items).await {
203 Ok(Standing::Own) => Ok(()),
204 Ok(_) => Err(resent),
205 Err(read) => Err(unread(unknown, route_key, &read)),
206 }
207 }
208 outcome => outcome,
209 }
210 }
211 }
212 }
213 outcome => outcome,
214 }
215}
216
217pub async fn apply_routed_entries_settled(
231 store: &dyn DurableStore,
232 route_key: &str,
233 entries: Vec<RoutedBatchEntry>,
234) -> Result<(), DurabilityError> {
235 if entries.is_empty() {
236 return Ok(());
237 }
238 match store.apply_routed_entries(route_key, entries.clone()).await {
239 Err(unknown @ DurabilityError::OutcomeUnknown { .. }) => {
240 match own_entries(store, route_key, &entries).await {
241 Err(read) => Err(unread(unknown, route_key, &read)),
242 Ok(Standing::Own) => Ok(()),
243 Ok(Standing::Other) => Err(unread(
244 unknown,
245 route_key,
246 &DurabilityError::ConfigError(
247 "routed batch keys stand neither as written nor as expected".to_owned(),
248 ),
249 )),
250 Ok(Standing::Empty) => {
251 match store.apply_routed_entries(route_key, entries.clone()).await {
252 Err(
253 resent @ (DurabilityError::ConfigError(_)
254 | DurabilityError::StoreError(_)),
255 ) => match own_entries(store, route_key, &entries).await {
256 Ok(Standing::Own) => Ok(()),
257 Ok(_) => Err(resent),
258 Err(read) => Err(unread(unknown, route_key, &read)),
259 },
260 outcome => outcome,
261 }
262 }
263 }
264 }
265 outcome => outcome,
266 }
267}
268
269const fn conflict(expected_seq: u64) -> DurabilityError {
272 DurabilityError::SequenceConflict {
273 expected: expected_seq,
274 actual: expected_seq.saturating_add(1),
275 }
276}
277
278fn unread(unknown: DurabilityError, key: &str, read: &DurabilityError) -> DurabilityError {
281 tracing::warn!(
282 key,
283 %read,
284 "a write's unknown outcome could not be read back; it stays unknown"
285 );
286 unknown
287}
288
289enum Standing {
291 Own,
293 Empty,
295 Other,
297}
298
299async fn own_row(
301 store: &dyn DurableStore,
302 stream_key: &str,
303 sequence: u64,
304 payload: &[u8],
305) -> Result<Standing, DurabilityError> {
306 Ok(match store.read_at(stream_key, sequence).await? {
307 None => Standing::Empty,
308 Some(entry) if entry.payload == payload => Standing::Own,
309 Some(_) => Standing::Other,
310 })
311}
312
313async fn own_keys(
319 store: &dyn DurableStore,
320 route_key: &str,
321 items: &[RoutedBatchItem],
322) -> Result<Standing, DurabilityError> {
323 let mut own = 0_usize;
324 let mut expected = 0_usize;
325 for item in items {
326 let stored = store.get_routed(route_key, &item.key).await?;
327 match stored {
328 Some(bytes) if bytes == item.value => own += 1,
329 None if item.expected.is_none() => expected += 1,
330 Some(bytes) if item.expected == Some(haematite::tree::Hash::of(&bytes)) => {
331 expected += 1;
332 }
333 _ => {}
334 }
335 }
336 Ok(if own == items.len() {
337 Standing::Own
338 } else if expected == items.len() {
339 Standing::Empty
340 } else {
341 Standing::Other
342 })
343}
344
345async fn own_entries(
349 store: &dyn DurableStore,
350 route_key: &str,
351 entries: &[RoutedBatchEntry],
352) -> Result<Standing, DurabilityError> {
353 let mut own = 0_usize;
354 let mut expected = 0_usize;
355 for entry in entries {
356 let stored = store.get_routed(route_key, entry.key()).await?;
357 match (entry, stored) {
358 (RoutedBatchEntry::Put(item), Some(bytes)) if bytes == item.value => own += 1,
359 (RoutedBatchEntry::Put(item), None) if item.expected.is_none() => expected += 1,
360 (RoutedBatchEntry::Put(item), Some(bytes))
361 if item.expected == Some(haematite::tree::Hash::of(&bytes)) =>
362 {
363 expected += 1;
364 }
365 (RoutedBatchEntry::Delete { .. }, None) => own += 1,
366 (
367 RoutedBatchEntry::Delete {
368 expected: guard, ..
369 },
370 Some(bytes),
371 ) if *guard == haematite::tree::Hash::of(&bytes) => {
372 expected += 1;
373 }
374 _ => {}
375 }
376 }
377 Ok(if own == entries.len() {
378 Standing::Own
379 } else if expected == entries.len() {
380 Standing::Empty
381 } else {
382 Standing::Other
383 })
384}
385
386async fn own_rows(
387 store: &dyn DurableStore,
388 stream_key: &str,
389 expected_seq: u64,
390 payloads: &[Vec<u8>],
391) -> Result<Standing, DurabilityError> {
392 let standing = store
393 .read_from(stream_key, expected_seq, payloads.len())
394 .await?;
395 if standing.is_empty() {
396 return Ok(Standing::Empty);
397 }
398 let own =
399 standing.len() == payloads.len()
400 && standing.iter().zip(payloads).zip(expected_seq..).all(
401 |((entry, payload), sequence)| {
402 entry.sequence == sequence && entry.payload == *payload
403 },
404 );
405 Ok(if own { Standing::Own } else { Standing::Other })
406}
407
408fn after_batch(stream_key: &str, expected_seq: u64, rows: usize) -> Result<u64, DurabilityError> {
410 u64::try_from(rows)
411 .ok()
412 .and_then(|rows| expected_seq.checked_add(rows))
413 .ok_or_else(|| {
414 DurabilityError::ConfigError(format!(
415 "{stream_key}: sequence overflow settling a batch at {expected_seq}"
416 ))
417 })
418}