uqa_storage/mvcc/session/
sequence_values.rs1use super::{
10 Arc, StorageBackendError, StorageBackendResult, StorageReadControl, VersionError,
11 VersionedKeyValueStore,
12};
13use parking_lot::{RwLock, RwLockWriteGuard};
14use std::sync::atomic::{AtomicBool, Ordering};
15
16pub(super) struct SequenceDurability {
17 state: RwLock<SequenceBoundary>,
18 required: AtomicBool,
19}
20
21pub(super) struct SequenceBoundary {
22 generation: u64,
23 open: bool,
24}
25
26impl Default for SequenceDurability {
27 fn default() -> Self {
28 Self {
29 state: RwLock::new(SequenceBoundary {
30 generation: 0,
31 open: false,
32 }),
33 required: AtomicBool::new(false),
34 }
35 }
36}
37
38impl SequenceDurability {
39 pub(super) fn begin(&self) -> StorageBackendResult<()> {
40 let mut state = self.state.write();
41 state.generation = state.generation.checked_add(1).ok_or_else(|| {
42 StorageBackendError::Other("sequence completion generations exhausted".into())
43 })?;
44 state.open = true;
45 self.required.store(false, Ordering::Release);
46 Ok(())
47 }
48
49 pub(super) fn generation(&self) -> u64 {
50 self.state.read().generation
51 }
52
53 pub(super) fn close(&self) -> RwLockWriteGuard<'_, SequenceBoundary> {
54 let mut state = self.state.write();
55 state.open = false;
56 state
57 }
58
59 pub(super) fn clear(&self) {
60 self.required.store(false, Ordering::Release);
61 }
62
63 fn lease(self: &Arc<Self>, expected: Option<u64>) -> Option<SequencePublicationLease> {
64 let state = self.state.read();
65 if !state.open || expected.is_some_and(|generation| generation != state.generation) {
66 return None;
67 }
68 self.required.store(true, Ordering::Release);
69 Some(SequencePublicationLease {
70 owner: Arc::clone(self),
71 generation: state.generation,
72 })
73 }
74}
75
76#[derive(Clone)]
78pub struct SequencePublicationLease {
79 owner: Arc<SequenceDurability>,
80 generation: u64,
81}
82
83impl SequencePublicationLease {
84 pub fn with_publication<T>(&self, operation: impl FnOnce(bool) -> T) -> T {
86 let state = self.owner.state.read();
87 operation(state.open && state.generation == self.generation)
88 }
89}
90
91impl VersionedKeyValueStore {
92 pub fn new_sequence_value_session(&self, cancellation: &uqa_core::CancellationToken) -> Self {
94 let persistence = self
95 .sequence_durability
96 .lease(self.sequence_generation)
97 .and_then(|owner| self.persistence.sequence_value_persistence(owner))
98 .unwrap_or_else(|| Arc::clone(&self.persistence));
99 Self::new_with_cancellation(
100 persistence,
101 self.identity.clone(),
102 self.options,
103 cancellation.clone(),
104 )
105 }
106
107 pub fn require_sequence_value_durability(&self) -> StorageBackendResult<()> {
109 self.sequence_durability
110 .lease(self.sequence_generation)
111 .map(|_| ())
112 .ok_or_else(|| {
113 StorageBackendError::Other(
114 "sequence values require an open consuming transaction".into(),
115 )
116 })
117 }
118
119 pub(super) fn synchronize_sequence_values(
120 &self,
121 control: &StorageReadControl,
122 ) -> StorageBackendResult<()> {
123 if self.retained.is_none() && self.sequence_durability.required.load(Ordering::Acquire) {
124 self.persistence
125 .synchronize_sequence_values(control)
126 .map_err(VersionError::into_storage_error)?;
127 }
128 Ok(())
129 }
130}
131
132impl Drop for VersionedKeyValueStore {
133 fn drop(&mut self) {
134 if self.retained.is_none() {
135 drop(self.sequence_durability.close());
137 }
138 }
139}