manifold/tree_store/page_store/
savepoint.rs1use crate::transaction_tracker::{SavepointId, TransactionId, TransactionTracker};
2use crate::tree_store::page_store::page_manager::FILE_FORMAT_VERSION3;
3use crate::tree_store::{BtreeHeader, TransactionalMemory};
4use crate::{TypeName, Value};
5use std::fmt::Debug;
6use std::mem::size_of;
7use std::sync::Arc;
8
9pub struct Savepoint {
23 version: u8,
24 id: SavepointId,
25 transaction_id: TransactionId,
28 user_root: Option<BtreeHeader>,
29 transaction_tracker: Arc<TransactionTracker>,
30 ephemeral: bool,
31}
32
33impl Savepoint {
34 #[allow(clippy::too_many_arguments)]
35 pub(crate) fn new_ephemeral(
36 mem: &TransactionalMemory,
37 transaction_tracker: Arc<TransactionTracker>,
38 id: SavepointId,
39 transaction_id: TransactionId,
40 user_root: Option<BtreeHeader>,
41 ) -> Self {
42 Self {
43 id,
44 transaction_id,
45 version: mem.get_version(),
46 user_root,
47 transaction_tracker,
48 ephemeral: true,
49 }
50 }
51
52 pub(crate) fn get_version(&self) -> u8 {
53 self.version
54 }
55
56 pub(crate) fn get_id(&self) -> SavepointId {
57 self.id
58 }
59
60 pub(crate) fn get_transaction_id(&self) -> TransactionId {
61 self.transaction_id
62 }
63
64 pub(crate) fn get_user_root(&self) -> Option<BtreeHeader> {
65 self.user_root
66 }
67
68 pub(crate) fn db_address(&self) -> *const TransactionTracker {
69 std::ptr::from_ref(self.transaction_tracker.as_ref())
70 }
71
72 pub(crate) fn set_persistent(&mut self) {
73 self.ephemeral = false;
74 }
75}
76
77impl Drop for Savepoint {
78 fn drop(&mut self) {
79 if self.ephemeral {
80 self.transaction_tracker
81 .deallocate_savepoint(self.get_id(), self.get_transaction_id());
82 }
83 }
84}
85
86#[derive(Debug)]
87pub(crate) enum SerializedSavepoint<'a> {
88 Ref(&'a [u8]),
89 Owned(Vec<u8>),
90}
91
92impl SerializedSavepoint<'_> {
93 pub(crate) fn from_savepoint(savepoint: &Savepoint) -> Self {
94 assert_eq!(savepoint.version, FILE_FORMAT_VERSION3);
95 let mut result = vec![savepoint.version];
96 result.extend(savepoint.id.0.to_le_bytes());
97 result.extend(savepoint.transaction_id.raw_id().to_le_bytes());
98
99 if let Some(header) = savepoint.user_root {
100 result.push(1);
101 result.extend(header.to_le_bytes());
102 } else {
103 result.push(0);
104 result.extend([0; BtreeHeader::serialized_size()]);
105 }
106
107 Self::Owned(result)
108 }
109
110 fn data(&self) -> &[u8] {
111 match self {
112 SerializedSavepoint::Ref(x) => x,
113 SerializedSavepoint::Owned(x) => x.as_slice(),
114 }
115 }
116
117 pub(crate) fn to_savepoint(&self, transaction_tracker: Arc<TransactionTracker>) -> Savepoint {
118 let data = self.data();
119 let mut offset = 0;
120 let version = data[offset];
121 assert_eq!(version, FILE_FORMAT_VERSION3);
122 offset += size_of::<u8>();
123
124 let id = u64::from_le_bytes(
125 data[offset..(offset + size_of::<u64>())]
126 .try_into()
127 .unwrap(),
128 );
129 offset += size_of::<u64>();
130
131 let transaction_id = u64::from_le_bytes(
132 data[offset..(offset + size_of::<u64>())]
133 .try_into()
134 .unwrap(),
135 );
136 offset += size_of::<u64>();
137
138 let not_null = data[offset];
139 assert!(not_null == 0 || not_null == 1);
140 offset += 1;
141 let user_root = if not_null == 1 {
142 Some(BtreeHeader::from_le_bytes(
143 data[offset..(offset + BtreeHeader::serialized_size())]
144 .try_into()
145 .unwrap(),
146 ))
147 } else {
148 None
149 };
150 offset += BtreeHeader::serialized_size();
151 assert_eq!(offset, data.len());
152
153 Savepoint {
154 version,
155 id: SavepointId(id),
156 transaction_id: TransactionId::new(transaction_id),
157 user_root,
158 transaction_tracker,
159 ephemeral: false,
160 }
161 }
162}
163
164impl Value for SerializedSavepoint<'_> {
165 type SelfType<'a>
166 = SerializedSavepoint<'a>
167 where
168 Self: 'a;
169 type AsBytes<'a>
170 = &'a [u8]
171 where
172 Self: 'a;
173
174 fn fixed_width() -> Option<usize> {
175 None
176 }
177
178 fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
179 where
180 Self: 'a,
181 {
182 SerializedSavepoint::Ref(data)
183 }
184
185 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
186 where
187 Self: 'b,
188 {
189 value.data()
190 }
191
192 fn type_name() -> TypeName {
193 TypeName::internal("redb::SerializedSavepoint")
194 }
195}