cleanup unlock_notify code a bit

This commit is contained in:
Thom Chiovoloni 2022-01-04 20:23:32 -08:00
parent 3e57bf4567
commit 519684a744
4 changed files with 59 additions and 58 deletions

View File

@ -13,7 +13,6 @@ use super::{Connection, InterruptHandle, OpenFlags, Result};
use crate::error::{error_from_handle, error_from_sqlite_code, Error}; use crate::error::{error_from_handle, error_from_sqlite_code, Error};
use crate::raw_statement::RawStatement; use crate::raw_statement::RawStatement;
use crate::statement::Statement; use crate::statement::Statement;
use crate::unlock_notify;
use crate::version::version_number; use crate::version::version_number;
pub struct InnerConnection { pub struct InnerConnection {
@ -223,35 +222,37 @@ impl InnerConnection {
let mut c_stmt = ptr::null_mut(); let mut c_stmt = ptr::null_mut();
let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?; let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
let mut c_tail = ptr::null(); let mut c_tail = ptr::null();
#[cfg(not(feature = "unlock_notify"))]
let r = unsafe { let r = unsafe {
if cfg!(feature = "unlock_notify") { ffi::sqlite3_prepare_v2(
let mut rc; self.db(),
loop { c_sql,
rc = ffi::sqlite3_prepare_v2( len,
self.db(), &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
c_sql, &mut c_tail as *mut *const c_char,
len, )
&mut c_stmt as *mut *mut ffi::sqlite3_stmt, };
&mut c_tail as *mut *const c_char, #[cfg(feature = "unlock_notify")]
); let r = unsafe {
if !unlock_notify::is_locked(self.db, rc) { use crate::unlock_notify;
break; let mut rc;
} loop {
rc = unlock_notify::wait_for_unlock_notify(self.db); rc = ffi::sqlite3_prepare_v2(
if rc != ffi::SQLITE_OK {
break;
}
}
rc
} else {
ffi::sqlite3_prepare_v2(
self.db(), self.db(),
c_sql, c_sql,
len, len,
&mut c_stmt as *mut *mut ffi::sqlite3_stmt, &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
&mut c_tail as *mut *const c_char, &mut c_tail as *mut *const c_char,
) );
if !unlock_notify::is_locked(self.db, rc) {
break;
}
rc = unlock_notify::wait_for_unlock_notify(self.db);
if rc != ffi::SQLITE_OK {
break;
}
} }
rc
}; };
// If there is an error, *ppStmt is set to NULL. // If there is an error, *ppStmt is set to NULL.
self.decode_result(r)?; self.decode_result(r)?;

View File

@ -125,6 +125,7 @@ mod statement;
pub mod trace; pub mod trace;
mod transaction; mod transaction;
pub mod types; pub mod types;
#[cfg(feature = "unlock_notify")]
mod unlock_notify; mod unlock_notify;
mod version; mod version;
#[cfg(feature = "vtab")] #[cfg(feature = "vtab")]

View File

@ -1,5 +1,4 @@
use super::ffi; use super::ffi;
use super::unlock_notify;
use super::StatementStatus; use super::StatementStatus;
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
use crate::util::SqliteMallocString; use crate::util::SqliteMallocString;
@ -101,25 +100,38 @@ impl RawStatement {
} }
} }
#[cfg_attr(not(feature = "unlock_notify"), inline)] #[inline]
#[cfg(not(feature = "unlock_notify"))]
pub fn step(&self) -> c_int { pub fn step(&self) -> c_int {
if cfg!(feature = "unlock_notify") { unsafe { ffi::sqlite3_step(self.ptr) }
let db = unsafe { ffi::sqlite3_db_handle(self.ptr) }; }
let mut rc;
loop { #[cfg(feature = "unlock_notify")]
rc = unsafe { ffi::sqlite3_step(self.ptr) }; pub fn step(&self) -> c_int {
if unsafe { !unlock_notify::is_locked(db, rc) } { use crate::unlock_notify;
break; let mut db = core::ptr::null_mut::<ffi::sqlite3>();
loop {
unsafe {
let mut rc = ffi::sqlite3_step(self.ptr);
// Bail out early for success and errors unrelated to locking. We
// still need check `is_locked` after this, but checking now lets us
// avoid one or two (admittedly cheap) calls into SQLite that we
// don't need to make.
if (rc & 0xff) != ffi::SQLITE_LOCKED {
break rc;
} }
rc = unsafe { unlock_notify::wait_for_unlock_notify(db) }; if db.is_null() {
db = ffi::sqlite3_db_handle(self.ptr);
}
if !unlock_notify::is_locked(db, rc) {
break rc;
}
rc = unlock_notify::wait_for_unlock_notify(db);
if rc != ffi::SQLITE_OK { if rc != ffi::SQLITE_OK {
break; break rc;
} }
self.reset(); self.reset();
} }
rc
} else {
unsafe { ffi::sqlite3_step(self.ptr) }
} }
} }

