From d617d1d21ed1e9a1ef7435699b091c4046cb4182 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 22 Jul 2025 16:17:17 +0400 Subject: [PATCH 1/2] fix raw read frame WAL API --- core/lib.rs | 11 ++------- core/storage/pager.rs | 14 ++---------- core/storage/sqlite3_ondisk.rs | 18 +++++++++++++++ core/storage/wal.rs | 42 +++++++++------------------------- sqlite3/src/lib.rs | 3 ++- 5 files changed, 35 insertions(+), 53 deletions(-) diff --git a/core/lib.rs b/core/lib.rs index aa139b319..87daf3dc6 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -809,15 +809,8 @@ impl Connection { self.pager.borrow().wal_frame_count() } - pub fn wal_get_frame( - &self, - frame_no: u32, - p_frame: *mut u8, - frame_len: u32, - ) -> Result> { - self.pager - .borrow() - .wal_get_frame(frame_no, p_frame, frame_len) + pub fn wal_get_frame(&self, frame_no: u32, frame: &mut [u8]) -> Result> { + self.pager.borrow().wal_get_frame(frame_no, frame) } /// Flush dirty pages to disk. diff --git a/core/storage/pager.rs b/core/storage/pager.rs index bb3829a54..9bd087a74 100644 --- a/core/storage/pager.rs +++ b/core/storage/pager.rs @@ -956,19 +956,9 @@ impl Pager { } #[instrument(skip_all, level = Level::DEBUG)] - pub fn wal_get_frame( - &self, - frame_no: u32, - p_frame: *mut u8, - frame_len: u32, - ) -> Result> { + pub fn wal_get_frame(&self, frame_no: u32, frame: &mut [u8]) -> Result> { let wal = self.wal.borrow(); - wal.read_frame_raw( - frame_no.into(), - self.buffer_pool.clone(), - p_frame, - frame_len, - ) + wal.read_frame_raw(frame_no.into(), frame) } #[instrument(skip_all, level = Level::DEBUG, name = "pager_checkpoint",)] diff --git a/core/storage/sqlite3_ondisk.rs b/core/storage/sqlite3_ondisk.rs index bf5c1d47e..400d8af65 100644 --- a/core/storage/sqlite3_ondisk.rs +++ b/core/storage/sqlite3_ondisk.rs @@ -1509,6 +1509,24 @@ pub fn read_entire_wal_dumb(file: &Arc) -> Result, + offset: usize, + page_size: u32, + complete: Box>, i32)>, +) -> Result> { + tracing::trace!("begin_read_wal_frame_raw(offset={})", offset); + let drop_fn = Rc::new(|_buf| {}); + let buf = Arc::new(RefCell::new(Buffer::allocate( + page_size as usize + WAL_FRAME_HEADER_SIZE, + drop_fn, + ))); + #[allow(clippy::arc_with_non_send_sync)] + let c = Completion::new_read(buf, complete); + let c = io.pread(offset, c.into())?; + Ok(c) +} + pub fn begin_read_wal_frame( io: &Arc, offset: usize, diff --git a/core/storage/wal.rs b/core/storage/wal.rs index bb5eba210..83c4f86cf 100644 --- a/core/storage/wal.rs +++ b/core/storage/wal.rs @@ -20,8 +20,8 @@ use crate::fast_lock::SpinLock; use crate::io::{File, IO}; use crate::result::LimboResult; use crate::storage::sqlite3_ondisk::{ - begin_read_wal_frame, begin_write_wal_frame, finish_read_page, WAL_FRAME_HEADER_SIZE, - WAL_HEADER_SIZE, + begin_read_wal_frame, begin_read_wal_frame_raw, begin_write_wal_frame, finish_read_page, + WAL_FRAME_HEADER_SIZE, WAL_HEADER_SIZE, }; use crate::types::IOResult; use crate::{turso_assert, Buffer, LimboError, Result}; @@ -214,14 +214,9 @@ pub trait Wal { /// Read a frame from the WAL. fn read_frame(&self, frame_id: u64, page: PageRef, buffer_pool: Arc) -> Result<()>; - /// Read a frame from the WAL. - fn read_frame_raw( - &self, - frame_id: u64, - buffer_pool: Arc, - frame: *mut u8, - frame_len: u32, - ) -> Result>; + /// Read a raw frame (header included) from the WAL. + fn read_frame_raw(&self, frame_id: u64, frame: &mut [u8]) -> Result>; + /// Write a frame to the WAL. /// db_size is the database size in pages after the transaction finishes. @@ -289,13 +284,7 @@ impl Wal for DummyWAL { Ok(()) } - fn read_frame_raw( - &self, - _frame_id: u64, - _buffer_pool: Arc, - _frame: *mut u8, - _frame_len: u32, - ) -> Result> { + fn read_frame_raw(&self, _frame_id: u64, _frame: &mut [u8]) -> Result> { todo!(); } @@ -633,15 +622,10 @@ impl Wal for WalFile { } #[instrument(skip_all, level = Level::DEBUG)] - fn read_frame_raw( - &self, - frame_id: u64, - buffer_pool: Arc, - frame: *mut u8, - frame_len: u32, - ) -> Result> { + fn read_frame_raw(&self, frame_id: u64, frame: &mut [u8]) -> Result> { tracing::debug!("read_frame({})", frame_id); let offset = self.frame_offset(frame_id); + let (frame_ptr, frame_len) = (frame.as_mut_ptr(), frame.len()); let complete = Box::new(move |buf: Arc>, bytes_read: i32| { let buf = buf.borrow(); let buf_len = buf.len(); @@ -651,15 +635,11 @@ impl Wal for WalFile { ); let buf_ptr = buf.as_ptr(); unsafe { - std::ptr::copy_nonoverlapping(buf_ptr, frame, frame_len as usize); + std::ptr::copy_nonoverlapping(buf_ptr, frame_ptr, frame_len); } }); - let c = begin_read_wal_frame( - &self.get_shared().file, - offset + WAL_FRAME_HEADER_SIZE, - buffer_pool, - complete, - )?; + let c = + begin_read_wal_frame_raw(&self.get_shared().file, offset, self.page_size(), complete)?; Ok(c) } diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index c063bcccc..f502e0286 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -1185,7 +1185,8 @@ pub unsafe extern "C" fn libsql_wal_get_frame( } let db: &mut sqlite3 = &mut *db; let db = db.inner.lock().unwrap(); - match db.conn.wal_get_frame(frame_no, p_frame, frame_len) { + let frame = std::slice::from_raw_parts_mut(p_frame, frame_len as usize); + match db.conn.wal_get_frame(frame_no, frame) { Ok(c) => match db.io.wait_for_completion(c) { Ok(_) => SQLITE_OK, Err(_) => SQLITE_ERROR, From b34d081d352a7b62790c8a84cac6161a63e3fa29 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 22 Jul 2025 16:23:04 +0400 Subject: [PATCH 2/2] cargo fmt --- core/storage/wal.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/core/storage/wal.rs b/core/storage/wal.rs index 83c4f86cf..86106e521 100644 --- a/core/storage/wal.rs +++ b/core/storage/wal.rs @@ -217,7 +217,6 @@ pub trait Wal { /// Read a raw frame (header included) from the WAL. fn read_frame_raw(&self, frame_id: u64, frame: &mut [u8]) -> Result>; - /// Write a frame to the WAL. /// db_size is the database size in pages after the transaction finishes. /// db_size > 0 -> last frame written in transaction