use std::time::Duration;
use std::time::Instant;
use rusqlite::Connection;
use super::{sqlite_is_busy, HostLeaseError, HostLeaseStore};
const WAL_CONVERSION_RETRY_INTERVAL: Duration = Duration::from_millis(5);
impl HostLeaseStore {
pub(super) fn connection(&self, busy_timeout: Duration) -> Result<Connection, HostLeaseError> {
let conn = Connection::open(&self.db_path)?;
self.install_lock_patience(&conn, busy_timeout)?;
self.enable_wal_journal(&conn, busy_timeout)?;
Ok(conn)
}
fn enable_wal_journal(
&self,
conn: &Connection,
busy_timeout: Duration,
) -> Result<(), HostLeaseError> {
let deadline = Instant::now() + busy_timeout;
loop {
match conn.execute_batch("PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;") {
Ok(()) => return Ok(()),
Err(error) if sqlite_is_busy(&error) && Instant::now() < deadline => {
std::thread::sleep(WAL_CONVERSION_RETRY_INTERVAL);
}
Err(error) => return Err(error.into()),
}
}
}
fn install_lock_patience(
&self,
conn: &Connection,
busy_timeout: Duration,
) -> Result<(), HostLeaseError> {
#[cfg(test)]
if !busy_timeout.is_zero() {
if let Some(handler) = self.busy_handler {
conn.busy_handler(Some(handler))?;
return Ok(());
}
}
conn.busy_timeout(busy_timeout)?;
Ok(())
}
}