uqa_storage/mvcc/session/
serializable.rs1use std::sync::Arc;
10
11use crate::mvcc::{
12 SafeSnapshot, SerializableGraph, SerializableParticipant, SerializablePredicate,
13 SerializableTransactionId, VersionError, VersionResult, VersionedPersistence,
14};
15use crate::read_control::StorageReadControl;
16use crate::StorageBackendResult;
17
18#[derive(Clone, Copy, Debug, Default)]
20pub struct SerializableSnapshotOptions {
21 pub read_only: bool,
22 pub deferrable: bool,
23}
24
25pub type SerializableSnapshotCapture<'a> =
27 dyn FnMut(&mut dyn FnMut() -> VersionResult<()>) -> VersionResult<()> + 'a;
28
29pub trait SerializableSession: Send + Sync {
31 fn establish_serializable_snapshot(&self) -> StorageBackendResult<SerializableReadContext>;
32 fn establish_serializable_snapshot_with(
34 &self,
35 options: SerializableSnapshotOptions,
36 capture: &mut SerializableSnapshotCapture<'_>,
37 ) -> StorageBackendResult<SerializableReadContext>;
38 fn serializable_read_context(&self) -> StorageBackendResult<Option<SerializableReadContext>>;
39 fn observe_serializable_write(
40 &self,
41 predicate: SerializablePredicate<'_>,
42 ) -> StorageBackendResult<()>;
43}
44
45impl SerializableSession for super::VersionedKeyValueStore {
46 fn establish_serializable_snapshot(&self) -> StorageBackendResult<SerializableReadContext> {
47 Self::establish_serializable_snapshot(self)
48 }
49
50 fn establish_serializable_snapshot_with(
51 &self,
52 options: SerializableSnapshotOptions,
53 capture: &mut SerializableSnapshotCapture<'_>,
54 ) -> StorageBackendResult<SerializableReadContext> {
55 self.require_mutable_session()?;
56 self.active
57 .lock()
58 .as_mut()
59 .ok_or_else(super::no_transaction)?
60 .establish_serializable_with(&self.persistence, options, capture, &self.write_control())
61 .map_err(VersionError::into_storage_error)
62 }
63
64 fn serializable_read_context(&self) -> StorageBackendResult<Option<SerializableReadContext>> {
65 if let Some(view) = &self.retained {
66 return Ok(view.serializable().cloned());
67 }
68 let active = self.active.lock();
69 let Some(transaction) = active.as_ref() else {
70 return Ok(None);
71 };
72 transaction
73 .unsealed()
74 .map_err(VersionError::into_storage_error)?;
75 Ok(transaction.serializable_context().cloned())
76 }
77
78 fn observe_serializable_write(
79 &self,
80 predicate: SerializablePredicate<'_>,
81 ) -> StorageBackendResult<()> {
82 self.require_mutable_session()?;
83 Self::observe_serializable_write(self, predicate)
84 }
85}
86
87#[derive(Clone)]
89pub struct SerializableReadContext {
90 pub(super) persistence: Arc<dyn VersionedPersistence>,
91 pub(super) participant: SerializableParticipant,
92 pub(super) memory: uqa_core::memory::MemoryBudget,
93 pub(super) safe: bool,
94}
95
96impl SerializableReadContext {
97 pub fn id(&self) -> SerializableTransactionId {
98 self.participant.id()
99 }
100
101 pub fn read_control(&self, cancellation: &uqa_core::CancellationToken) -> StorageReadControl {
103 StorageReadControl::new(&self.memory, cancellation)
104 }
105
106 pub fn observe_read(
108 &self,
109 predicate: SerializablePredicate<'_>,
110 control: &StorageReadControl,
111 ) -> VersionResult<()> {
112 self.with_graph(control, |graph| {
113 if self.safe {
114 graph.check_active(self.id())
116 } else {
117 graph.observe_read(self.id(), predicate, control)
118 }
119 })
120 }
121
122 pub fn safe_snapshot(&self, control: &StorageReadControl) -> VersionResult<SafeSnapshot> {
123 self.with_graph(control, |graph| graph.safe_snapshot(self.id(), control))
124 }
125
126 pub(super) fn with_graph<T>(
127 &self,
128 control: &StorageReadControl,
129 operation: impl FnOnce(&mut SerializableGraph) -> VersionResult<T>,
130 ) -> VersionResult<T> {
131 let coordinator =
132 self.persistence
133 .serializable_coordinator()
134 .ok_or(VersionError::InvalidEncoding(
135 "serializable session lost its coordinator",
136 ))?;
137 let mut operation = Some(operation);
138 let mut result = None;
139 coordinator.with_serializable_admission(control, &mut |graph, leases| {
140 let operation = operation.take().ok_or(VersionError::InvalidEncoding(
141 "serializable session operation was replayed",
142 ))?;
143 crate::mvcc::serializable::recover(coordinator, graph, leases, control)?;
144 result = Some(operation(graph)?);
145 Ok(())
146 })?;
147 result.ok_or(VersionError::InvalidEncoding(
148 "serializable session operation was not invoked",
149 ))
150 }
151}