View File

@ -1,22 +1,17 @@
//! [Unlock Notification](http://sqlite.org/unlock_notify.html) //! [Unlock Notification](http://sqlite.org/unlock_notify.html)
use std::os::raw::c_int; use std::os::raw::c_int;
#[cfg(feature = "unlock_notify")]
use std::os::raw::c_void; use std::os::raw::c_void;
#[cfg(feature = "unlock_notify")]
use std::panic::catch_unwind; use std::panic::catch_unwind;
#[cfg(feature = "unlock_notify")]
use std::sync::{Condvar, Mutex}; use std::sync::{Condvar, Mutex};
use crate::ffi; use crate::ffi;
#[cfg(feature = "unlock_notify")]
struct UnlockNotification { struct UnlockNotification {
cond: Condvar, // Condition variable to wait on cond: Condvar, // Condition variable to wait on
mutex: Mutex<bool>, // Mutex to protect structure mutex: Mutex<bool>, // Mutex to protect structure
} }
#[cfg(feature = "unlock_notify")]
#[allow(clippy::mutex_atomic)] #[allow(clippy::mutex_atomic)]
impl UnlockNotification { impl UnlockNotification {
fn new() -> UnlockNotification { fn new() -> UnlockNotification {
@ -27,21 +22,25 @@ impl UnlockNotification {
} }
fn fired(&self) { fn fired(&self) {
let mut flag = self.mutex.lock().unwrap(); let mut flag = unpoison(self.mutex.lock());
*flag = true; *flag = true;
self.cond.notify_one(); self.cond.notify_one();
} }
fn wait(&self) { fn wait(&self) {
let mut fired = self.mutex.lock().unwrap(); let mut fired = unpoison(self.mutex.lock());
while !*fired { while !*fired {
fired = self.cond.wait(fired).unwrap(); fired = unpoison(self.cond.wait(fired));
} }
} }
} }
#[inline]
fn unpoison<T>(r: Result<T, std::sync::PoisonError<T>>) -> T {
r.unwrap_or_else(std::sync::PoisonError::into_inner)
}
/// This function is an unlock-notify callback /// This function is an unlock-notify callback
#[cfg(feature = "unlock_notify")]
unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) { unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) {
use std::slice::from_raw_parts; use std::slice::from_raw_parts;
let args = from_raw_parts(ap_arg as *const &UnlockNotification, n_arg as usize); let args = from_raw_parts(ap_arg as *const &UnlockNotification, n_arg as usize);
@ -50,7 +49,6 @@ unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) {
} }
} }
#[cfg(feature = "unlock_notify")]
pub unsafe fn is_locked(db: *mut ffi::sqlite3, rc: c_int) -> bool { pub unsafe fn is_locked(db: *mut ffi::sqlite3, rc: c_int) -> bool {
rc == ffi::SQLITE_LOCKED_SHAREDCACHE rc == ffi::SQLITE_LOCKED_SHAREDCACHE
|| (rc & 0xFF) == ffi::SQLITE_LOCKED || (rc & 0xFF) == ffi::SQLITE_LOCKED
@ -87,17 +85,6 @@ pub unsafe fn wait_for_unlock_notify(db: *mut ffi::sqlite3) -> c_int {
rc rc
} }
#[cfg(not(feature = "unlock_notify"))]
pub unsafe fn is_locked(_db: *mut ffi::sqlite3, _rc: c_int) -> bool {
unreachable!()
}
#[cfg(not(feature = "unlock_notify"))]
pub unsafe fn wait_for_unlock_notify(_db: *mut ffi::sqlite3) -> c_int {
unreachable!()
}
#[cfg(feature = "unlock_notify")]
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{Connection, OpenFlags, Result, Transaction, TransactionBehavior}; use crate::{Connection, OpenFlags, Result, Transaction, TransactionBehavior};