Skip to content

Commit 61558b2

Browse files
committed
libsql-{sqlite3,ffi}: Add xReadFrameRaw() to the virtual WAL API
This adds a new xReadFrameRaw() function to the virtual WAL API, which upper layers can use to fetch the full frame, including the page number, that is useful for appending frames to a WAL.
1 parent 3ac4aa1 commit 61558b2

File tree

13 files changed

+151
-0
lines changed

13 files changed

+151
-0
lines changed

libsql-ffi/bundled/bindings/bindgen.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3289,6 +3289,14 @@ pub struct libsql_wal_methods {
32893289
arg3: *mut ::std::os::raw::c_uchar,
32903290
) -> ::std::os::raw::c_int,
32913291
>,
3292+
pub xReadFrameRaw: ::std::option::Option<
3293+
unsafe extern "C" fn(
3294+
pWal: *mut wal_impl,
3295+
arg1: ::std::os::raw::c_uint,
3296+
arg2: ::std::os::raw::c_int,
3297+
arg3: *mut ::std::os::raw::c_uchar,
3298+
) -> ::std::os::raw::c_int,
3299+
>,
32923300
pub xDbsize:
32933301
::std::option::Option<unsafe extern "C" fn(pWal: *mut wal_impl) -> ::std::os::raw::c_uint>,
32943302
pub xBeginWriteTransaction:

libsql-ffi/bundled/bindings/session_bindgen.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3795,6 +3795,14 @@ pub struct libsql_wal_methods {
37953795
arg3: *mut ::std::os::raw::c_uchar,
37963796
) -> ::std::os::raw::c_int,
37973797
>,
3798+
pub xReadFrameRaw: ::std::option::Option<
3799+
unsafe extern "C" fn(
3800+
pWal: *mut wal_impl,
3801+
arg1: ::std::os::raw::c_uint,
3802+
arg2: ::std::os::raw::c_int,
3803+
arg3: *mut ::std::os::raw::c_uchar,
3804+
) -> ::std::os::raw::c_int,
3805+
>,
37983806
pub xDbsize:
37993807
::std::option::Option<unsafe extern "C" fn(pWal: *mut wal_impl) -> ::std::os::raw::c_uint>,
38003808
pub xBeginWriteTransaction:

libsql-replication/src/injector/sqlite_injector/injector_wal.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ impl Wal for InjectorWal {
110110
self.inner.read_frame(frame_no, buffer)
111111
}
112112

113+
fn read_frame_raw(&mut self, frame_no: NonZeroU32, buffer: &mut [u8]) -> Result<()> {
114+
self.inner.read_frame_raw(frame_no, buffer)
115+
}
116+
113117
fn db_size(&self) -> u32 {
114118
self.inner.db_size()
115119
}

libsql-sqlite3/src/wal.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3391,6 +3391,29 @@ static int sqlite3WalReadFrame(
33913391
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
33923392
}
33933393

