libsql_sys/wal/
mod.rs

1use std::ffi::{c_int, CStr};
2use std::num::NonZeroU32;
3
4pub use crate::ffi::Error;
5use crate::ffi::*;
6
7pub use sqlite3_wal::{Sqlite3Wal, Sqlite3WalManager};
8
9pub mod either;
10pub(crate) mod ffi;
11mod sqlite3_wal;
12pub mod wrapper;
13
14pub type Result<T, E = Error> = std::result::Result<T, E>;
15pub use ffi::make_wal_manager;
16
17use self::wrapper::{WalWrapper, WrapWal};
18
19pub trait WalManager {
20    type Wal: Wal;
21
22    fn use_shared_memory(&self) -> bool;
23
24    fn open(
25        &self,
26        vfs: &mut Vfs,
27        file: &mut Sqlite3File,
28        no_shm_mode: c_int,
29        max_log_size: i64,
30        db_path: &CStr,
31    ) -> Result<Self::Wal>;
32
33    fn close(
34        &self,
35        wal: &mut Self::Wal,
36        db: &mut Sqlite3Db,
37        sync_flags: c_int,
38        scratch: Option<&mut [u8]>,
39    ) -> Result<()>;
40
41    fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()>;
42    fn log_exists(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<bool>;
43
44    fn destroy(self)
45    where
46        Self: Sized;
47
48    fn wrap<U>(self, wrapper: U) -> WalWrapper<U, Self>
49    where
50        U: WrapWal<Self::Wal> + Clone,
51        Self: Sized,
52    {
53        WalWrapper::new(wrapper, self)
54    }
55}
56
57/// Wrapper type around `*mut sqlite3`, to seal the pointer from extern usage.
58pub struct Sqlite3Db {
59    inner: *mut sqlite3,
60}
61
62impl Sqlite3Db {
63    pub fn as_ptr(&mut self) -> *mut sqlite3 {
64        self.inner
65    }
66}
67
68/// Wrapper type around `*mut sqlite3_file`, to seal the pointer from extern usage.
69#[repr(transparent)]
70pub struct Sqlite3File {
71    inner: *mut sqlite3_file,
72}
73
74impl Sqlite3File {
75    pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_file {
76        self.inner
77    }
78
79    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<()> {
80        unsafe {
81            assert!(!self.inner.is_null());
82            let inner = &mut *self.inner;
83            assert!(!inner.pMethods.is_null());
84            let io_methods = &*inner.pMethods;
85
86            let read = io_methods.xRead.unwrap();
87
88            let rc = read(
89                self.inner,
90                buf.as_mut_ptr() as *mut _,
91                buf.len() as _,
92                offset as _,
93            );
94
95            if rc == 0 {
96                Ok(())
97            } else {
98                Err(Error::new(rc))
99            }
100        }
101    }
102}
103
104/// Wrapper type around `*mut sqlite3_vfs`, to seal the pointer from extern usage.
105pub struct Vfs {
106    vfs: *mut sqlite3_vfs,
107}
108
109impl Vfs {
110    pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_vfs {
111        self.vfs
112    }
113}
114
115pub struct PageHeaders {
116    inner: *mut libsql_pghdr,
117}
118
119impl PageHeaders {
120    pub(crate) fn as_ptr(&self) -> *const libsql_pghdr {
121        self.inner
122    }
123
124    pub(crate) fn as_mut_ptr(&mut self) -> *mut libsql_pghdr {
125        self.inner
126    }
127
128    /// # Safety
129    /// caller must ensure the headers list validity.
130    pub unsafe fn from_raw(inner: *mut libsql_pghdr) -> Self {
131        Self { inner }
132    }
133
134    pub fn iter(&self) -> PageHdrIter {
135        // TODO: move LIBSQL_PAGE_SIZE
136        PageHdrIter::new(self.as_ptr(), 4096)
137    }
138}
139
140pub trait BusyHandler {
141    // Handle busy, and returns whether a retry should be performed
142    fn handle_busy(&mut self) -> bool;
143}
144
145impl<F> BusyHandler for F
146where
147    F: FnMut() -> bool,
148{
149    fn handle_busy(&mut self) -> bool {
150        (self)()
151    }
152}
153
154pub trait UndoHandler {
155    fn handle_undo(&mut self, page_no: u32) -> Result<()>;
156}
157
158#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
159#[repr(i32)]
160pub enum CheckpointMode {
161    Passive = SQLITE_CHECKPOINT_PASSIVE,
162    Full = SQLITE_CHECKPOINT_FULL,
163    Restart = SQLITE_CHECKPOINT_RESTART,
164    Truncate = SQLITE_CHECKPOINT_TRUNCATE,
165}
166
167pub trait CheckpointCallback {
168    fn frame(
169        &mut self,
170        max_safe_frame_no: u32,
171        frame: &[u8],
172        page_no: NonZeroU32,
173        frame_no: NonZeroU32,
174    ) -> Result<()>;
175    fn finish(&mut self) -> Result<()>;
176}
177
178pub trait Wal {
179    /// Set the WAL limit in pages
180    fn limit(&mut self, size: i64);
181    /// start a read transaction. Returns whether the in-memory page cache should be invalidated.
182    fn begin_read_txn(&mut self) -> Result<bool>;
183    fn end_read_txn(&mut self);
184
185    /// locate the frame containing page `page_no`
186    fn find_frame(&mut self, page_no: NonZeroU32) -> Result<Option<NonZeroU32>>;
187    /// reads frame `frame_no` into buffer.
188    fn read_frame(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> Result<()>;
189    /// reads frame `frame_no` including its frame header into buffer.
190    fn read_frame_raw(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> Result<()>;
191
192    fn db_size(&self) -> u32;
193
194    fn begin_write_txn(&mut self) -> Result<()>;
195    fn end_write_txn(&mut self) -> Result<()>;
196
197    fn undo<U: UndoHandler>(&mut self, handler: Option<&mut U>) -> Result<()>;
198
199    fn savepoint(&mut self, rollback_data: &mut [u32]);
200    fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> Result<()>;
201
202    fn frame_count(&self, locked: i32) -> Result<u32>;
203
204    /// Insert frames in the wal. On commit, returns the number of inserted frames for that
205    /// transaction, or 0 for non-commit calls.
206    fn insert_frames(
207        &mut self,
208        page_size: c_int,
209        page_headers: &mut PageHeaders,
210        size_after: u32,
211        is_commit: bool,
212        sync_flags: c_int,
213    ) -> Result<usize>;
214
215    /// Returns the number of frames in the log and the number of checkpointed frames in the WAL.
216    fn checkpoint(
217        &mut self,
218        db: &mut Sqlite3Db,
219        mode: CheckpointMode,
220        busy_handler: Option<&mut dyn BusyHandler>,
221        sync_flags: u32,
222        // temporary scratch buffer
223        buf: &mut [u8],
224        checkpoint_cb: Option<&mut dyn CheckpointCallback>,
225        in_wal: Option<&mut i32>,
226        backfilled: Option<&mut i32>,
227    ) -> Result<()>;
228
229    fn exclusive_mode(&mut self, op: c_int) -> Result<()>;
230    fn uses_heap_memory(&self) -> bool;
231    fn set_db(&mut self, db: &mut Sqlite3Db);
232
233    /// Return the value to pass to a sqlite3_wal_hook callback, the
234    /// number of frames in the WAL at the point of the last commit since
235    /// sqlite3WalCallback() was called.  If no commits have occurred since
236    /// the last call, then return 0.
237    fn callback(&self) -> i32;
238
239    fn frames_in_wal(&self) -> u32;
240}