diff --git a/bottomless/src/bottomless_wal.rs b/bottomless/src/bottomless_wal.rs index 7f4dbaa3ae..efe10631b5 100644 --- a/bottomless/src/bottomless_wal.rs +++ b/bottomless/src/bottomless_wal.rs @@ -1,8 +1,12 @@ +use std::ffi::{c_int, CStr}; use std::ops::Deref; use std::sync::{Arc, Mutex}; use libsql_sys::ffi::{SQLITE_BUSY, SQLITE_IOERR_WRITE}; -use libsql_sys::wal::{CheckpointMode, CreateWal, Error, Result, Wal}; +use libsql_sys::wal::{ + CheckpointMode, CreateWal, Error, PageHeaders, Result, Sqlite3Db, Sqlite3File, UndoHandler, + Vfs, Wal, +}; use crate::replicator::Replicator; @@ -35,11 +39,11 @@ impl CreateWal for CreateBottomlessWal { fn open( &self, - vfs: &mut libsql_sys::wal::Vfs, - file: *mut libsql_sys::ffi::sqlite3_file, - no_shm_mode: std::ffi::c_int, + vfs: &mut Vfs, + file: &mut Sqlite3File, + no_shm_mode: c_int, max_log_size: i64, - db_path: &std::ffi::CStr, + db_path: &CStr, ) -> Result { let inner = self .inner @@ -53,26 +57,18 @@ impl CreateWal for CreateBottomlessWal { fn close( &self, wal: &mut Self::Wal, - db: *mut libsql_sys::ffi::sqlite3, - sync_flags: std::ffi::c_int, + db: &mut Sqlite3Db, + sync_flags: c_int, scratch: &mut [u8], ) -> Result<()> { self.inner.close(&mut wal.inner, db, sync_flags, scratch) } - fn destroy_log( - &self, - vfs: &mut libsql_sys::wal::Vfs, - db_path: &std::ffi::CStr, - ) -> Result<()> { + fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()> { self.inner.destroy_log(vfs, db_path) } - fn log_exists( - &self, - vfs: &mut libsql_sys::wal::Vfs, - db_path: &std::ffi::CStr, - ) -> Result { + fn log_exists(&self, vfs: &mut Vfs, db_path: &CStr) -> Result { self.inner.log_exists(vfs, db_path) } @@ -122,12 +118,8 @@ impl Wal for BottomlessWal { self.inner.end_write_txn() } - fn undo( - &mut self, - cb: Option i32>, - cb_ctx: *mut std::ffi::c_void, - ) -> Result<()> { - self.inner.undo(cb, cb_ctx) + fn undo(&mut self, undo_handler: Option<&mut U>) -> Result<()> { + self.inner.undo(undo_handler) } fn savepoint(&mut self, rollback_data: &mut [u32]) { @@ -152,11 +144,11 @@ impl Wal for BottomlessWal { fn insert_frames( &mut self, - page_size: std::ffi::c_int, - page_headers: *mut libsql_sys::ffi::PgHdr, + page_size: c_int, + page_headers: &mut PageHeaders, size_after: u32, is_commit: bool, - sync_flags: std::ffi::c_int, + sync_flags: c_int, ) -> Result<()> { let last_valid_frame = self.inner.last_fame_index(); @@ -178,7 +170,7 @@ impl Wal for BottomlessWal { fn checkpoint( &mut self, - db: *mut libsql_sys::ffi::sqlite3, + db: &mut Sqlite3Db, mode: CheckpointMode, busy_handler: Option<&mut B>, sync_flags: u32, @@ -253,7 +245,7 @@ impl Wal for BottomlessWal { Ok(ret) } - fn exclusive_mode(&mut self, op: std::ffi::c_int) -> Result<()> { + fn exclusive_mode(&mut self, op: c_int) -> Result<()> { self.inner.exclusive_mode(op) } @@ -261,7 +253,7 @@ impl Wal for BottomlessWal { self.inner.uses_heap_memory() } - fn set_db(&mut self, db: *mut libsql_sys::ffi::sqlite3) { + fn set_db(&mut self, db: &mut Sqlite3Db) { self.inner.set_db(db) } diff --git a/bottomless/src/lib.rs b/bottomless/src/lib.rs index f6be1ed17f..ef12e5a9ac 100644 --- a/bottomless/src/lib.rs +++ b/bottomless/src/lib.rs @@ -2,7 +2,6 @@ #![allow(clippy::not_unsafe_ptr_arg_deref)] #![allow(improper_ctypes)] -// mod ffi; mod backup; pub mod bottomless_wal; pub mod read; @@ -10,576 +9,3 @@ pub mod replicator; pub mod transaction_cache; pub mod uuid_utils; mod wal; - -// // Just heuristics, but should work for ~100% of cases -// fn is_regular(vfs: *const sqlite3_vfs) -> bool { -// let vfs = unsafe { std::ffi::CStr::from_ptr((*vfs).zName) } -// .to_str() -// .unwrap_or("[error]"); -// tracing::trace!("VFS: {}", vfs); -// vfs.starts_with("unix") || vfs.starts_with("win32") -// } -// -// macro_rules! block_on { -// ($runtime:expr, $e:expr) => { -// $runtime.block_on(async { $e.await }) -// }; -// } -// -// fn is_local() -> bool { -// std::env::var("LIBSQL_BOTTOMLESS_LOCAL").map_or(false, |local| { -// local.eq_ignore_ascii_case("true") -// || local.eq_ignore_ascii_case("t") -// || local.eq_ignore_ascii_case("yes") -// || local.eq_ignore_ascii_case("y") -// || local == "1" -// }) -// } - -// pub extern "C" fn xOpen( -// vfs: *mut sqlite3_vfs, -// db_file: *mut sqlite3_file, -// wal_name: *const c_char, -// no_shm_mode: i32, -// max_size: i64, -// methods: *mut libsql_wal_methods, -// wal: *mut *mut Wal, -// ) -> i32 { -// tracing::debug!("Opening WAL {}", unsafe { -// std::ffi::CStr::from_ptr(wal_name).to_str().unwrap() -// }); -// -// let orig_methods = unsafe { &*(*(methods as *mut bottomless_methods)).underlying_methods }; -// let rc = unsafe { -// (orig_methods.xOpen.unwrap())(vfs, db_file, wal_name, no_shm_mode, max_size, methods, wal) -// }; -// if rc != ffi::SQLITE_OK { -// return rc; -// } -// -// if !is_regular(vfs) { -// tracing::error!("Bottomless WAL is currently only supported for regular VFS"); -// return ffi::SQLITE_CANTOPEN; -// } -// -// if is_local() { -// tracing::info!("Running in local-mode only, without any replication"); -// return ffi::SQLITE_OK; -// } -// -// let runtime = match tokio::runtime::Builder::new_current_thread() -// .enable_all() -// .build() -// { -// Ok(runtime) => runtime, -// Err(e) => { -// tracing::error!("Failed to initialize async runtime: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// }; -// -// let path = unsafe { -// match std::ffi::CStr::from_ptr(wal_name).to_str() { -// Ok(path) if path.len() >= 4 => &path[..path.len() - 4], -// Ok(path) => path, -// Err(e) => { -// tracing::error!("Failed to parse the main database path: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// }; -// -// let replicator = block_on!(runtime, replicator::Replicator::new(path)); -// let mut replicator = match replicator { -// Ok(repl) => repl, -// Err(e) => { -// tracing::error!("Failed to initialize replicator: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// }; -// -// let rc = block_on!(runtime, try_restore(&mut replicator)); -// if rc != ffi::SQLITE_OK { -// return rc; -// } -// -// let context = replicator::Context { -// replicator, -// runtime, -// }; -// let context_ptr = Box::into_raw(Box::new(context)) as *mut c_void; -// unsafe { (*(*wal)).pMethodsData = context_ptr }; -// -// ffi::SQLITE_OK -// } -// -// fn get_orig_methods(wal: *mut Wal) -> &'static libsql_wal_methods { -// let wal = unsafe { &*wal }; -// let methods = unsafe { &*(wal.pMethods as *const bottomless_methods) }; -// unsafe { &*methods.underlying_methods } -// } -// -// fn get_replicator_context(wal: *mut Wal) -> &'static mut replicator::Context { -// unsafe { &mut *((*wal).pMethodsData as *mut replicator::Context) } -// } -// -// pub extern "C" fn xClose( -// wal: *mut Wal, -// db: *mut sqlite3, -// sync_flags: i32, -// n_buf: i32, -// z_buf: *mut u8, -// ) -> i32 { -// tracing::debug!("Closing wal"); -// let orig_methods = get_orig_methods(wal); -// let methods_data = unsafe { (*wal).pMethodsData as *mut replicator::Context }; -// let rc = unsafe { (orig_methods.xClose.unwrap())(wal, db, sync_flags, n_buf, z_buf) }; -// if rc != ffi::SQLITE_OK { -// return rc; -// } -// if !is_local() && !methods_data.is_null() { -// let _box = unsafe { Box::from_raw(methods_data) }; -// } -// rc -// } -// -// pub extern "C" fn xLimit(wal: *mut Wal, limit: i64) { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xLimit.unwrap())(wal, limit) } -// } -// -// pub extern "C" fn xBeginReadTransaction(wal: *mut Wal, changed: *mut i32) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xBeginReadTransaction.unwrap())(wal, changed) } -// } -// -// pub extern "C" fn xEndReadTransaction(wal: *mut Wal) { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xEndReadTransaction.unwrap())(wal) } -// } -// -// pub extern "C" fn xFindFrame(wal: *mut Wal, pgno: u32, frame: *mut u32) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xFindFrame.unwrap())(wal, pgno, frame) } -// } -// -// pub extern "C" fn xReadFrame(wal: *mut Wal, frame: u32, n_out: i32, p_out: *mut u8) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xReadFrame.unwrap())(wal, frame, n_out, p_out) } -// } -// -// pub extern "C" fn xDbsize(wal: *mut Wal) -> u32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xDbsize.unwrap())(wal) } -// } -// -// pub extern "C" fn xBeginWriteTransaction(wal: *mut Wal) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xBeginWriteTransaction.unwrap())(wal) } -// } -// -// pub extern "C" fn xEndWriteTransaction(wal: *mut Wal) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xEndWriteTransaction.unwrap())(wal) } -// } -// -// pub extern "C" fn xUndo( -// wal: *mut Wal, -// func: Option i32>, -// ctx: *mut c_void, -// ) -> i32 { -// let orig_methods = get_orig_methods(wal); -// let rc = unsafe { (orig_methods.xUndo.unwrap())(wal, func, ctx) }; -// if is_local() || rc != ffi::SQLITE_OK { -// return rc; -// } -// -// let last_valid_frame = unsafe { (*wal).hdr.mxFrame }; -// let ctx = get_replicator_context(wal); -// tracing::trace!( -// "Undo: rolling back from frame {} to {}", -// ctx.replicator.peek_last_valid_frame(), -// last_valid_frame -// ); -// ctx.replicator.rollback_to_frame(last_valid_frame); -// -// ffi::SQLITE_OK -// } -// -// pub extern "C" fn xSavepoint(wal: *mut Wal, wal_data: *mut u32) { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xSavepoint.unwrap())(wal, wal_data) } -// } -// -// pub extern "C" fn xSavepointUndo(wal: *mut Wal, wal_data: *mut u32) -> i32 { -// let orig_methods = get_orig_methods(wal); -// let rc = unsafe { (orig_methods.xSavepointUndo.unwrap())(wal, wal_data) }; -// if is_local() || rc != ffi::SQLITE_OK { -// return rc; -// } -// -// let last_valid_frame = unsafe { *wal_data }; -// let ctx = get_replicator_context(wal); -// tracing::trace!( -// "Savepoint: rolling back from frame {} to {}", -// ctx.replicator.peek_last_valid_frame(), -// last_valid_frame -// ); -// ctx.replicator.rollback_to_frame(last_valid_frame); -// -// ffi::SQLITE_OK -// } -// -// pub extern "C" fn xFrames( -// wal: *mut Wal, -// page_size: i32, -// page_headers: *mut PgHdr, -// size_after: u32, -// is_commit: i32, -// sync_flags: i32, -// ) -> i32 { -// if !is_local() { -// let ctx = get_replicator_context(wal); -// let last_valid_frame = unsafe { (*wal).hdr.mxFrame }; -// ctx.replicator.register_last_valid_frame(last_valid_frame); -// // In theory it's enough to set the page size only once, but in practice -// // it's a very cheap operation anyway, and the page is not always known -// // upfront and can change dynamically. -// // FIXME: changing the page size in the middle of operation is *not* -// // supported by bottomless storage. -// if let Err(e) = ctx.replicator.set_page_size(page_size as usize) { -// tracing::error!("{}", e); -// return ffi::SQLITE_IOERR_WRITE; -// } -// let frame_count = ffi::PageHdrIter::new(page_headers, page_size as usize).count(); -// if size_after != 0 { -// // only submit frames from committed transactions -// ctx.replicator.submit_frames(frame_count as u32); -// } -// } -// -// let orig_methods = get_orig_methods(wal); -// let rc = unsafe { -// (orig_methods.xFrames.unwrap())( -// wal, -// page_size, -// page_headers, -// size_after, -// is_commit, -// sync_flags, -// ) -// }; -// if is_local() || rc != ffi::SQLITE_OK { -// return rc; -// } -// -// ffi::SQLITE_OK -// } -// -// extern "C" fn always_wait(_busy_param: *mut c_void) -> i32 { -// std::thread::sleep(std::time::Duration::from_millis(10)); -// 1 -// } -// -// #[tracing::instrument(skip(wal, db, busy_handler, busy_arg))] -// pub extern "C" fn xCheckpoint( -// wal: *mut Wal, -// db: *mut sqlite3, -// emode: i32, -// busy_handler: Option i32>, -// busy_arg: *mut c_void, -// sync_flags: i32, -// n_buf: i32, -// z_buf: *mut u8, -// frames_in_wal: *mut i32, -// backfilled_frames: *mut i32, -// ) -> i32 { -// tracing::trace!("Checkpoint"); -// let start = Instant::now(); -// -// /* In order to avoid partial checkpoints, passive checkpoint -// ** mode is not allowed. Only TRUNCATE checkpoints are accepted, -// ** because these are guaranteed to block writes, copy all WAL pages -// ** back into the main database file and reset the frame number. -// ** In order to avoid autocheckpoint on close (that's too often), -// ** checkpoint attempts weaker than TRUNCATE are ignored. -// */ -// if emode < ffi::SQLITE_CHECKPOINT_TRUNCATE { -// tracing::trace!("Ignoring a checkpoint request weaker than TRUNCATE"); -// return ffi::SQLITE_OK; -// } -// -// let ctx = get_replicator_context(wal); -// let last_known_frame = ctx.replicator.last_known_frame(); -// ctx.replicator.request_flush(); -// if last_known_frame == 0 { -// tracing::debug!("No committed changes in this generation, not snapshotting"); -// ctx.replicator.skip_snapshot_for_current_generation(); -// return ffi::SQLITE_OK; -// } -// if let Err(e) = block_on!( -// ctx.runtime, -// ctx.replicator.wait_until_committed(last_known_frame) -// ) { -// tracing::error!( -// "Failed to finalize frame {} replication: {}", -// last_known_frame, -// e -// ); -// return ffi::SQLITE_IOERR_WRITE; -// } -// if let Err(e) = block_on!(ctx.runtime, ctx.replicator.wait_until_snapshotted()) { -// tracing::error!("Failed to finalize snapshot replication: {}", e); -// return ffi::SQLITE_IOERR_WRITE; -// } -// -// /* If there's no busy handler, let's provide a default one, -// ** since we auto-upgrade the passive checkpoint -// */ -// let busy_handler = Some(busy_handler.unwrap_or_else(|| { -// tracing::trace!("Falling back to the default busy handler - always wait"); -// always_wait -// })); -// -// let orig_methods = get_orig_methods(wal); -// let rc = unsafe { -// (orig_methods.xCheckpoint.unwrap())( -// wal, -// db, -// emode, -// busy_handler, -// busy_arg, -// sync_flags, -// n_buf, -// z_buf, -// frames_in_wal, -// backfilled_frames, -// ) -// }; -// -// if is_local() || rc != ffi::SQLITE_OK { -// return rc; -// } -// -// let _prev = ctx.replicator.new_generation(); -// tracing::debug!("Snapshotting after checkpoint"); -// match block_on!(ctx.runtime, ctx.replicator.snapshot_main_db_file()) { -// Ok(_handle) => { -// tracing::trace!("got snapshot handle"); -// } -// Err(e) => { -// tracing::error!( -// "Failed to snapshot the main db file during checkpoint: {}", -// e -// ); -// return ffi::SQLITE_IOERR_WRITE; -// } -// } -// tracing::debug!("Checkpoint completed in {:?}", Instant::now() - start); -// -// ffi::SQLITE_OK -// } -// -// pub extern "C" fn xCallback(wal: *mut Wal) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xCallback.unwrap())(wal) } -// } -// -// pub extern "C" fn xExclusiveMode(wal: *mut Wal, op: i32) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xExclusiveMode.unwrap())(wal, op) } -// } -// -// pub extern "C" fn xHeapMemory(wal: *mut Wal) -> i32 { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xHeapMemory.unwrap())(wal) } -// } -// -// pub extern "C" fn xFile(wal: *mut Wal) -> *mut sqlite3_file { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xFile.unwrap())(wal) } -// } -// -// pub extern "C" fn xDb(wal: *mut Wal, db: *mut sqlite3) { -// let orig_methods = get_orig_methods(wal); -// unsafe { (orig_methods.xDb.unwrap())(wal, db) } -// } -// -// pub extern "C" fn xPathnameLen(orig_len: i32) -> i32 { -// orig_len + 4 -// } -// -// pub extern "C" fn xGetPathname(buf: *mut c_char, orig: *const c_char, orig_len: i32) { -// unsafe { std::ptr::copy(orig, buf, orig_len as usize) } -// unsafe { -// std::ptr::copy( -// "-wal".as_ptr() as *const _, -// buf.offset(orig_len as isize), -// 4, -// ) -// } -// } - -// async fn try_restore(replicator: &mut replicator::Replicator) -> i32 { -// match replicator.restore(None, None).await { -// Ok((replicator::RestoreAction::SnapshotMainDbFile, _)) => { -// replicator.new_generation(); -// match replicator.snapshot_main_db_file().await { -// Ok(Some(h)) => { -// if let Err(e) = h.await { -// tracing::error!("Failed to join snapshot main db file task: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// Ok(None) => {} -// Err(e) => { -// tracing::error!("Failed to snapshot the main db file: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// // Restoration process only leaves the local WAL file if it was -// // detected to be newer than its remote counterpart. -// if let Err(e) = replicator.maybe_replicate_wal().await { -// tracing::error!("Failed to replicate local WAL: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// Ok((replicator::RestoreAction::ReuseGeneration(gen), _)) => { -// replicator.set_generation(gen); -// } -// Err(e) => { -// tracing::error!("Failed to restore the database: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// -// ffi::SQLITE_OK -// } - -// pub extern "C" fn xPreMainDbOpen(_methods: *mut libsql_wal_methods, path: *const c_char) -> i32 { -// if is_local() { -// tracing::info!("Running in local-mode only, without any replication"); -// return ffi::SQLITE_OK; -// } -// -// if path.is_null() { -// return ffi::SQLITE_OK; -// } -// let path = unsafe { -// match std::ffi::CStr::from_ptr(path).to_str() { -// Ok(path) => path, -// Err(e) => { -// tracing::error!("Failed to parse the main database path: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// } -// }; -// tracing::debug!("Main database file {} will be open soon", path); -// -// let runtime = match tokio::runtime::Builder::new_current_thread() -// .enable_all() -// .build() -// { -// Ok(runtime) => runtime, -// Err(e) => { -// tracing::error!("Failed to initialize async runtime: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// }; -// -// let options = match replicator::Options::from_env() { -// Ok(options) => options, -// Err(e) => { -// tracing::error!("Failed to parse replicator options: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// }; -// let replicator = block_on!(runtime, replicator::Replicator::with_options(path, options)); -// let mut replicator = match replicator { -// Ok(repl) => repl, -// Err(e) => { -// tracing::error!("Failed to initialize replicator: {}", e); -// return ffi::SQLITE_CANTOPEN; -// } -// }; -// block_on!(runtime, try_restore(&mut replicator)) -// } -// -// #[no_mangle] -// pub extern "C" fn bottomless_init() { -// tracing::debug!("bottomless module initialized"); -// } -// -// #[no_mangle] -// pub extern "C" fn bottomless_tracing_init() { -// tracing_subscriber::fmt::init(); -// } - -// #[tracing::instrument] -// #[no_mangle] -// pub extern "C" fn bottomless_methods( -// underlying_methods: *const libsql_wal_methods, -// ) -> *const libsql_wal_methods { -// let vwal_name: *const c_char = "bottomless\0".as_ptr() as *const _; -// -// Box::into_raw(Box::new(bottomless_methods { -// methods: libsql_wal_methods { -// iVersion: 1, -// xOpen: Some(xOpen), -// xClose: Some(xClose), -// xLimit: Some(xLimit), -// xBeginReadTransaction: Some(xBeginReadTransaction), -// xEndReadTransaction: Some(xEndReadTransaction), -// xFindFrame: Some(xFindFrame), -// xReadFrame: Some(xReadFrame), -// xDbsize: Some(xDbsize), -// xBeginWriteTransaction: Some(xBeginWriteTransaction), -// xEndWriteTransaction: Some(xEndWriteTransaction), -// xUndo: Some(xUndo), -// xSavepoint: Some(xSavepoint), -// xSavepointUndo: Some(xSavepointUndo), -// xFrames: Some(xFrames), -// xCheckpoint: Some(xCheckpoint), -// xCallback: Some(xCallback), -// xExclusiveMode: Some(xExclusiveMode), -// xHeapMemory: Some(xHeapMemory), -// xSnapshotGet: None, -// xSnapshotOpen: None, -// xSnapshotRecover: None, -// xSnapshotCheck: None, -// xSnapshotUnlock: None, -// xFramesize: None, -// xFile: Some(xFile), -// xWriteLock: None, -// xDb: Some(xDb), -// xPathnameLen: Some(xPathnameLen), -// xGetWalPathname: Some(xGetPathname), -// xPreMainDbOpen: Some(xPreMainDbOpen), -// zName: vwal_name, -// bUsesShm: 0, -// pNext: std::ptr::null_mut(), -// }, -// underlying_methods, -// })) as *const libsql_wal_methods -// } -#[cfg(feature = "libsql_linked_statically")] -pub mod static_init { - - pub fn register_bottomless_methods() { - todo!() - // static INIT: std::sync::Once = std::sync::Once::new(); - // INIT.call_once(|| { - // crate::bottomless_init(); - // let orig_methods = unsafe { libsql_wal_methods_find(std::ptr::null()) }; - // if orig_methods.is_null() { - // panic!("failed to locate default WAL methods") - // } - // let methods = crate::bottomless_methods(orig_methods); - // let rc = unsafe { libsql_wal_methods_register(methods) }; - // if rc != crate::ffi::SQLITE_OK { - // let _box = unsafe { Box::from_raw(methods as *mut libsql_wal_methods) }; - // tracing::warn!("Failed to instantiate bottomless WAL methods"); - // } - // }) - } -} diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 443da80e93..283539e16d 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -60156,7 +60156,6 @@ static int pagerOpenWalIfPresent(Pager *pPager){ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); - printf("hello\n"); if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ rc =pPager->create_wal->ref.xLogExists(pPager->create_wal->ref.pData, pPager->pVfs, pPager->zFilename, &isWal); diff --git a/libsql-ffi/src/lib.rs b/libsql-ffi/src/lib.rs index 819ec2ca88..e039091921 100644 --- a/libsql-ffi/src/lib.rs +++ b/libsql-ffi/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(non_snake_case, non_camel_case_types)] +#![allow(non_snake_case, non_camel_case_types, clippy::type_complexity)] #![cfg_attr(test, allow(deref_nullptr))] // https://github.com/rust-lang/rust-bindgen/issues/2066 use std::default::Default; @@ -7,7 +7,6 @@ use std::fmt; use std::mem; use std::os::raw::c_int; - include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); #[must_use] diff --git a/libsql-replication/Cargo.toml b/libsql-replication/Cargo.toml index e4430f8a23..2de7772cd0 100644 --- a/libsql-replication/Cargo.toml +++ b/libsql-replication/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] tonic = { version = "0.10.0", features = ["tls"] } prost = "0.12" -libsql-sys = { path = "../libsql-sys", default-feature = false, features = ["wal", "rusqlite"] } +libsql-sys = { path = "../libsql-sys", default-features = false, features = ["wal", "rusqlite"] } rusqlite = { workspace = true } parking_lot = "0.12.1" bytemuck = { version = "1.13.0", features = ["derive"] } diff --git a/libsql-replication/src/injector/injector_wal.rs b/libsql-replication/src/injector/injector_wal.rs index b8dccdb803..13f1d3d659 100644 --- a/libsql-replication/src/injector/injector_wal.rs +++ b/libsql-replication/src/injector/injector_wal.rs @@ -1,8 +1,9 @@ use std::ffi::{c_int, CStr}; -use libsql_sys::ffi::{sqlite3, sqlite3_file, PgHdr}; +use libsql_sys::ffi::PgHdr; use libsql_sys::wal::{ - BusyHandler, CheckpointMode, CreateSqlite3Wal, CreateWal, Result, Sqlite3Wal, Vfs, Wal, + BusyHandler, CheckpointMode, CreateSqlite3Wal, CreateWal, PageHeaders, Result, Sqlite3Db, + Sqlite3File, Sqlite3Wal, UndoHandler, Vfs, Wal, }; use crate::frame::FrameBorrowed; @@ -40,12 +41,11 @@ impl CreateWal for CreateInjectorWal { fn open( &self, vfs: &mut Vfs, - file: *mut sqlite3_file, + file: &mut Sqlite3File, no_shm_mode: c_int, max_log_size: i64, db_path: &CStr, ) -> Result { - dbg!(); let inner = self .inner .open(vfs, file, no_shm_mode, max_log_size, db_path)?; @@ -59,7 +59,7 @@ impl CreateWal for CreateInjectorWal { fn close( &self, wal: &mut Self::Wal, - db: *mut sqlite3, + db: &mut Sqlite3Db, sync_flags: c_int, scratch: &mut [u8], ) -> Result<()> { @@ -121,12 +121,8 @@ impl Wal for InjectorWal { self.inner.end_write_txn() } - fn undo( - &mut self, - cb: Option i32>, - cb_ctx: *mut std::ffi::c_void, - ) -> Result<()> { - self.inner.undo(cb, cb_ctx) + fn undo(&mut self, undo_handler: Option<&mut U>) -> Result<()> { + self.inner.undo(undo_handler) } fn savepoint(&mut self, rollback_data: &mut [u32]) { @@ -140,44 +136,48 @@ impl Wal for InjectorWal { fn insert_frames( &mut self, page_size: c_int, - _page_headers: *mut libsql_sys::ffi::PgHdr, + _page_headers: &mut PageHeaders, _size_after: u32, - is_commit: bool, + _is_commit: bool, sync_flags: c_int, ) -> Result<()> { self.is_txn = true; - let buffer = self.buffer.lock(); - let (mut headers, size_after) = make_page_header(buffer.iter().map(|f| &**f)); - - if let Err(e) = self.inner.insert_frames( - page_size, - headers.as_mut_ptr(), - size_after, - is_commit, - sync_flags, - ) { - tracing::error!("fatal replication error: failed to apply pages: {e}"); - return Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_FATAL)); - } + let mut buffer = self.buffer.lock(); + + { + let (mut headers, size_after) = make_page_header(buffer.iter().map(|f| &**f)); + let mut page_headers = unsafe { PageHeaders::from_raw(headers.as_mut_ptr()) }; + if let Err(e) = self.inner.insert_frames( + page_size, + &mut page_headers, + size_after, + size_after != 0, + sync_flags, + ) { + tracing::error!("fatal replication error: failed to apply pages: {e}"); + return Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_FATAL)); + } - debug_assert!(headers.all_applied()); - if size_after != 0 { - self.is_txn = false; + debug_assert!(headers.all_applied()); + drop(headers); + if size_after != 0 { + self.is_txn = false; + } } tracing::trace!("applied frame batch"); - self.buffer.lock().clear(); + buffer.clear(); if !self.is_txn { - return Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_OK)); + Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_OK)) } else { - return Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_OK_TXN)); + Err(libsql_sys::wal::Error::new(LIBSQL_INJECT_OK_TXN)) } } fn checkpoint( &mut self, - db: *mut sqlite3, + db: &mut Sqlite3Db, mode: CheckpointMode, busy_handler: Option<&mut B>, sync_flags: u32, @@ -196,7 +196,7 @@ impl Wal for InjectorWal { self.inner.uses_heap_memory() } - fn set_db(&mut self, db: *mut sqlite3) { + fn set_db(&mut self, db: &mut Sqlite3Db) { self.inner.set_db(db) } diff --git a/libsql-replication/src/injector/mod.rs b/libsql-replication/src/injector/mod.rs index 3423e84194..90f0836700 100644 --- a/libsql-replication/src/injector/mod.rs +++ b/libsql-replication/src/injector/mod.rs @@ -152,8 +152,8 @@ impl Injector { #[cfg(test)] mod test { - use std::mem::size_of; use crate::frame::FrameBorrowed; + use std::mem::size_of; use super::*; /// this this is generated by creating a table test, inserting 5 rows into it, and then diff --git a/libsql-server/src/connection/libsql.rs b/libsql-server/src/connection/libsql.rs index f4b867bdf6..9c3b17640e 100644 --- a/libsql-server/src/connection/libsql.rs +++ b/libsql-server/src/connection/libsql.rs @@ -3,10 +3,10 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use libsql_sys::wal::{CreateWal, Wal}; use metrics::{histogram, increment_counter}; use parking_lot::{Mutex, RwLock}; use rusqlite::{DatabaseName, ErrorCode, OpenFlags, StatementStatus, TransactionState}; -use libsql_sys::wal::{CreateWal, Wal}; use tokio::sync::{watch, Notify}; use tokio::time::{Duration, Instant}; @@ -45,7 +45,7 @@ pub struct MakeLibSqlConn { impl MakeLibSqlConn where - T: CreateWal + Clone +Send + 'static, + T: CreateWal + Clone + Send + 'static, T::Wal: Send + 'static, { #[allow(clippy::too_many_arguments)] @@ -147,7 +147,9 @@ pub struct LibSqlConnection { impl Clone for LibSqlConnection { fn clone(&self) -> Self { - Self { inner: self.inner.clone() } + Self { + inner: self.inner.clone(), + } } } @@ -193,8 +195,9 @@ where builder_config: QueryBuilderConfig, current_frame_no_receiver: watch::Receiver>, state: Arc>, - ) -> crate::Result - where T: CreateWal + Send + 'static, + ) -> crate::Result + where + T: CreateWal + Send + 'static, { let max_db_size = config_store.get().max_db_pages; let conn = tokio::task::spawn_blocking(move || -> crate::Result<_> { @@ -289,7 +292,10 @@ impl TxnSlot { self.created_at + TXN_TIMEOUT } - fn abort(&self) where T: Wal { + fn abort(&self) + where + T: Wal, + { let conn = self.conn.lock(); // we have a lock on the connection, we don't need mode than a // Relaxed store. diff --git a/libsql-server/src/connection/write_proxy.rs b/libsql-server/src/connection/write_proxy.rs index 7d7d9fdf39..a9cf3f0d26 100644 --- a/libsql-server/src/connection/write_proxy.rs +++ b/libsql-server/src/connection/write_proxy.rs @@ -8,8 +8,8 @@ use libsql_replication::rpc::proxy::{ exec_req, exec_resp, ExecReq, ExecResp, StreamDescribeReq, StreamProgramReq, }; use libsql_replication::rpc::replication::NAMESPACE_METADATA_KEY; -use parking_lot::Mutex as PMutex; use libsql_sys::wal::{CreateSqlite3Wal, Sqlite3Wal}; +use parking_lot::Mutex as PMutex; use tokio::sync::{mpsc, watch, Mutex}; use tokio_stream::StreamExt; use tonic::metadata::BinaryMetadataValue; diff --git a/libsql-server/src/lib.rs b/libsql-server/src/lib.rs index b1e1b86d5f..46e827e535 100644 --- a/libsql-server/src/lib.rs +++ b/libsql-server/src/lib.rs @@ -25,6 +25,7 @@ use config::{ use http::user::UserApi; use hyper::client::HttpConnector; use hyper_rustls::HttpsConnector; +pub use libsql_sys as libsql_bindings; use namespace::{ MakeNamespace, NamespaceName, NamespaceStore, PrimaryNamespaceConfig, PrimaryNamespaceMaker, ReplicaNamespaceConfig, ReplicaNamespaceMaker, @@ -32,7 +33,6 @@ use namespace::{ use net::Connector; use once_cell::sync::Lazy; use replication::NamespacedSnapshotCallback; -pub use libsql_sys as libsql_bindings; use tokio::runtime::Runtime; use tokio::sync::{mpsc, Notify}; use tokio::task::JoinSet; @@ -275,24 +275,16 @@ where { /// Setup sqlite global environment fn init_sqlite_globals(&self) { - if self.db_config.bottomless_replication.is_some() { - bottomless::static_init::register_bottomless_methods(); - } - if let Some(soft_limit_mb) = self.db_config.soft_heap_limit_mb { tracing::warn!("Setting soft heap limit to {soft_limit_mb}MiB"); unsafe { - libsql_sys::ffi::sqlite3_soft_heap_limit64( - soft_limit_mb as i64 * 1024 * 1024, - ) + libsql_sys::ffi::sqlite3_soft_heap_limit64(soft_limit_mb as i64 * 1024 * 1024) }; } if let Some(hard_limit_mb) = self.db_config.hard_heap_limit_mb { tracing::warn!("Setting hard heap limit to {hard_limit_mb}MiB"); unsafe { - libsql_sys::ffi::sqlite3_hard_heap_limit64( - hard_limit_mb as i64 * 1024 * 1024, - ) + libsql_sys::ffi::sqlite3_hard_heap_limit64(hard_limit_mb as i64 * 1024 * 1024) }; } } @@ -331,7 +323,7 @@ where let heartbeat_auth = config.heartbeat_auth.clone(); let heartbeat_period = config.heartbeat_period; let heartbeat_url = if let Some(url) = &config.heartbeat_url { - Some(Url::from_str(&url).context("invalid heartbeat URL")?) + Some(Url::from_str(url).context("invalid heartbeat URL")?) } else { None }; diff --git a/libsql-server/src/namespace/mod.rs b/libsql-server/src/namespace/mod.rs index 96b8b4d756..3f2e268a67 100644 --- a/libsql-server/src/namespace/mod.rs +++ b/libsql-server/src/namespace/mod.rs @@ -14,9 +14,9 @@ use enclose::enclose; use futures_core::Stream; use hyper::Uri; use libsql_replication::rpc::replication::replication_log_client::ReplicationLogClient; +use libsql_sys::wal::{CreateSqlite3Wal, CreateWal}; use parking_lot::Mutex; use rusqlite::ErrorCode; -use libsql_sys::wal::{CreateSqlite3Wal, CreateWal}; use tokio::io::AsyncBufReadExt; use tokio::sync::watch; use tokio::task::JoinSet; diff --git a/libsql-server/src/namespace/replication_wal.rs b/libsql-server/src/namespace/replication_wal.rs index 9fe1c46c38..9735eefe59 100644 --- a/libsql-server/src/namespace/replication_wal.rs +++ b/libsql-server/src/namespace/replication_wal.rs @@ -1,9 +1,10 @@ -use std::ffi::{c_int, CStr, c_void}; +use std::ffi::{c_int, CStr}; use bottomless::bottomless_wal::{BottomlessWal, CreateBottomlessWal}; -use rusqlite::ffi::PgHdr; -use libsql_sys::ffi::{sqlite3, sqlite3_file}; -use libsql_sys::wal::{CreateWal, Result, Vfs, Wal, BusyHandler, CheckpointMode}; +use libsql_sys::wal::{ + BusyHandler, CheckpointMode, CreateWal, PageHeaders, Result, Sqlite3Db, Sqlite3File, + UndoHandler, Vfs, Wal, +}; use crate::replication::primary::replication_logger_wal::{ CreateReplicationLoggerWal, ReplicationLoggerWal, @@ -30,7 +31,7 @@ impl CreateWal for CreateReplicationWal { fn open( &self, vfs: &mut Vfs, - file: *mut sqlite3_file, + file: &mut Sqlite3File, no_shm_mode: c_int, max_log_size: i64, db_path: &CStr, @@ -48,14 +49,18 @@ impl CreateWal for CreateReplicationWal { fn close( &self, wal: &mut Self::Wal, - db: *mut sqlite3, + db: &mut Sqlite3Db, sync_flags: c_int, scratch: &mut [u8], ) -> Result<()> { match (self, wal) { - (CreateReplicationWal::Bottomless(inner), ReplicationWal::Bottomless(wal)) => inner.close(wal, db, sync_flags, scratch), - (CreateReplicationWal::Logger(inner), ReplicationWal::Logger(wal)) => inner.close(wal, db, sync_flags, scratch), - _ => unreachable!() + (CreateReplicationWal::Bottomless(inner), ReplicationWal::Bottomless(wal)) => { + inner.close(wal, db, sync_flags, scratch) + } + (CreateReplicationWal::Logger(inner), ReplicationWal::Logger(wal)) => { + inner.close(wal, db, sync_flags, scratch) + } + _ => unreachable!(), } } @@ -90,7 +95,7 @@ pub enum ReplicationWal { } impl Wal for ReplicationWal { - fn limit(&mut self,size:i64) { + fn limit(&mut self, size: i64) { match self { ReplicationWal::Bottomless(inner) => inner.limit(size), ReplicationWal::Logger(inner) => inner.limit(size), @@ -111,14 +116,14 @@ impl Wal for ReplicationWal { } } - fn find_frame(&mut self,page_no:u32) -> Result { + fn find_frame(&mut self, page_no: u32) -> Result { match self { ReplicationWal::Bottomless(inner) => inner.find_frame(page_no), ReplicationWal::Logger(inner) => inner.find_frame(page_no), } } - fn read_frame(&mut self,frame_no:u32,buffer: &mut[u8]) -> Result<()> { + fn read_frame(&mut self, frame_no: u32, buffer: &mut [u8]) -> Result<()> { match self { ReplicationWal::Bottomless(inner) => inner.read_frame(frame_no, buffer), ReplicationWal::Logger(inner) => inner.read_frame(frame_no, buffer), @@ -146,42 +151,64 @@ impl Wal for ReplicationWal { } } - fn undo(&mut self,cb:Option i32>,cb_ctx: *mut c_void,) -> Result<()> { + fn undo(&mut self, undo_handler: Option<&mut U>) -> Result<()> { match self { - ReplicationWal::Bottomless(inner) => inner.undo(cb, cb_ctx), - ReplicationWal::Logger(inner) => inner.undo(cb, cb_ctx), + ReplicationWal::Bottomless(inner) => inner.undo(undo_handler), + ReplicationWal::Logger(inner) => inner.undo(undo_handler), } } - fn savepoint(&mut self,rollback_data: &mut[u32]) { + fn savepoint(&mut self, rollback_data: &mut [u32]) { match self { ReplicationWal::Bottomless(inner) => inner.savepoint(rollback_data), ReplicationWal::Logger(inner) => inner.savepoint(rollback_data), } } - fn savepoint_undo(&mut self,rollback_data: &mut[u32]) -> Result<()> { + fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> Result<()> { match self { ReplicationWal::Bottomless(inner) => inner.savepoint_undo(rollback_data), ReplicationWal::Logger(inner) => inner.savepoint_undo(rollback_data), } } - fn insert_frames(&mut self,page_size:c_int,page_headers: *mut PgHdr,size_after:u32,is_commit:bool,sync_flags:c_int,) -> Result<()> { + fn insert_frames( + &mut self, + page_size: c_int, + page_headers: &mut PageHeaders, + size_after: u32, + is_commit: bool, + sync_flags: c_int, + ) -> Result<()> { match self { - ReplicationWal::Bottomless(inner) => inner.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags), - ReplicationWal::Logger(inner) => inner.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags), + ReplicationWal::Bottomless(inner) => { + inner.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags) + } + ReplicationWal::Logger(inner) => { + inner.insert_frames(page_size, page_headers, size_after, is_commit, sync_flags) + } } } - fn checkpoint(&mut self,db: *mut sqlite3,mode:CheckpointMode,busy_handler:Option<&mut B>,sync_flags:u32,buf: &mut[u8],) -> Result<(u32,u32)> { + fn checkpoint( + &mut self, + db: &mut Sqlite3Db, + mode: CheckpointMode, + busy_handler: Option<&mut B>, + sync_flags: u32, + buf: &mut [u8], + ) -> Result<(u32, u32)> { match self { - ReplicationWal::Bottomless(inner) => inner.checkpoint(db, mode, busy_handler, sync_flags, buf), - ReplicationWal::Logger(inner) => inner.checkpoint(db, mode, busy_handler, sync_flags, buf), + ReplicationWal::Bottomless(inner) => { + inner.checkpoint(db, mode, busy_handler, sync_flags, buf) + } + ReplicationWal::Logger(inner) => { + inner.checkpoint(db, mode, busy_handler, sync_flags, buf) + } } } - fn exclusive_mode(&mut self,op:c_int) -> Result<()> { + fn exclusive_mode(&mut self, op: c_int) -> Result<()> { match self { ReplicationWal::Bottomless(inner) => inner.exclusive_mode(op), ReplicationWal::Logger(inner) => inner.exclusive_mode(op), @@ -195,7 +222,7 @@ impl Wal for ReplicationWal { } } - fn set_db(&mut self,db: *mut sqlite3) { + fn set_db(&mut self, db: &mut Sqlite3Db) { match self { ReplicationWal::Bottomless(inner) => inner.set_db(db), ReplicationWal::Logger(inner) => inner.set_db(db), diff --git a/libsql-server/src/replication/primary/logger.rs b/libsql-server/src/replication/primary/logger.rs index f581fe0db3..a6b94033cf 100644 --- a/libsql-server/src/replication/primary/logger.rs +++ b/libsql-server/src/replication/primary/logger.rs @@ -750,8 +750,8 @@ mod test { use super::*; use crate::connection::libsql::open_conn; - use crate::DEFAULT_AUTO_CHECKPOINT; use crate::replication::primary::replication_logger_wal::CreateReplicationLoggerWal; + use crate::DEFAULT_AUTO_CHECKPOINT; #[tokio::test] async fn write_and_read_from_frame_log() { diff --git a/libsql-server/src/replication/primary/replication_logger_wal.rs b/libsql-server/src/replication/primary/replication_logger_wal.rs index 02211e5607..3cfe4415ad 100644 --- a/libsql-server/src/replication/primary/replication_logger_wal.rs +++ b/libsql-server/src/replication/primary/replication_logger_wal.rs @@ -1,11 +1,11 @@ -use std::ffi::c_int; -use std::ffi::c_void; +use std::ffi::{c_int, CStr}; use std::sync::Arc; use bytes::Bytes; -use rusqlite::ffi::{sqlite3, PgHdr, SQLITE_IOERR}; -use libsql_sys::ffi::PageHdrIter; +use libsql_sys::wal::Vfs; use libsql_sys::wal::{BusyHandler, CreateSqlite3Wal, CreateWal, Result, Sqlite3Wal}; +use libsql_sys::wal::{PageHeaders, Sqlite3Db, Sqlite3File, UndoHandler}; +use rusqlite::ffi::SQLITE_IOERR; use crate::replication::ReplicationLogger; @@ -35,11 +35,11 @@ impl CreateWal for CreateReplicationLoggerWal { fn open( &self, - vfs: &mut libsql_sys::wal::Vfs, - file: *mut rusqlite::ffi::sqlite3_file, - no_shm_mode: std::ffi::c_int, + vfs: &mut Vfs, + file: &mut Sqlite3File, + no_shm_mode: c_int, max_log_size: i64, - db_path: &std::ffi::CStr, + db_path: &CStr, ) -> Result { let inner = self .sqlite_create_wal @@ -54,27 +54,19 @@ impl CreateWal for CreateReplicationLoggerWal { fn close( &self, wal: &mut Self::Wal, - db: *mut rusqlite::ffi::sqlite3, - sync_flags: std::ffi::c_int, + db: &mut Sqlite3Db, + sync_flags: c_int, scratch: &mut [u8], ) -> Result<()> { self.sqlite_create_wal .close(&mut wal.inner, db, sync_flags, scratch) } - fn destroy_log( - &self, - vfs: &mut libsql_sys::wal::Vfs, - db_path: &std::ffi::CStr, - ) -> Result<()> { + fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()> { self.sqlite_create_wal.destroy_log(vfs, db_path) } - fn log_exists( - &self, - vfs: &mut libsql_sys::wal::Vfs, - db_path: &std::ffi::CStr, - ) -> Result { + fn log_exists(&self, vfs: &mut Vfs, db_path: &CStr) -> Result { self.sqlite_create_wal.log_exists(vfs, db_path) } @@ -163,13 +155,9 @@ impl libsql_sys::wal::Wal for ReplicationLoggerWal { self.inner.end_write_txn() } - fn undo( - &mut self, - cb: Option i32>, - cb_ctx: *mut c_void, - ) -> Result<()> { + fn undo(&mut self, undo_handler: Option<&mut U>) -> Result<()> { self.rollback(); - self.inner.undo(cb, cb_ctx) + self.inner.undo(undo_handler) } fn savepoint(&mut self, rollback_data: &mut [u32]) { @@ -183,13 +171,14 @@ impl libsql_sys::wal::Wal for ReplicationLoggerWal { fn insert_frames( &mut self, page_size: c_int, - page_headers: *mut PgHdr, + page_headers: &mut PageHeaders, size_after: u32, is_commit: bool, sync_flags: c_int, ) -> Result<()> { assert_eq!(page_size, 4096); - for (page_no, data) in PageHdrIter::new(page_headers, page_size as _) { + let iter = unsafe { page_headers.iter() }; + for (page_no, data) in iter { self.write_frame(page_no, data); } if let Err(e) = self.flush(size_after) { @@ -226,7 +215,7 @@ impl libsql_sys::wal::Wal for ReplicationLoggerWal { fn checkpoint( &mut self, - db: *mut sqlite3, + db: &mut Sqlite3Db, mode: libsql_sys::wal::CheckpointMode, busy_handler: Option<&mut B>, sync_flags: u32, @@ -245,7 +234,7 @@ impl libsql_sys::wal::Wal for ReplicationLoggerWal { self.inner.uses_heap_memory() } - fn set_db(&mut self, db: *mut sqlite3) { + fn set_db(&mut self, db: &mut Sqlite3Db) { self.inner.set_db(db) } diff --git a/libsql-sqlite3/src/pager.c b/libsql-sqlite3/src/pager.c index aa7991d310..100c2d0113 100644 --- a/libsql-sqlite3/src/pager.c +++ b/libsql-sqlite3/src/pager.c @@ -3304,7 +3304,6 @@ static int pagerOpenWalIfPresent(Pager *pPager){ assert( pPager->eState==PAGER_OPEN ); assert( pPager->eLock>=SHARED_LOCK ); - printf("hello\n"); if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ rc =pPager->create_wal->ref.xLogExists(pPager->create_wal->ref.pData, pPager->pVfs, pPager->zFilename, &isWal); diff --git a/libsql-sys-tmp/Cargo.toml b/libsql-sys-tmp/Cargo.toml deleted file mode 100644 index 76d00d4fad..0000000000 --- a/libsql-sys-tmp/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "sqld-libsql-bindings" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1.0.66" -rusqlite = { workspace = true, features = ["trace"] } -tracing = "0.1.37" -once_cell = "1.17.1" -enum_dispatch = "0.3.12" - -[features] -unix-excl-vfs = [] diff --git a/libsql-sys-tmp/src/ffi/mod.rs b/libsql-sys-tmp/src/ffi/mod.rs deleted file mode 100644 index 1e8985cdf1..0000000000 --- a/libsql-sys-tmp/src/ffi/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![allow(dead_code)] - -pub mod types; - -pub use rusqlite::ffi::{ - libsql_wal_methods, sqlite3, sqlite3_file, sqlite3_hard_heap_limit64, sqlite3_io_methods, - sqlite3_soft_heap_limit64, sqlite3_vfs, WalIndexHdr, SQLITE_CANTOPEN, SQLITE_CHECKPOINT_FULL, - SQLITE_CHECKPOINT_TRUNCATE, SQLITE_IOERR_WRITE, SQLITE_OK, -}; - -pub use rusqlite::ffi::*; - -pub struct PageHdrIter { - current_ptr: *const PgHdr, - page_size: usize, -} - -impl PageHdrIter { - pub fn new(current_ptr: *const PgHdr, page_size: usize) -> Self { - Self { - current_ptr, - page_size, - } - } -} - -impl std::iter::Iterator for PageHdrIter { - type Item = (u32, &'static [u8]); - - fn next(&mut self) -> Option { - if self.current_ptr.is_null() { - return None; - } - let current_hdr: &PgHdr = unsafe { &*self.current_ptr }; - let raw_data = - unsafe { std::slice::from_raw_parts(current_hdr.pData as *const u8, self.page_size) }; - let item = Some((current_hdr.pgno, raw_data)); - self.current_ptr = current_hdr.pDirty; - item - } -} diff --git a/libsql-sys-tmp/src/ffi/types.rs b/libsql-sys-tmp/src/ffi/types.rs deleted file mode 100644 index c37577456e..0000000000 --- a/libsql-sys-tmp/src/ffi/types.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Typedefs for virtual function signatures. -use std::ffi::{c_char, c_int, c_uint, c_void}; - -use super::{libsql_wal_methods, sqlite3_file, sqlite3_vfs, PgHdr, Wal}; -use rusqlite::ffi::sqlite3; - -// WAL methods -pub type XWalLimitFn = extern "C" fn(wal: *mut Wal, limit: i64); -pub type XWalBeginReadTransactionFn = extern "C" fn(wal: *mut Wal, changed: *mut c_int) -> c_int; -pub type XWalEndReadTransaction = extern "C" fn(wal: *mut Wal); -pub type XWalFindFrameFn = extern "C" fn(wal: *mut Wal, pgno: u32, frame: *mut u32) -> c_int; -pub type XWalReadFrameFn = - extern "C" fn(wal: *mut Wal, frame: u32, n_out: c_int, p_out: *mut u8) -> c_int; -pub type XWalDbsizeFn = extern "C" fn(wal: *mut Wal) -> u32; -pub type XWalBeginWriteTransactionFn = extern "C" fn(wal: *mut Wal) -> c_int; -pub type XWalEndWriteTransactionFn = extern "C" fn(wal: *mut Wal) -> c_int; -pub type XWalSavepointFn = extern "C" fn(wal: *mut Wal, wal_data: *mut u32); -pub type XWalSavePointUndoFn = unsafe extern "C" fn(wal: *mut Wal, wal_data: *mut u32) -> c_int; -pub type XWalCheckpointFn = unsafe extern "C" fn( - wal: *mut Wal, - db: *mut rusqlite::ffi::sqlite3, - emode: c_int, - busy_handler: Option c_int>, - busy_arg: *mut c_void, - sync_flags: c_int, - n_buf: c_int, - z_buf: *mut u8, - frames_in_wal: *mut c_int, - backfilled_frames: *mut c_int, -) -> c_int; -pub type XWalCallbackFn = extern "C" fn(wal: *mut Wal) -> c_int; -pub type XWalExclusiveModeFn = extern "C" fn(wal: *mut Wal, op: c_int) -> c_int; -pub type XWalHeapMemoryFn = extern "C" fn(wal: *mut Wal) -> c_int; -pub type XWalFileFn = extern "C" fn(wal: *mut Wal) -> *mut sqlite3_file; -pub type XWalDbFn = extern "C" fn(wal: *mut Wal, db: *mut rusqlite::ffi::sqlite3); -pub type XWalPathNameLenFn = extern "C" fn(orig_len: c_int) -> c_int; -pub type XWalGetPathNameFn = extern "C" fn(buf: *mut c_char, orig: *const c_char, orig_len: c_int); -pub type XWalPreMainDbOpen = - extern "C" fn(methods: *mut libsql_wal_methods, path: *const c_char) -> c_int; -pub type XWalOpenFn = extern "C" fn( - vfs: *mut sqlite3_vfs, - file: *mut sqlite3_file, - wal_name: *const c_char, - no_shm_mode: c_int, - max_size: i64, - methods: *mut libsql_wal_methods, - wal: *mut *mut Wal, -) -> c_int; -pub type XWalCloseFn = extern "C" fn( - wal: *mut Wal, - db: *mut sqlite3, - sync_flags: c_int, - n_buf: c_int, - z_buf: *mut u8, -) -> c_int; -pub type XWalFrameFn = unsafe extern "C" fn( - wal: *mut Wal, - page_size: c_int, - page_headers: *mut PgHdr, - size_after: u32, - is_commit: c_int, - sync_flags: c_int, -) -> c_int; -pub type XWalUndoFn = unsafe extern "C" fn( - wal: *mut Wal, - func: Option c_int>, - ctx: *mut c_void, -) -> c_int; - -// io methods -pub type XAccessFn = unsafe extern "C" fn( - vfs: *mut sqlite3_vfs, - name: *const c_char, - flags: c_int, - res: *mut c_int, -) -> c_int; -pub type XDeleteFn = - unsafe extern "C" fn(vfs: *mut sqlite3_vfs, name: *const c_char, sync_dir: c_int) -> c_int; -pub type XFullPathNameFn = unsafe extern "C" fn( - vfs: *mut sqlite3_vfs, - name: *const c_char, - n: c_int, - out: *mut c_char, -) -> c_int; -pub type XOpenFn = unsafe extern "C" fn( - vfs: *mut sqlite3_vfs, - name: *const c_char, - file: *mut sqlite3_file, - flags: c_int, - out_flags: *mut c_int, -) -> c_int; -pub type XDlOpenFn = - unsafe extern "C" fn(vfs: *mut sqlite3_vfs, name: *const c_char) -> *const c_void; -pub type XDlErrorFn = unsafe extern "C" fn(vfs: *mut sqlite3_vfs, n: c_int, msg: *mut c_char); -pub type XDlSymFn = unsafe extern "C" fn( - vfs: *mut sqlite3_vfs, - arg: *mut c_void, - symbol: *const c_char, -) -> unsafe extern "C" fn(); -pub type XDlCloseFn = unsafe extern "C" fn(vfs: *mut sqlite3_vfs, arg: *mut c_void); -pub type XRandomnessFn = - unsafe extern "C" fn(vfs: *mut sqlite3_vfs, n_bytes: c_int, out: *mut c_char) -> c_int; -pub type XSleepFn = unsafe extern "C" fn(vfs: *mut sqlite3_vfs, ms: c_int) -> c_int; -pub type XCurrentTimeFn = unsafe extern "C" fn(vfs: *mut sqlite3_vfs, time: *mut f64) -> c_int; -pub type XGetLastErrorFn = - unsafe extern "C" fn(vfs: *mut sqlite3_vfs, n: c_int, buf: *mut c_char) -> c_int; -pub type XCurrentTimeInt64 = unsafe extern "C" fn(vfs: *mut sqlite3_vfs, time: *mut i64) -> c_int; -pub type XCloseFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file) -> c_int; -pub type XReadFn = unsafe extern "C" fn( - file_ptr: *mut sqlite3_file, - buf: *mut c_char, - n: c_int, - off: i64, -) -> c_int; -pub type XWriteFn = unsafe extern "C" fn( - file_ptr: *mut sqlite3_file, - buf: *const c_char, - n: c_int, - off: i64, -) -> c_int; -pub type XTruncateFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file, size: i64) -> c_int; -pub type XSyncFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file, flags: c_int) -> c_int; -pub type XFileSizeFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file, size: *mut i64) -> c_int; -pub type XLockFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file, lock: c_int) -> c_int; -pub type XUnlockFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file, lock: c_int) -> c_int; -pub type XCheckReservedLockFn = - unsafe extern "C" fn(file_ptr: *mut sqlite3_file, res: *mut c_int) -> c_int; -pub type XFileControlFn = - unsafe extern "C" fn(file_ptr: *mut sqlite3_file, op: c_int, arg: *mut c_void) -> c_int; -pub type XSectorSizeFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file) -> c_int; -pub type XDeviceCharacteristicsFn = unsafe extern "C" fn(file_ptr: *mut sqlite3_file) -> c_int; diff --git a/libsql-sys-tmp/src/lib.rs b/libsql-sys-tmp/src/lib.rs deleted file mode 100644 index 01edf7ff14..0000000000 --- a/libsql-sys-tmp/src/lib.rs +++ /dev/null @@ -1,87 +0,0 @@ -//#![allow(improper_ctypes)] - -// pub mod ffi; -// pub mod wal; -// -// use std::marker::PhantomData; -// use std::ops::Deref; -// -// pub use once_cell::sync::Lazy; -// pub use rusqlite; -// use rusqlite::ffi::sqlite3; -// -// use self::wal::ffi::make_create_wal; -// use self::wal::{CreateWal, Wal}; -// -// #[derive(Debug)] -// pub struct Connection { -// conn: rusqlite::Connection, -// _pth: PhantomData, -// } -// -// impl Deref for Connection { -// type Target = rusqlite::Connection; -// -// fn deref(&self) -> &Self::Target { -// &self.conn -// } -// } -// -// // impl Connection { -// // /// returns a dummy, in-memory connection. For testing purposes only -// // pub fn test() -> Self { -// // let conn = rusqlite::Connection::open_in_memory().unwrap(); -// // Self { -// // conn, -// // _ctx: Box::new(()), -// // } -// // } -// // } -// -// impl Connection { -// /// Opens a database with the regular wal methods in the directory pointed to by path -// pub fn open( -// path: impl AsRef, -// flags: rusqlite::OpenFlags, -// create_wal: T, -// auto_checkpoint: u32, -// ) -> Result -// where -// T: CreateWal, -// { -// let path = path.as_ref().join("data"); -// tracing::trace!( -// "Opening a connection with regular WAL at {}", -// path.display() -// ); -// -// let conn_str = format!("file:{}?_journal_mode=WAL", path.display()); -// let conn = rusqlite::Connection::open_with_flags_and_wal( -// conn_str, -// flags, -// make_create_wal(create_wal), -// )?; -// unsafe { -// let rc = rusqlite::ffi::sqlite3_wal_autocheckpoint(conn.handle(), auto_checkpoint as _); -// if rc != 0 { -// return Err(rusqlite::Error::SqliteFailure( -// rusqlite::ffi::Error::new(rc), -// Some("failed to set auto_checkpoint".into()), -// )); -// } -// } -// -// Ok(Connection { -// conn, -// _pth: PhantomData, -// }) -// } -// -// /// Returns the raw sqlite handle -// /// -// /// # Safety -// /// The caller is responsible for the returned pointer. -// pub unsafe fn handle(&self) -> *mut sqlite3 { -// self.conn.handle() -// } -// } diff --git a/libsql-sys-tmp/src/wal_hook.rs b/libsql-sys-tmp/src/wal_hook.rs deleted file mode 100644 index 0b2f0bd43c..0000000000 --- a/libsql-sys-tmp/src/wal_hook.rs +++ /dev/null @@ -1,478 +0,0 @@ -#![allow(clippy::not_unsafe_ptr_arg_deref)] -use std::{ - ffi::{c_char, c_int, c_void, CStr}, - marker::PhantomData, - panic::{catch_unwind, resume_unwind}, path::Path, -}; - -use crate::ffi::{libsql_wal_methods, sqlite3, sqlite3_file, sqlite3_vfs, types::*, PgHdr, Wal}; -use crate::get_orig_wal_methods; - -/// This macro handles the registering of a WalHook with the process's sqlite. It first instantiate a `WalMethodsHook` -/// to a stable location in memory, and then call `libsql_wal_methods_register` with the WAL methods. -/// -/// The methods are never unregistered, since they're expected to live for the entirety of the program. -#[macro_export] -macro_rules! init_static_wal_method { - ($name:ident, $ty:path) => { - pub static $name: $crate::Lazy<&'static $crate::WalMethodsHook<$ty>> = - $crate::Lazy::new(|| { - // we need a 'static address before we can register the methods. - static METHODS: $crate::Lazy<$crate::WalMethodsHook<$ty>> = - $crate::Lazy::new(|| $crate::WalMethodsHook::<$ty>::new()); - - let ret = unsafe { - $crate::ffi::libsql_wal_methods_register(METHODS.as_wal_methods_ptr() as *mut _) - }; - - assert!( - ret == 0, - "failed to register wal methods for {}", - stringify!($ty) - ); - - &METHODS - }); - }; -} - -/// The `WalHook` trait allows to intercept WAL method call. -/// -/// All the methods in this trait have the following format: - arguments to the WAL method - -/// function pointer to the wrapped WAL method -/// -/// The default implementations for this trait methods is to transparently call the wrapped methods -/// with the passed arguments -/// -/// # Safety -/// The implementer is responsible for calling the orig method with valid arguments. -pub unsafe trait WalHook { - type Context; - - fn name() -> &'static CStr; - /// Intercept `xFrame` call. `orig` is the function pointer to the underlying wal method. - /// The default implementation of this trait simply calls orig with the other passed arguments. - #[allow(clippy::too_many_arguments)] - fn on_frames( - wal: &mut Wal, - page_size: c_int, - page_headers: *mut PgHdr, - size_after: u32, - is_commit: c_int, - sync_flags: c_int, - orig: XWalFrameFn, - ) -> c_int { - unsafe { - (orig)( - wal, - page_size, - page_headers, - size_after, - is_commit, - sync_flags, - ) - } - } - - /// Intercept `xUndo` call. `orig` is the function pointer to the underlying wal method. - /// The default implementation of this trait simply calls orig with the other passed arguments. - fn on_undo( - wal: &mut Wal, - func: Option i32>, - undo_ctx: *mut c_void, - orig: XWalUndoFn, - ) -> i32 { - unsafe { orig(wal, func, undo_ctx) } - } - - fn wal_extract_ctx(wal: &mut Wal) -> &mut Self::Context { - let ctx_ptr = wal.pMethodsData as *mut Self::Context; - assert!(!ctx_ptr.is_null(), "missing wal context"); - unsafe { &mut *ctx_ptr } - } - - fn on_savepoint_undo(wal: &mut Wal, wal_data: *mut u32, orig: XWalSavePointUndoFn) -> i32 { - unsafe { orig(wal, wal_data) } - } - - #[allow(clippy::too_many_arguments)] - fn on_checkpoint( - wal: &mut Wal, - db: *mut sqlite3, - emode: i32, - busy_handler: Option i32>, - busy_arg: *mut c_void, - sync_flags: i32, - n_buf: i32, - z_buf: *mut u8, - frames_in_wal: *mut i32, - backfilled_frames: *mut i32, - orig: XWalCheckpointFn, - ) -> i32 { - unsafe { - orig( - wal, - db, - emode, - busy_handler, - busy_arg, - sync_flags, - n_buf, - z_buf, - frames_in_wal, - backfilled_frames, - ) - } - } -} - -init_static_wal_method!(TRANSPARENT_METHODS, TransparentMethods); - -/// Wal implemementation that just proxies calls to the wrapped WAL methods implementation -#[derive(Debug)] -pub enum TransparentMethods {} - -unsafe impl WalHook for TransparentMethods { - type Context = (); - - fn name() -> &'static CStr { - CStr::from_bytes_with_nul(b"transparent\0").unwrap() - } -} - -impl Default for WalMethodsHook { - fn default() -> Self { - Self::new() - } -} - -impl WalMethodsHook { - pub fn new() -> Self { - let default_methods = get_orig_wal_methods().expect("failed to get original WAL methods"); - - WalMethodsHook { - methods: libsql_wal_methods { - iVersion: 1, - xOpen: Some(xOpen::), - xClose: Some(xClose::), - xLimit: Some(xLimit::), - xBeginReadTransaction: Some(xBeginReadTransaction::), - xEndReadTransaction: Some(xEndReadTransaction::), - xFindFrame: Some(xFindFrame::), - xReadFrame: Some(xReadFrame::), - xDbsize: Some(xDbsize::), - xBeginWriteTransaction: Some(xBeginWriteTransaction::), - xEndWriteTransaction: Some(xEndWriteTransaction::), - xUndo: Some(xUndo::), - xSavepoint: Some(xSavepoint::), - xSavepointUndo: Some(xSavepointUndo::), - xFrames: Some(xFrames::), - xCheckpoint: Some(xCheckpoint::), - xCallback: Some(xCallback::), - xExclusiveMode: Some(xExclusiveMode::), - xHeapMemory: Some(xHeapMemory::), - xSnapshotGet: None, - xSnapshotOpen: None, - xSnapshotRecover: None, - xSnapshotCheck: None, - xSnapshotUnlock: None, - xFramesize: None, - xFile: Some(xFile::), - xWriteLock: None, - xDb: Some(xDb::), - xPathnameLen: Some(xPathnameLen::), - xGetWalPathname: Some(xGetPathname::), - xPreMainDbOpen: Some(xPreMainDbOpen::), - zName: T::name().as_ptr(), - bUsesShm: 0, - pNext: std::ptr::null_mut(), - }, - underlying_methods: default_methods, - _pth: PhantomData, - } - } - - pub fn as_wal_methods_ptr(&self) -> *const libsql_wal_methods { - self as *const _ as *mut _ - } -} - -macro_rules! catch_panic { - ($name:literal, { $($body:tt)* }) => { - { - let ret = catch_unwind(move || { - $($body)* - }); - - match ret { - Ok(x) => x, - Err(e) => { - let error = if let Some(s) = e.downcast_ref::() { - s.as_str() - } else if let Some(s) = e.downcast_ref::<&str>() { - s - } else { - "unknown" - }; - let bt = std::backtrace::Backtrace::force_capture(); - tracing::error!("panic in call to {}: {error}:\n{bt}", $name); - resume_unwind(e) - } - } - } - }; -} - -#[allow(non_snake_case)] -pub extern "C" fn xOpen( - vfs: *mut sqlite3_vfs, - db_file: *mut sqlite3_file, - wal_name: *const c_char, - no_shm_mode: i32, - max_size: i64, - methods: *mut libsql_wal_methods, - wal: *mut *mut Wal, -) -> i32 { - tracing::debug!("Opening WAL {}", unsafe { - std::ffi::CStr::from_ptr(wal_name).to_str().unwrap() - }); - let ref_methods = unsafe { &*(methods as *mut WalMethodsHook) }; - let origxOpen = unsafe { (*ref_methods.underlying_methods).xOpen.unwrap() }; - unsafe { (origxOpen)(vfs, db_file, wal_name, no_shm_mode, max_size, methods, wal) } -} - -fn get_orig_methods(wal: &mut Wal) -> &libsql_wal_methods { - let methods = get_methods::(wal); - assert!(!methods.underlying_methods.is_null()); - unsafe { &*methods.underlying_methods } -} - -fn get_methods(wal: &mut Wal) -> &mut WalMethodsHook { - assert!(!wal.pMethods.is_null()); - unsafe { &mut *(wal.pMethods as *mut _ as *mut WalMethodsHook) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xClose( - wal: *mut Wal, - db: *mut rusqlite::ffi::sqlite3, - sync_flags: i32, - n_buf: c_int, - z_buf: *mut u8, -) -> c_int { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xClose.unwrap())(wal, db, sync_flags, n_buf, z_buf) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xLimit(wal: *mut Wal, limit: i64) { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xLimit.unwrap())(wal, limit) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xBeginReadTransaction(wal: *mut Wal, changed: *mut i32) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xBeginReadTransaction.unwrap())(wal, changed) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xEndReadTransaction(wal: *mut Wal) { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xEndReadTransaction.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xFindFrame(wal: *mut Wal, pgno: u32, frame: *mut u32) -> c_int { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xFindFrame.unwrap())(wal, pgno, frame) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xReadFrame( - wal: *mut Wal, - frame: u32, - n_out: c_int, - p_out: *mut u8, -) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xReadFrame.unwrap())(wal, frame, n_out, p_out) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xDbsize(wal: *mut Wal) -> u32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xDbsize.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xBeginWriteTransaction(wal: *mut Wal) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xBeginWriteTransaction.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xEndWriteTransaction(wal: *mut Wal) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xEndWriteTransaction.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xUndo( - wal: *mut Wal, - func: Option i32>, - undo_ctx: *mut c_void, -) -> i32 { - catch_panic!("xUndo", { - assert!(!wal.is_null()); - let wal = unsafe { &mut *wal }; - let orig_methods = get_orig_methods::(wal); - let orig_xundo = orig_methods.xUndo.unwrap(); - T::on_undo(wal, func, undo_ctx, orig_xundo) - }) -} - -#[allow(non_snake_case)] -pub extern "C" fn xSavepoint(wal: *mut Wal, wal_data: *mut u32) { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xSavepoint.unwrap())(wal, wal_data) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xSavepointUndo(wal: *mut Wal, wal_data: *mut u32) -> i32 { - catch_panic!("xSavepointUndo", { - let wal = unsafe { &mut *wal }; - let orig_methods = get_orig_methods::(wal); - let orig_xsavepointundo = orig_methods.xSavepointUndo.unwrap(); - T::on_savepoint_undo(wal, wal_data, orig_xsavepointundo) - }) -} - -#[allow(non_snake_case)] -pub extern "C" fn xFrames( - wal: *mut Wal, - page_size: c_int, - page_headers: *mut PgHdr, - size_after: u32, - is_commit: c_int, - sync_flags: c_int, -) -> c_int { - catch_panic!("xFrames", { - assert!(!wal.is_null()); - let wal = unsafe { &mut *wal }; - let orig_methods = get_orig_methods::(wal); - let orig_xframe = orig_methods.xFrames.unwrap(); - - T::on_frames( - wal, - page_size, - page_headers, - size_after, - is_commit, - sync_flags, - orig_xframe, - ) - }) -} - -#[tracing::instrument(skip(wal, db))] -#[allow(non_snake_case)] -pub extern "C" fn xCheckpoint( - wal: *mut Wal, - db: *mut rusqlite::ffi::sqlite3, - emode: c_int, - busy_handler: Option c_int>, - busy_arg: *mut c_void, - sync_flags: c_int, - n_buf: c_int, - z_buf: *mut u8, - frames_in_wal: *mut c_int, - backfilled_frames: *mut c_int, -) -> i32 { - catch_panic!("xCheckpoint", { - let wal = unsafe { &mut *wal }; - let orig_methods = get_orig_methods::(wal); - let orig_xcheckpoint = orig_methods.xCheckpoint.unwrap(); - T::on_checkpoint( - wal, - db, - emode, - busy_handler, - busy_arg, - sync_flags, - n_buf, - z_buf, - frames_in_wal, - backfilled_frames, - orig_xcheckpoint, - ) - }) -} - -#[allow(non_snake_case)] -pub extern "C" fn xCallback(wal: *mut Wal) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xCallback.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xExclusiveMode(wal: *mut Wal, op: c_int) -> c_int { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xExclusiveMode.unwrap())(wal, op) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xHeapMemory(wal: *mut Wal) -> i32 { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xHeapMemory.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xFile(wal: *mut Wal) -> *mut sqlite3_file { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xFile.unwrap())(wal) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xDb(wal: *mut Wal, db: *mut rusqlite::ffi::sqlite3) { - let orig_methods = unsafe { get_orig_methods::(&mut *wal) }; - unsafe { (orig_methods.xDb.unwrap())(wal, db) } -} - -#[allow(non_snake_case)] -pub extern "C" fn xPathnameLen(orig_len: i32) -> i32 { - orig_len + 4 -} - -#[allow(non_snake_case)] -pub extern "C" fn xGetPathname(buf: *mut c_char, orig: *const c_char, orig_len: c_int) { - unsafe { std::ptr::copy(orig, buf, orig_len as usize) } - unsafe { - std::ptr::copy( - "-wal".as_ptr(), - (buf as *mut u8).offset(orig_len as isize), - 4, - ) - } -} - -#[allow(non_snake_case)] -pub extern "C" fn xPreMainDbOpen( - methods: *mut libsql_wal_methods, - path: *const c_char, -) -> i32 { - let orig_methods = unsafe { &*(*(methods as *mut WalMethodsHook)).underlying_methods }; - unsafe { (orig_methods.xPreMainDbOpen.unwrap())(methods, path) } -} - -unsafe impl Send for WalMethodsHook {} -unsafe impl Sync for WalMethodsHook {} - -#[repr(C)] -#[allow(non_snake_case)] -pub struct WalMethodsHook { - pub methods: libsql_wal_methods, - // user data - underlying_methods: *mut libsql_wal_methods, - _pth: PhantomData, -} diff --git a/libsql-sys/src/connection.rs b/libsql-sys/src/connection.rs index 2d788a4645..2633bef82e 100644 --- a/libsql-sys/src/connection.rs +++ b/libsql-sys/src/connection.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use std::path::Path; -use crate::wal::{Wal, CreateWal, ffi::make_create_wal, Sqlite3Wal}; +use crate::wal::{ffi::make_create_wal, CreateWal, Wal}; #[cfg(not(feature = "rusqlite"))] type RawConnection = *mut crate::ffi::sqlite3; @@ -18,7 +18,6 @@ type Error = rusqlite::Error; #[cfg(not(feature = "rusqlite"))] type Error = crate::Error; - #[derive(Debug)] pub struct Connection { conn: RawConnection, @@ -41,13 +40,14 @@ impl std::ops::DerefMut for Connection { } } -impl Connection { +#[cfg(feature = "rusqlite")] +impl Connection { /// returns a dummy, in-memory connection. For testing purposes only pub fn test() -> Self { let conn = rusqlite::Connection::open_in_memory().unwrap(); Self { conn, - _pth: PhantomData + _pth: PhantomData, } } } @@ -63,52 +63,50 @@ impl Connection { where T: CreateWal, { - let path = path.as_ref(); tracing::trace!( "Opening a connection with regular WAL at {}", - path.display() + path.as_ref().display() ); - let conn_str = format!("file:{}?_journal_mode=WAL", path.display()); - #[cfg(feature = "rusqlite")] let conn = { - dbg!(); let conn = rusqlite::Connection::open_with_flags_and_wal( - conn_str, + path, flags, make_create_wal(create_wal), )?; - dbg!(); + conn.pragma_update(None, "journal_mode", "WAL")?; unsafe { - let rc = rusqlite::ffi::sqlite3_wal_autocheckpoint(conn.handle(), auto_checkpoint as _); + let rc = + rusqlite::ffi::sqlite3_wal_autocheckpoint(conn.handle(), auto_checkpoint as _); if rc != 0 { return Err(rusqlite::Error::SqliteFailure( - rusqlite::ffi::Error::new(rc), - Some("failed to set auto_checkpoint".into()), + rusqlite::ffi::Error::new(rc), + Some("failed to set auto_checkpoint".into()), )); } } - // unsafe { - // crate::ffi::sqlite3_busy_timeout(conn, 5000); - // } + conn.busy_timeout(std::time::Duration::from_secs(5000))?; + conn }; #[cfg(not(feature = "rusqlite"))] let conn = unsafe { - let filename = std::ffi::CString::new(conn_str).unwrap(); + use std::os::unix::ffi::OsStrExt; + let path = std::ffi::CString::new(path.as_ref().as_os_str().as_bytes()) + .map_err(|_| crate::error::Error::Bug("invalid database path"))?; let mut conn: *mut crate::ffi::sqlite3 = std::ptr::null_mut(); // We pass a pointer to the WAL methods data to the database connection. This means // that the reference must outlive the connection. This is guaranteed by the marker in // the returned connection. let mut rc = libsql_ffi::libsql_open( - filename.as_ptr(), + path.as_ptr(), &mut conn as *mut _, flags, std::ptr::null_mut(), - make_create_wal(create_wal) + make_create_wal(create_wal), ); if rc == 0 { diff --git a/libsql-sys/src/lib.rs b/libsql-sys/src/lib.rs index 641e2d6959..aae4dca2b9 100644 --- a/libsql-sys/src/lib.rs +++ b/libsql-sys/src/lib.rs @@ -1,7 +1,6 @@ #[allow(clippy::all)] #[allow(non_snake_case)] #[allow(non_camel_case_types)] - pub use libsql_ffi as ffi; #[cfg(feature = "api")] diff --git a/libsql-sys/src/wal/ffi.rs b/libsql-sys/src/wal/ffi.rs index db8ab4f21f..01b2dfe0a4 100644 --- a/libsql-sys/src/wal/ffi.rs +++ b/libsql-sys/src/wal/ffi.rs @@ -6,9 +6,9 @@ use libsql_ffi::{ SQLITE_CHECKPOINT_RESTART, SQLITE_CHECKPOINT_TRUNCATE, SQLITE_OK, WAL_SAVEPOINT_NDATA, }; -use crate::wal::{BusyHandler, CheckpointMode}; +use crate::wal::{BusyHandler, CheckpointMode, UndoHandler}; -use super::{CreateWal, Vfs, Wal}; +use super::{CreateWal, PageHeaders, Sqlite3Db, Sqlite3File, Vfs, Wal}; // Construct a libsql_wal instance from a pointer to a Wal. This pointer must be valid until a call // to CreateWal::close @@ -47,7 +47,6 @@ pub(crate) fn construct_libsql_wal(wal: *mut W) -> libsql_wal { } pub(crate) fn make_create_wal(create_wal: T) -> libsql_create_wal { - dbg!(); libsql_create_wal { bUsesShm: create_wal.use_shared_memory() as _, xOpen: Some(open::), @@ -73,8 +72,15 @@ pub unsafe extern "C" fn open( let this = &*(create_wal as *mut T); let mut vfs = Vfs { vfs }; let db_path = CStr::from_ptr(db_path); - - match this.open(&mut vfs, db_file, no_shm_mode as _, max_size as _, db_path) { + let mut file = Sqlite3File { inner: db_file }; + + match this.open( + &mut vfs, + &mut file, + no_shm_mode as _, + max_size as _, + db_path, + ) { Ok(wal) => { let wal = Box::into_raw(Box::new(wal)); *out_wal = construct_libsql_wal(wal); @@ -95,8 +101,9 @@ pub unsafe extern "C" fn close( let this = &*(create_wal as *mut T); let mut wal = Box::from_raw(wal as *mut T::Wal); let scratch = std::slice::from_raw_parts_mut(z_buf, n_buf as usize); + let mut db = Sqlite3Db { inner: db }; - match this.close(&mut wal, db, sync_flags, scratch) { + match this.close(&mut wal, &mut db, sync_flags, scratch) { Ok(_) => SQLITE_OK, Err(code) => code.extended_code, } @@ -219,7 +226,25 @@ pub unsafe extern "C" fn undo( undo_ctx: *mut c_void, ) -> i32 { let this = &mut (*(wal as *mut T)); - match this.undo(func, undo_ctx) { + struct SqliteUndoHandler { + data: *mut c_void, + f: unsafe extern "C" fn(busy_param: *mut c_void, page_no: u32) -> c_int, + } + + impl UndoHandler for SqliteUndoHandler { + fn handle_undo(&mut self, page_no: u32) -> Result<(), libsql_ffi::Error> { + let rc = unsafe { (self.f)(self.data, page_no) }; + if rc != 0 { + Err(libsql_ffi::Error::new(rc)) + } else { + Ok(()) + } + } + } + + let mut undo_handler = func.map(|f| SqliteUndoHandler { data: undo_ctx, f }); + + match this.undo(undo_handler.as_mut()) { Ok(_) => SQLITE_OK, Err(code) => code.extended_code, } @@ -249,9 +274,12 @@ pub unsafe extern "C" fn frames( sync_flags: c_int, ) -> c_int { let this = &mut (*(wal as *mut T)); + let mut headers = PageHeaders { + inner: page_headers, + }; match this.insert_frames( page_size, - page_headers, + &mut headers, size_after, is_commit != 0, sync_flags, @@ -272,7 +300,7 @@ pub unsafe extern "C" fn checkpoint( n_buf: c_int, z_buf: *mut u8, frames_in_wal_out: *mut c_int, - backfilled_frames_out: *mut c_int, + checkpointed_frames_out: *mut c_int, ) -> i32 { let this = &mut (*(wal as *mut T)); struct SqliteBusyHandler { @@ -297,10 +325,15 @@ pub unsafe extern "C" fn checkpoint( _ => panic!("invalid checkpoint mode"), }; - match this.checkpoint(db, mode, busy_handler.as_mut(), sync_flags as _, buf) { + let mut db = Sqlite3Db { inner: db }; + match this.checkpoint(&mut db, mode, busy_handler.as_mut(), sync_flags as _, buf) { Ok((frames_in_wal, backfilled_frames)) => { - *frames_in_wal_out = frames_in_wal as _; - *backfilled_frames_out = backfilled_frames as _; + if !frames_in_wal_out.is_null() { + *frames_in_wal_out = frames_in_wal as _; + } + if !checkpointed_frames_out.is_null() { + *checkpointed_frames_out = backfilled_frames as _; + } SQLITE_OK } Err(code) => code.extended_code, @@ -327,5 +360,6 @@ pub unsafe extern "C" fn heap_memory(wal: *mut wal_impl) -> c_int { pub unsafe extern "C" fn db(wal: *mut wal_impl, db: *mut libsql_ffi::sqlite3) { let this = &mut (*(wal as *mut T)); - this.set_db(db); + let mut db = Sqlite3Db { inner: db }; + this.set_db(&mut db); } diff --git a/libsql-sys/src/wal/mod.rs b/libsql-sys/src/wal/mod.rs index 8e5ea639be..c2b765fd17 100644 --- a/libsql-sys/src/wal/mod.rs +++ b/libsql-sys/src/wal/mod.rs @@ -1,7 +1,7 @@ -use std::ffi::{c_int, c_void, CStr}; +use std::ffi::{c_int, CStr}; -use crate::ffi::*; pub use crate::ffi::Error; +use crate::ffi::*; pub use sqlite3_wal::{CreateSqlite3Wal, Sqlite3Wal}; @@ -18,7 +18,7 @@ pub trait CreateWal { fn open( &self, vfs: &mut Vfs, - file: *mut sqlite3_file, + file: &mut Sqlite3File, no_shm_mode: c_int, max_log_size: i64, db_path: &CStr, @@ -26,7 +26,7 @@ pub trait CreateWal { fn close( &self, wal: &mut Self::Wal, - db: *mut sqlite3, + db: &mut Sqlite3Db, sync_flags: c_int, scratch: &mut [u8], ) -> Result<()>; @@ -39,68 +39,71 @@ pub trait CreateWal { Self: Sized; } -// impl CreateWal for Arc { -// type Wal = T::Wal; -// -// fn use_shared_memory(&self) -> bool { -// self.as_ref().use_shared_memory() -// } -// -// fn open( -// &self, -// vfs: &mut Vfs, -// file: *mut sqlite3_file, -// no_shm_mode: c_int, -// max_log_size: i64, -// db_path: &CStr, -// ) -> Result { -// self.as_ref() -// .open(vfs, file, no_shm_mode, max_log_size, db_path) -// } -// -// fn close( -// &self, -// wal: &mut Self::Wal, -// db: *mut sqlite3, -// sync_flags: c_int, -// scratch: &mut [u8], -// ) -> Result<()> { -// self.as_ref().close(wal, db, sync_flags, scratch) -// } -// -// fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()> { -// self.as_ref().destroy_log(vfs, db_path) -// } -// -// fn log_exists(&self, vfs: &mut Vfs, db_path: &CStr) -> Result { -// self.as_ref().log_exists(vfs, db_path) -// } -// -// fn destroy(self) -// where -// Self: Sized, -// { -// if let Ok(inner) = Arc::try_unwrap(self) { -// inner.destroy() -// } -// } -// } +/// Wrapper type around `*mut sqlite3`, to seal the pointer from extern usage. +pub struct Sqlite3Db { + inner: *mut sqlite3, +} -pub trait BusyHandler { - // Handle busy, and returns whether a retry should be performed - fn handle_busy(&mut self) -> bool; +impl Sqlite3Db { + pub(crate) fn as_ptr(&mut self) -> *mut sqlite3 { + self.inner + } } +/// Wrapper type around `*mut sqlite3_file`, to seal the pointer from extern usage. +pub struct Sqlite3File { + inner: *mut sqlite3_file, +} + +impl Sqlite3File { + pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_file { + self.inner + } +} + +/// Wrapper type around `*mut sqlite3_vfs`, to seal the pointer from extern usage. pub struct Vfs { vfs: *mut sqlite3_vfs, } impl Vfs { - pub unsafe fn as_mut_ptr(&mut self) -> *mut sqlite3_vfs { + pub(crate) fn as_ptr(&mut self) -> *mut sqlite3_vfs { self.vfs } } +pub struct PageHeaders { + inner: *mut libsql_pghdr, +} + +impl PageHeaders { + pub(crate) fn as_ptr(&mut self) -> *mut libsql_pghdr { + self.inner + } + + /// # Safety + /// caller must ensure the headers list validity. + pub unsafe fn from_raw(inner: *mut libsql_pghdr) -> Self { + Self { inner } + } + + /// # Safety + /// The caller must not modify the list, unless they really know what they are doing. + pub unsafe fn iter(&mut self) -> PageHdrIter { + // TODO: move LIBSQL_PAGE_SIZE + PageHdrIter::new(self.as_ptr(), 4096) + } +} + +pub trait BusyHandler { + // Handle busy, and returns whether a retry should be performed + fn handle_busy(&mut self) -> bool; +} + +pub trait UndoHandler { + fn handle_undo(&mut self, page_no: u32) -> Result<()>; +} + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] #[repr(i32)] pub enum CheckpointMode { @@ -127,11 +130,7 @@ pub trait Wal { fn begin_write_txn(&mut self) -> Result<()>; fn end_write_txn(&mut self) -> Result<()>; - fn undo( - &mut self, - cb: Option i32>, - cb_ctx: *mut c_void, - ) -> Result<()>; + fn undo(&mut self, handler: Option<&mut U>) -> Result<()>; fn savepoint(&mut self, rollback_data: &mut [u32]); fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> Result<()>; @@ -139,16 +138,16 @@ pub trait Wal { fn insert_frames( &mut self, page_size: c_int, - page_headers: *mut PgHdr, + page_headers: &mut PageHeaders, size_after: u32, is_commit: bool, sync_flags: c_int, ) -> Result<()>; - /// Returns the number of frames in the log and the number of backfilled frames in the WAL. + /// Returns the number of frames in the log and the number of checkpointed frames in the WAL. fn checkpoint( &mut self, - db: *mut sqlite3, + db: &mut Sqlite3Db, mode: CheckpointMode, busy_handler: Option<&mut B>, sync_flags: u32, @@ -158,7 +157,7 @@ pub trait Wal { fn exclusive_mode(&mut self, op: c_int) -> Result<()>; fn uses_heap_memory(&self) -> bool; - fn set_db(&mut self, db: *mut sqlite3); + fn set_db(&mut self, db: &mut Sqlite3Db); /// Return the value to pass to a sqlite3_wal_hook callback, the /// number of frames in the WAL at the point of the last commit since diff --git a/libsql-sys/src/wal/sqlite3_wal.rs b/libsql-sys/src/wal/sqlite3_wal.rs index 1947f4e9b6..e06383e82f 100644 --- a/libsql-sys/src/wal/sqlite3_wal.rs +++ b/libsql-sys/src/wal/sqlite3_wal.rs @@ -2,11 +2,14 @@ use std::ffi::{c_int, c_void, CStr}; use std::mem::MaybeUninit; use libsql_ffi::{ - libsql_create_wal, libsql_pghdr, libsql_wal, sqlite3, sqlite3_create_wal, sqlite3_file, - sqlite3_wal, WAL_SAVEPOINT_NDATA, Error, + libsql_create_wal, libsql_wal, sqlite3_create_wal, sqlite3_wal, Error, SQLITE_OK, + WAL_SAVEPOINT_NDATA, }; -use super::{BusyHandler, CheckpointMode, CreateWal, Result, Vfs, Wal}; +use super::{ + BusyHandler, CheckpointMode, CreateWal, PageHeaders, Result, Sqlite3Db, Sqlite3File, + UndoHandler, Vfs, Wal, +}; /// SQLite3 default create_wal implementation. #[derive(Clone, Copy)] @@ -26,6 +29,12 @@ impl CreateSqlite3Wal { } } +impl Default for CreateSqlite3Wal { + fn default() -> Self { + Self::new() + } +} + impl CreateWal for CreateSqlite3Wal { type Wal = Sqlite3Wal; @@ -36,7 +45,7 @@ impl CreateWal for CreateSqlite3Wal { fn open( &self, vfs: &mut Vfs, - file: *mut sqlite3_file, + file: &mut Sqlite3File, no_shm_mode: c_int, max_log_size: i64, db_path: &CStr, @@ -45,8 +54,8 @@ impl CreateWal for CreateSqlite3Wal { let rc = unsafe { (self.inner.xOpen.unwrap())( self.inner.pData, - vfs.as_mut_ptr(), - file, + vfs.as_ptr(), + file.as_ptr(), no_shm_mode, max_log_size, db_path.as_ptr(), @@ -66,7 +75,7 @@ impl CreateWal for CreateSqlite3Wal { fn close( &self, wal: &mut Self::Wal, - db: *mut sqlite3, + db: &mut Sqlite3Db, sync_flags: c_int, scratch: &mut [u8], ) -> Result<()> { @@ -74,7 +83,7 @@ impl CreateWal for CreateSqlite3Wal { (self.inner.xClose.unwrap())( self.inner.pData, wal.inner.pData, - db, + db.as_ptr(), sync_flags, scratch.len() as _, scratch.as_mut_ptr() as _, @@ -90,7 +99,7 @@ impl CreateWal for CreateSqlite3Wal { fn destroy_log(&self, vfs: &mut Vfs, db_path: &CStr) -> Result<()> { let rc = unsafe { - (self.inner.xLogDestroy.unwrap())(self.inner.pData, vfs.as_mut_ptr(), db_path.as_ptr()) + (self.inner.xLogDestroy.unwrap())(self.inner.pData, vfs.as_ptr(), db_path.as_ptr()) }; if rc != 0 { @@ -105,7 +114,7 @@ impl CreateWal for CreateSqlite3Wal { let rc = unsafe { (self.inner.xLogExists.unwrap())( self.inner.pData, - vfs.as_mut_ptr(), + vfs.as_ptr(), db_path.as_ptr(), &mut out, ) @@ -114,7 +123,6 @@ impl CreateWal for CreateSqlite3Wal { if rc != 0 { Err(Error::new(rc))? } else { - dbg!(out); Ok(out != 0) } } @@ -212,12 +220,24 @@ impl Wal for Sqlite3Wal { } } - fn undo( - &mut self, - cb: Option i32>, - cb_ctx: *mut c_void, - ) -> Result<()> { - let rc = unsafe { (self.inner.methods.xUndo.unwrap())(self.inner.pData, cb, cb_ctx) }; + fn undo(&mut self, undo_handler: Option<&mut U>) -> Result<()> { + unsafe extern "C" fn call_handler(p: *mut c_void, page_no: u32) -> c_int { + let this = &mut *(p as *mut U); + match this.handle_undo(page_no) { + Ok(_) => SQLITE_OK, + Err(e) => e.extended_code, + } + } + + let handler = undo_handler + .is_some() + .then_some(call_handler:: as unsafe extern "C" fn(*mut c_void, u32) -> i32); + let handler_data = undo_handler + .map(|d| d as *mut _ as *mut _) + .unwrap_or(std::ptr::null_mut()); + + let rc = + unsafe { (self.inner.methods.xUndo.unwrap())(self.inner.pData, handler, handler_data) }; if rc != 0 { Err(Error::new(rc)) } else { @@ -226,14 +246,14 @@ impl Wal for Sqlite3Wal { } fn savepoint(&mut self, rollback_data: &mut [u32]) { - assert_eq!(rollback_data.len(), WAL_SAVEPOINT_NDATA as _); + assert_eq!(rollback_data.len(), WAL_SAVEPOINT_NDATA as usize); unsafe { (self.inner.methods.xSavepoint.unwrap())(self.inner.pData, rollback_data.as_mut_ptr()); } } fn savepoint_undo(&mut self, rollback_data: &mut [u32]) -> Result<()> { - assert_eq!(rollback_data.len(), WAL_SAVEPOINT_NDATA as _); + assert_eq!(rollback_data.len(), WAL_SAVEPOINT_NDATA as usize); let rc = unsafe { (self.inner.methods.xSavepointUndo.unwrap())( self.inner.pData, @@ -250,7 +270,7 @@ impl Wal for Sqlite3Wal { fn insert_frames( &mut self, page_size: c_int, - page_headers: *mut libsql_pghdr, + page_headers: &mut PageHeaders, size_after: u32, is_commit: bool, sync_flags: c_int, @@ -259,7 +279,7 @@ impl Wal for Sqlite3Wal { (self.inner.methods.xFrames.unwrap())( self.inner.pData, page_size, - page_headers, + page_headers.as_ptr(), size_after, is_commit as _, sync_flags, @@ -274,7 +294,7 @@ impl Wal for Sqlite3Wal { fn checkpoint( &mut self, - db: *mut sqlite3, + db: &mut Sqlite3Db, mode: CheckpointMode, busy_handler: Option<&mut B>, sync_flags: u32, @@ -299,7 +319,7 @@ impl Wal for Sqlite3Wal { let rc = unsafe { (self.inner.methods.xCheckpoint.unwrap())( self.inner.pData, - db, + db.as_ptr(), mode as _, handler, handler_data, @@ -332,9 +352,9 @@ impl Wal for Sqlite3Wal { unsafe { (self.inner.methods.xHeapMemory.unwrap())(self.inner.pData) != 0 } } - fn set_db(&mut self, db: *mut sqlite3) { + fn set_db(&mut self, db: &mut Sqlite3Db) { unsafe { - (self.inner.methods.xDb.unwrap())(self.inner.pData, db); + (self.inner.methods.xDb.unwrap())(self.inner.pData, db.as_ptr()); } } @@ -345,7 +365,7 @@ impl Wal for Sqlite3Wal { fn last_fame_index(&self) -> u32 { unsafe { let wal = &*(self.inner.pData as *const sqlite3_wal); - wal.hdr.mxFrame as u32 + wal.hdr.mxFrame } } } diff --git a/libsql/src/hrana/hyper.rs b/libsql/src/hrana/hyper.rs index e1527f538f..9a7f32e4f3 100644 --- a/libsql/src/hrana/hyper.rs +++ b/libsql/src/hrana/hyper.rs @@ -17,7 +17,7 @@ pub struct HttpSender { impl HttpSender { pub fn new(connector: ConnectorService, version: Option<&str>) -> Self { - let ver = version.unwrap_or_else(|| env!("CARGO_PKG_VERSION")); + let ver = version.unwrap_or(env!("CARGO_PKG_VERSION")); let version = HeaderValue::try_from(format!("libsql-remote-{ver}")).unwrap(); diff --git a/libsql/src/local/database.rs b/libsql/src/local/database.rs index 41c77a8dba..3438ad314b 100644 --- a/libsql/src/local/database.rs +++ b/libsql/src/local/database.rs @@ -104,7 +104,7 @@ impl Database { connector, endpoint.as_str().try_into().unwrap(), auth_token, - version.as_ref().map(String::as_str), + version.as_deref(), ) .unwrap(); let path = PathBuf::from(db_path); diff --git a/libsql/src/replication/client.rs b/libsql/src/replication/client.rs index 1664753886..8a0e76d9c0 100644 --- a/libsql/src/replication/client.rs +++ b/libsql/src/replication/client.rs @@ -48,7 +48,7 @@ impl Client { auth_token: impl AsRef, version: Option<&str>, ) -> anyhow::Result { - let ver = version.unwrap_or_else(|| env!("CARGO_PKG_VERSION")); + let ver = version.unwrap_or(env!("CARGO_PKG_VERSION")); let version: AsciiMetadataValue = format!("libsql-rpc-{ver}") .try_into()