3394+
/*
3395+
** Read the contents of frame iRead from the wal file into buffer pOut
3396+
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
3397+
** error code otherwise.
3398+
*/
3399+
static int sqlite3WalReadFrameRaw(
3400+
Wal *pWal, /* WAL handle */
3401+
u32 iRead, /* Frame to read */
3402+
int nOut, /* Size of buffer pOut in bytes */
3403+
u8 *pOut /* Buffer to write page data to */
3404+
){
3405+
int sz;
3406+
i64 iOffset;
3407+
sz = pWal->hdr.szPage;
3408+
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
3409+
testcase( sz<=32768 );
3410+
testcase( sz>=65536 );
3411+
iOffset = walFrameOffset(iRead, sz);
3412+
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
3413+
sz += WAL_FRAME_HDRSIZE;
3414+
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
3415+
}
3416+
33943417
/*
33953418
** Return the size of the database in pages (or zero, if unknown).
33963419
*/
@@ -4513,6 +4536,7 @@ static int sqlite3WalOpen(
45134536
out->methods.xEndReadTransaction = (void (*)(wal_impl *))sqlite3WalEndReadTransaction;
45144537
out->methods.xFindFrame = (int (*)(wal_impl *, unsigned int, unsigned int *))sqlite3WalFindFrame;
45154538
out->methods.xReadFrame = (int (*)(wal_impl *, unsigned int, int, unsigned char *))sqlite3WalReadFrame;
4539+
out->methods.xReadFrameRaw = (int (*)(wal_impl *, unsigned int, int, unsigned char *))sqlite3WalReadFrameRaw;
45164540
out->methods.xDbsize = (unsigned int (*)(wal_impl *))sqlite3WalDbsize;
45174541
out->methods.xBeginWriteTransaction = (int (*)(wal_impl *))sqlite3WalBeginWriteTransaction;
45184542
out->methods.xEndWriteTransaction = (int (*)(wal_impl *))sqlite3WalEndWriteTransaction;

libsql-sqlite3/src/wal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef struct libsql_wal_methods {
5656
/* Read a page from the write-ahead log, if it is present. */
5757
int (*xFindFrame)(wal_impl* pWal, unsigned int, unsigned int *);
5858
int (*xReadFrame)(wal_impl* pWal, unsigned int, int, unsigned char *);
59+
int (*xReadFrameRaw)(wal_impl* pWal, unsigned int, int, unsigned char *);
5960

6061
/* If the WAL is not empty, return the size of the database. */
6162
unsigned int (*xDbsize)(wal_impl* pWal);

libsql-sqlite3/test/rust_suite/src/virtual_wal.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ mod tests {
9898
self.0.read_frame(frame_no, buffer)
9999
}
100100

101+
fn read_frame_raw(
102+
&mut self,
103+
page_no: NonZeroU32,
104+
buffer: &mut [u8],
105+
) -> libsql_sys::wal::Result<()> {
106+
self.0.read_frame_raw(page_no, buffer)
107+
}
108+
101109
fn frame_count(&self, locked: i32) -> libsql_sys::wal::Result<u32> {
102110
self.0.frame_count(locked)
103111
}

libsql-storage/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ impl Wal for DurableWal {
266266
Ok(())
267267
}
268268

269+
fn read_frame_raw(&mut self, _page_no: std::num::NonZeroU32, _buffer: &mut [u8]) -> Result<()> {
270+
todo!()
271+
}
272+
269273
fn frame_count(&self, _locked: i32) -> Result<u32> {
270274
todo!()
271275
}

libsql-sys/src/wal/either.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ macro_rules! create_either {
3939
}
4040
}
4141

42+
fn read_frame_raw(&mut self, frame_no: std::num::NonZeroU32, buffer: &mut [u8]) -> super::Result<()> {
43+
match self {
44+
$( $name::$t(inner) => inner.read_frame_raw(frame_no, buffer) ),*
45+
}
46+
}
47+
4248
fn db_size(&self) -> u32 {
4349
match self {
4450
$( $name::$t(inner) => inner.db_size() ),*

libsql-sys/src/wal/ffi.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) fn construct_libsql_wal<W: Wal>(wal: *mut W) -> libsql_wal {
2323
xEndReadTransaction: Some(end_read_transaction::<W>),
2424
xFindFrame: Some(find_frame::<W>),
2525
xReadFrame: Some(read_frame::<W>),
26+
xReadFrameRaw: Some(read_frame_raw::<W>),
2627
xDbsize: Some(db_size::<W>),
2728
xBeginWriteTransaction: Some(begin_write_transaction::<W>),
2829
xEndWriteTransaction: Some(end_write_transaction::<W>),
@@ -211,6 +212,23 @@ pub unsafe extern "C" fn read_frame<T: Wal>(
211212
}
212213
}
213214

215+
pub unsafe extern "C" fn read_frame_raw<T: Wal>(
216+
wal: *mut wal_impl,
217+
frame: u32,
218+
n_out: c_int,
219+
p_out: *mut u8,
220+
) -> i32 {
221+
let this = &mut (*(wal as *mut T));
222+
let buffer = std::slice::from_raw_parts_mut(p_out, n_out as usize);
223+
match this.read_frame_raw(
224+
NonZeroU32::new(frame).expect("invalid frame number"),
225+
buffer,
226+
) {
227+
Ok(_) => SQLITE_OK,
228+
Err(code) => code.extended_code,
229+
}
230+
}
231+
214232
pub unsafe extern "C" fn db_size<T: Wal>(wal: *mut wal_impl) -> u32 {
215233
let this = &mut (*(wal as *mut T));
216234
this.db_size()

libsql-sys/src/wal/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ pub trait Wal {
186186
fn find_frame(&mut self, page_no: NonZeroU32) -> Result<Option<NonZeroU32>>;
187187
/// reads frame `frame_no` into buffer.
188188
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<()>;
189191

190192
fn db_size(&self) -> u32;
191193

0 commit comments

Comments
 (0)