clt_database/mvcc/persistent_storage/
mod.rs1use crate::io::FileSyncType;
2use crate::storage::encryption::EncryptionContext;
3use crate::storage::sqlite3_ondisk::DatabaseHeader;
4use crate::sync::atomic::{AtomicI64, AtomicU64, Ordering};
5use crate::sync::Arc;
6use crate::sync::RwLock;
7use crate::turso_assert;
8use std::fmt::Debug;
9
10pub mod logical_log;
11use crate::mvcc::database::{LogRecord, RowVersion};
12use crate::mvcc::persistent_storage::logical_log::{
13 serialize_header_entry, serialize_op_entry, LogicalLog, OnSerializationComplete,
14 DEFAULT_LOG_CHECKPOINT_THRESHOLD,
15};
16use crate::{CheckpointResult, Completion, File, LimboError, Result};
17
18pub trait DurableStorage: Send + Sync + Debug {
19 fn serialize_row_version(
22 &self,
23 log_record: &mut LogRecord,
24 row_version: &RowVersion,
25 portable_extension: Option<&[u8]>,
26 ) -> Result<()>;
27
28 fn serialize_database_header(
30 &self,
31 log_record: &mut LogRecord,
32 header: &DatabaseHeader,
33 ) -> Result<()>;
34
35 fn log_tx(
42 &self,
43 m: LogRecord,
44 on_serialization_complete: OnSerializationComplete<'_>,
45 ) -> Result<(Completion, u64)>;
46
47 fn upgrade_header_for_log_tx(&self, m: &LogRecord) -> Result<Option<Completion>>;
51
52 fn sync(&self, sync_type: FileSyncType) -> Result<Completion>;
53
54 fn on_log_write_complete(&self) -> Result<Completion> {
60 Ok(Completion::new_yield())
61 }
62
63 fn update_header(&self) -> Result<Completion>;
68
69 fn truncate(&self, checkpointed_through_ts: u64) -> Result<Completion>;
73
74 fn reset_to_fresh_header(&self) -> Result<Completion>;
79 fn get_logical_log_file(&self) -> Arc<dyn File>;
80 fn logical_log_offset(&self) -> u64;
81 fn should_checkpoint(&self) -> bool;
82 fn set_checkpoint_threshold(&self, threshold: i64);
85 fn checkpoint_threshold(&self) -> i64;
86 fn advance_logical_log_offset_after_success(&self, bytes: u64) -> Result<()>;
87 fn discard_pending_log_write(&self) -> Result<()> {
88 Ok(())
89 }
90 fn restore_logical_log_state_after_recovery(&self, offset: u64, running_crc: u32);
91
92 fn set_header(&self, header: logical_log::LogHeader);
96
97 fn on_checkpoint_start(&self) -> Result<()> {
99 Ok(())
100 }
101
102 fn on_checkpoint_end(&self, _result: Result<&CheckpointResult>) -> Result<()> {
105 Ok(())
106 }
107
108 fn encryption_ctx(&self) -> Option<EncryptionContext> {
109 None
110 }
111}
112
113pub struct Storage {
114 pub logical_log: RwLock<LogicalLog>,
115 log_offset: AtomicU64,
117 checkpoint_threshold: AtomicI64,
118}
119
120impl Storage {
121 pub fn new(
122 file: Arc<dyn File>,
123 io: Arc<dyn crate::IO>,
124 encryption_ctx: Option<EncryptionContext>,
125 ) -> Self {
126 Self {
127 logical_log: RwLock::new(LogicalLog::new(file, io, encryption_ctx)),
128 log_offset: AtomicU64::new(0),
129 checkpoint_threshold: AtomicI64::new(DEFAULT_LOG_CHECKPOINT_THRESHOLD),
130 }
131 }
132
133 #[inline(always)]
136 fn shadow_offset_store(&self, value: u64) {
137 self.log_offset.store(value, Ordering::Relaxed);
138 }
139
140 #[inline(always)]
141 fn shadow_offset_advance(&self, bytes: u64) {
142 self.log_offset.fetch_add(bytes, Ordering::Relaxed);
143 }
144}
145
146impl DurableStorage for Storage {
147 fn serialize_row_version(
148 &self,
149 log_record: &mut LogRecord,
150 row_version: &RowVersion,
151 portable_extension: Option<&[u8]>,
152 ) -> Result<()> {
153 serialize_op_entry(&mut log_record.buf, row_version, portable_extension)?;
154 log_record.op_count = log_record.op_count.checked_add(1).ok_or_else(|| {
155 LimboError::InternalError("logical log op_count exceeds u32".to_string())
156 })?;
157 Ok(())
158 }
159
160 fn serialize_database_header(
161 &self,
162 log_record: &mut LogRecord,
163 header: &DatabaseHeader,
164 ) -> Result<()> {
165 turso_assert!(
166 !log_record.has_header,
167 "DatabaseHeader op appended more than once to a single LogRecord"
168 );
169 serialize_header_entry(&mut log_record.buf, header);
170 log_record.has_header = true;
171 log_record.op_count = log_record.op_count.checked_add(1).ok_or_else(|| {
172 LimboError::InternalError("logical log op_count exceeds u32".to_string())
173 })?;
174 Ok(())
175 }
176
177 fn log_tx(
178 &self,
179 m: LogRecord,
180 on_serialization_complete: OnSerializationComplete<'_>,
181 ) -> Result<(Completion, u64)> {
182 self.logical_log
183 .write()
184 .log_tx_deferred_offset(m, on_serialization_complete)
185 }
186
187 fn upgrade_header_for_log_tx(&self, m: &LogRecord) -> Result<Option<Completion>> {
188 self.logical_log.write().upgrade_header_for_log_tx(m)
189 }
190
191 fn sync(&self, sync_type: FileSyncType) -> Result<Completion> {
192 self.logical_log.write().sync(sync_type)
193 }
194
195 fn update_header(&self) -> Result<Completion> {
196 self.logical_log.write().update_header()
197 }
198
199 fn truncate(&self, checkpointed_through_ts: u64) -> Result<Completion> {
200 let mut log = self.logical_log.write();
201 let c = log.truncate(checkpointed_through_ts)?;
202 let new_offset = log.offset;
206 drop(log);
207 self.shadow_offset_store(new_offset);
208 Ok(c)
209 }
210
211 fn reset_to_fresh_header(&self) -> Result<Completion> {
212 let c = self.logical_log.write().reset_to_fresh_header()?;
213 self.shadow_offset_store(0);
214 Ok(c)
215 }
216
217 fn get_logical_log_file(&self) -> Arc<dyn File> {
218 self.logical_log.read().file.clone()
219 }
220
221 fn logical_log_offset(&self) -> u64 {
222 self.log_offset.load(Ordering::Relaxed)
223 }
224
225 fn encryption_ctx(&self) -> Option<EncryptionContext> {
226 self.logical_log.read().encryption_ctx().cloned()
227 }
228
229 fn should_checkpoint(&self) -> bool {
231 let threshold = self.checkpoint_threshold.load(Ordering::Relaxed);
232 if threshold < 0 {
233 return false;
234 }
235 self.log_offset.load(Ordering::Relaxed) >= threshold as u64
236 }
237
238 fn set_checkpoint_threshold(&self, threshold: i64) {
239 self.checkpoint_threshold
240 .store(threshold, Ordering::Relaxed);
241 }
242
243 fn checkpoint_threshold(&self) -> i64 {
244 self.checkpoint_threshold.load(Ordering::Relaxed)
245 }
246
247 fn advance_logical_log_offset_after_success(&self, bytes: u64) -> Result<()> {
248 self.logical_log.write().advance_offset_after_success(bytes);
249 self.shadow_offset_advance(bytes);
250 Ok(())
251 }
252
253 fn restore_logical_log_state_after_recovery(&self, offset: u64, running_crc: u32) {
254 let mut log = self.logical_log.write();
255 log.offset = offset;
256 log.running_crc = running_crc;
257 self.shadow_offset_store(offset);
258 }
259
260 fn set_header(&self, header: logical_log::LogHeader) {
261 self.logical_log.write().set_header(header);
262 }
263}
264
265impl Debug for Storage {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 write!(f, "LogicalLog {{ logical_log }}")
268 }
269}