mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-17 08:34:19 +01:00
core: Switch RwLock<Arc<Pager>> to ArcSwap<Pager>
We don't actually need the RwLock locking capabilities, just the ability to swap the instance.
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -227,6 +227,12 @@ version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@@ -4904,6 +4910,7 @@ dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
"antithesis_sdk",
|
||||
"arc-swap",
|
||||
"bitflags 2.9.4",
|
||||
"built",
|
||||
"bytemuck",
|
||||
|
||||
@@ -84,6 +84,7 @@ twox-hash = "2.1.1"
|
||||
intrusive-collections = "0.9.7"
|
||||
roaring = "0.11.2"
|
||||
simsimd = "6.5.3"
|
||||
arc-swap = "1.7"
|
||||
|
||||
[build-dependencies]
|
||||
chrono = { workspace = true, default-features = false }
|
||||
|
||||
@@ -2580,7 +2580,7 @@ mod tests {
|
||||
let io: Arc<dyn IO> = Arc::new(MemoryIO::new());
|
||||
let db = Database::open_file(io.clone(), ":memory:", false, false).unwrap();
|
||||
let conn = db.connect().unwrap();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
|
||||
let _ = pager.io.block(|| pager.allocate_page1()).unwrap();
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ mod tests {
|
||||
let db = Database::open_file(io.clone(), ":memory:", false, false).unwrap();
|
||||
let conn = db.connect().unwrap();
|
||||
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
|
||||
// Allocate page 1 first (database header)
|
||||
let _ = pager.io.block(|| pager.allocate_page1());
|
||||
|
||||
@@ -86,7 +86,7 @@ impl ProjectOperator {
|
||||
|
||||
for col in &self.columns {
|
||||
// Use the internal connection's pager for expression evaluation
|
||||
let internal_pager = self.internal_conn.pager.read().clone();
|
||||
let internal_pager = self.internal_conn.pager.load().clone();
|
||||
|
||||
// Execute the compiled expression (handles both columns and complex expressions)
|
||||
let result = col
|
||||
|
||||
63
core/lib.rs
63
core/lib.rs
@@ -51,6 +51,7 @@ use crate::vdbe::explain::{EXPLAIN_COLUMNS_TYPE, EXPLAIN_QUERY_PLAN_COLUMNS_TYPE
|
||||
use crate::vdbe::metrics::ConnectionMetrics;
|
||||
use crate::vtab::VirtualTable;
|
||||
use crate::{incremental::view::AllViewsTxState, translate::emitter::TransactionMode};
|
||||
use arc_swap::ArcSwap;
|
||||
use core::str;
|
||||
pub use error::{CompletionError, LimboError};
|
||||
pub use io::clock::{Clock, Instant};
|
||||
@@ -487,7 +488,7 @@ impl Database {
|
||||
let conn = db.connect()?;
|
||||
|
||||
let syms = conn.syms.read();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
|
||||
if let Some(encryption_opts) = encryption_opts {
|
||||
conn.pragma_update("cipher", format!("'{}'", encryption_opts.cipher))?;
|
||||
@@ -559,7 +560,7 @@ impl Database {
|
||||
.get();
|
||||
let conn = Arc::new(Connection {
|
||||
db: self.clone(),
|
||||
pager: RwLock::new(pager),
|
||||
pager: ArcSwap::new(pager),
|
||||
schema: RwLock::new(self.schema.lock().unwrap().clone()),
|
||||
database_schemas: RwLock::new(std::collections::HashMap::new()),
|
||||
auto_commit: AtomicBool::new(true),
|
||||
@@ -1061,7 +1062,7 @@ impl DatabaseCatalog {
|
||||
|
||||
pub struct Connection {
|
||||
db: Arc<Database>,
|
||||
pager: RwLock<Arc<Pager>>,
|
||||
pager: ArcSwap<Pager>,
|
||||
schema: RwLock<Arc<Schema>>,
|
||||
/// Per-database schema cache (database_index -> schema)
|
||||
/// Loaded lazily to avoid copying all schemas on connection open
|
||||
@@ -1161,7 +1162,7 @@ impl Connection {
|
||||
.unwrap()
|
||||
.trim();
|
||||
self.maybe_update_schema();
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
let mode = QueryMode::new(&cmd);
|
||||
let (Cmd::Stmt(stmt) | Cmd::Explain(stmt) | Cmd::ExplainQueryPlan(stmt)) = cmd;
|
||||
let program = translate::translate(
|
||||
@@ -1192,7 +1193,7 @@ impl Connection {
|
||||
/// This function must be called outside of any transaction because internally it will start transaction session by itself
|
||||
#[allow(dead_code)]
|
||||
fn maybe_reparse_schema(self: &Arc<Connection>) -> Result<()> {
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
|
||||
// first, quickly read schema_version from the root page in order to check if schema changed
|
||||
pager.begin_read_tx()?;
|
||||
@@ -1258,7 +1259,7 @@ impl Connection {
|
||||
}
|
||||
|
||||
fn reparse_schema(self: &Arc<Connection>) -> Result<()> {
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
|
||||
// read cookie before consuming statement program - otherwise we can end up reading cookie with closed transaction state
|
||||
let cookie = pager
|
||||
@@ -1315,7 +1316,7 @@ impl Connection {
|
||||
let mut parser = Parser::new(sql.as_bytes());
|
||||
while let Some(cmd) = parser.next_cmd()? {
|
||||
let syms = self.syms.read();
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
let byte_offset_end = parser.offset();
|
||||
let input = str::from_utf8(&sql.as_bytes()[..byte_offset_end])
|
||||
.unwrap()
|
||||
@@ -1367,7 +1368,7 @@ impl Connection {
|
||||
return Err(LimboError::InternalError("Connection closed".to_string()));
|
||||
}
|
||||
let syms = self.syms.read();
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
let mode = QueryMode::new(&cmd);
|
||||
let (Cmd::Stmt(stmt) | Cmd::Explain(stmt) | Cmd::ExplainQueryPlan(stmt)) = cmd;
|
||||
let program = translate::translate(
|
||||
@@ -1399,7 +1400,7 @@ impl Connection {
|
||||
let mut parser = Parser::new(sql.as_bytes());
|
||||
while let Some(cmd) = parser.next_cmd()? {
|
||||
let syms = self.syms.read();
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
let byte_offset_end = parser.offset();
|
||||
let input = str::from_utf8(&sql.as_bytes()[..byte_offset_end])
|
||||
.unwrap()
|
||||
@@ -1428,7 +1429,7 @@ impl Connection {
|
||||
return Ok(None);
|
||||
};
|
||||
let syms = self.syms.read();
|
||||
let pager = self.pager.read().clone();
|
||||
let pager = self.pager.load().clone();
|
||||
let byte_offset_end = parser.offset();
|
||||
let input = str::from_utf8(&sql.as_bytes()[..byte_offset_end])
|
||||
.unwrap()
|
||||
@@ -1518,7 +1519,7 @@ impl Connection {
|
||||
if let Some(encryption_opts) = encryption_opts {
|
||||
let _ = conn.pragma_update("cipher", encryption_opts.cipher.to_string());
|
||||
let _ = conn.pragma_update("hexkey", encryption_opts.hexkey.to_string());
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
if db.db_state.get().is_initialized() {
|
||||
// Clear page cache so the header page can be reread from disk and decrypted using the encryption context.
|
||||
pager.clear_page_cache(false);
|
||||
@@ -1572,7 +1573,7 @@ impl Connection {
|
||||
/// Read schema version at current transaction
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn read_schema_version(&self) -> Result<u32> {
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
pager
|
||||
.io
|
||||
.block(|| pager.with_header(|header| header.schema_cookie))
|
||||
@@ -1590,7 +1591,7 @@ impl Connection {
|
||||
"write_schema_version must be called from within Write transaction".to_string(),
|
||||
));
|
||||
};
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
pager.io.block(|| {
|
||||
pager.with_header_mut(|header| {
|
||||
turso_assert!(
|
||||
@@ -1617,7 +1618,7 @@ impl Connection {
|
||||
page: &mut [u8],
|
||||
frame_watermark: Option<u64>,
|
||||
) -> Result<bool> {
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
let (page_ref, c) = match pager.read_page_no_cache(page_idx as i64, frame_watermark, true) {
|
||||
Ok(result) => result,
|
||||
// on windows, zero read will trigger UnexpectedEof
|
||||
@@ -1643,19 +1644,19 @@ impl Connection {
|
||||
/// (so, if concurrent connection wrote something to the WAL - this method will not see this change)
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_changed_pages_after(&self, frame_watermark: u64) -> Result<Vec<u32>> {
|
||||
self.pager.read().wal_changed_pages_after(frame_watermark)
|
||||
self.pager.load().wal_changed_pages_after(frame_watermark)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_state(&self) -> Result<WalState> {
|
||||
self.pager.read().wal_state()
|
||||
self.pager.load().wal_state()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_get_frame(&self, frame_no: u64, frame: &mut [u8]) -> Result<WalFrameInfo> {
|
||||
use crate::storage::sqlite3_ondisk::parse_wal_frame_header;
|
||||
|
||||
let c = self.pager.read().wal_get_frame(frame_no, frame)?;
|
||||
let c = self.pager.load().wal_get_frame(frame_no, frame)?;
|
||||
self.db.io.wait_for_completion(c)?;
|
||||
let (header, _) = parse_wal_frame_header(frame);
|
||||
Ok(WalFrameInfo {
|
||||
@@ -1669,13 +1670,13 @@ impl Connection {
|
||||
/// If attempt to write frame at the position `frame_no` will create gap in the WAL - method will return error
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_insert_frame(&self, frame_no: u64, frame: &[u8]) -> Result<WalFrameInfo> {
|
||||
self.pager.read().wal_insert_frame(frame_no, frame)
|
||||
self.pager.load().wal_insert_frame(frame_no, frame)
|
||||
}
|
||||
|
||||
/// Start WAL session by initiating read+write transaction for this connection
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_insert_begin(&self) -> Result<()> {
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
pager.begin_read_tx()?;
|
||||
pager.io.block(|| pager.begin_write_tx()).inspect_err(|_| {
|
||||
pager.end_read_tx();
|
||||
@@ -1695,7 +1696,7 @@ impl Connection {
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
pub fn wal_insert_end(self: &Arc<Connection>, force_commit: bool) -> Result<()> {
|
||||
{
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
|
||||
let Some(wal) = pager.wal.as_ref() else {
|
||||
return Err(LimboError::InternalError(
|
||||
@@ -1745,14 +1746,14 @@ impl Connection {
|
||||
if self.is_closed() {
|
||||
return Err(LimboError::InternalError("Connection closed".to_string()));
|
||||
}
|
||||
self.pager.read().cacheflush()
|
||||
self.pager.load().cacheflush()
|
||||
}
|
||||
|
||||
pub fn checkpoint(&self, mode: CheckpointMode) -> Result<CheckpointResult> {
|
||||
if self.is_closed() {
|
||||
return Err(LimboError::InternalError("Connection closed".to_string()));
|
||||
}
|
||||
self.pager.read().wal_checkpoint(mode)
|
||||
self.pager.load().wal_checkpoint(mode)
|
||||
}
|
||||
|
||||
/// Close a connection and checkpoint.
|
||||
@@ -1768,7 +1769,7 @@ impl Connection {
|
||||
}
|
||||
_ => {
|
||||
if !self.mvcc_enabled() {
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
pager.rollback_tx(self);
|
||||
}
|
||||
self.set_tx_state(TransactionState::None);
|
||||
@@ -1782,7 +1783,7 @@ impl Connection {
|
||||
.eq(&1)
|
||||
{
|
||||
self.pager
|
||||
.read()
|
||||
.load()
|
||||
.checkpoint_shutdown(self.is_wal_auto_checkpoint_disabled())?;
|
||||
};
|
||||
Ok(())
|
||||
@@ -1891,11 +1892,11 @@ impl Connection {
|
||||
shared_wal.enabled.store(false, Ordering::SeqCst);
|
||||
shared_wal.file = None;
|
||||
}
|
||||
self.pager.write().clear_page_cache(false);
|
||||
self.pager.load().clear_page_cache(false);
|
||||
let pager = self.db.init_pager(Some(size.get() as usize))?;
|
||||
pager.enable_encryption(self.db.opts.enable_encryption);
|
||||
*self.pager.write() = Arc::new(pager);
|
||||
self.pager.read().set_initial_page_size(size);
|
||||
self.pager.store(Arc::new(pager));
|
||||
self.pager.load().set_initial_page_size(size);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -2034,7 +2035,7 @@ impl Connection {
|
||||
|
||||
fn get_pager_from_database_index(&self, index: &usize) -> Arc<Pager> {
|
||||
if *index < 2 {
|
||||
self.pager.read().clone()
|
||||
self.pager.load().clone()
|
||||
} else {
|
||||
self.attached_databases.read().get_pager_by_index(index)
|
||||
}
|
||||
@@ -2247,7 +2248,7 @@ impl Connection {
|
||||
}
|
||||
|
||||
pub fn get_pager(&self) -> Arc<Pager> {
|
||||
self.pager.read().clone()
|
||||
self.pager.load().clone()
|
||||
}
|
||||
|
||||
pub fn get_query_only(&self) -> bool {
|
||||
@@ -2294,7 +2295,7 @@ impl Connection {
|
||||
}
|
||||
|
||||
pub fn set_reserved_bytes(&self, reserved_bytes: u8) -> Result<()> {
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
pager.set_reserved_space_bytes(reserved_bytes);
|
||||
Ok(())
|
||||
}
|
||||
@@ -2317,7 +2318,7 @@ impl Connection {
|
||||
return Ok(());
|
||||
};
|
||||
tracing::trace!("setting encryption ctx for connection");
|
||||
let pager = self.pager.read();
|
||||
let pager = self.pager.load();
|
||||
if pager.is_encryption_ctx_set() {
|
||||
return Err(LimboError::InvalidArgument(
|
||||
"cannot reset encryption attributes if already set in the session".to_string(),
|
||||
|
||||
@@ -404,7 +404,7 @@ impl<Clock: LogicalClock> CommitStateMachine<Clock> {
|
||||
commit_coordinator: Arc<CommitCoordinator>,
|
||||
header: Arc<RwLock<Option<DatabaseHeader>>>,
|
||||
) -> Self {
|
||||
let pager = connection.pager.read().clone();
|
||||
let pager = connection.pager.load().clone();
|
||||
Self {
|
||||
state,
|
||||
is_finalized: false,
|
||||
@@ -1047,7 +1047,7 @@ impl<Clock: LogicalClock> MvStore<Clock> {
|
||||
self.insert_table_id_to_rootpage(root_page_as_table_id, Some(*root_page));
|
||||
}
|
||||
|
||||
if !self.maybe_recover_logical_log(bootstrap_conn.pager.read().clone())? {
|
||||
if !self.maybe_recover_logical_log(bootstrap_conn.pager.load().clone())? {
|
||||
// There was no logical log to recover, so we're done.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ fn test_insert_read() {
|
||||
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -145,7 +145,7 @@ fn test_insert_read() {
|
||||
|
||||
let tx2 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
@@ -166,7 +166,7 @@ fn test_read_nonexistent() {
|
||||
let db = MvccTestDb::new();
|
||||
let tx = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row = db.mvcc_store.read(
|
||||
tx,
|
||||
@@ -184,7 +184,7 @@ fn test_delete() {
|
||||
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -224,7 +224,7 @@ fn test_delete() {
|
||||
|
||||
let tx2 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
@@ -244,7 +244,7 @@ fn test_delete_nonexistent() {
|
||||
let db = MvccTestDb::new();
|
||||
let tx = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
assert!(!db
|
||||
.mvcc_store
|
||||
@@ -263,7 +263,7 @@ fn test_commit() {
|
||||
let db = MvccTestDb::new();
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -297,7 +297,7 @@ fn test_commit() {
|
||||
|
||||
let tx2 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
@@ -320,7 +320,7 @@ fn test_rollback() {
|
||||
let db = MvccTestDb::new();
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row1 = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, row1.clone()).unwrap();
|
||||
@@ -351,10 +351,10 @@ fn test_rollback() {
|
||||
.unwrap();
|
||||
assert_eq!(row3, row4);
|
||||
db.mvcc_store
|
||||
.rollback_tx(tx1, db.conn.pager.read().clone(), &db.conn);
|
||||
.rollback_tx(tx1, db.conn.pager.load().clone(), &db.conn);
|
||||
let tx2 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row5 = db
|
||||
.mvcc_store
|
||||
@@ -376,7 +376,7 @@ fn test_dirty_write() {
|
||||
// T1 inserts a row with ID 1, but does not commit.
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -395,7 +395,7 @@ fn test_dirty_write() {
|
||||
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
// T2 attempts to delete row with ID 1, but fails because T1 has not committed.
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let tx2_row = generate_simple_string_row((-2).into(), 1, "World");
|
||||
assert!(!db.mvcc_store.update(tx2, tx2_row).unwrap());
|
||||
|
||||
@@ -420,14 +420,14 @@ fn test_dirty_read() {
|
||||
// T1 inserts a row with ID 1, but does not commit.
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let row1 = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, row1).unwrap();
|
||||
|
||||
// T2 attempts to read row with ID 1, but doesn't see one because T1 has not committed.
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let row2 = db
|
||||
.mvcc_store
|
||||
.read(
|
||||
@@ -448,7 +448,7 @@ fn test_dirty_read_deleted() {
|
||||
// T1 inserts a row with ID 1 and commits.
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -456,7 +456,7 @@ fn test_dirty_read_deleted() {
|
||||
|
||||
// T2 deletes row with ID 1, but does not commit.
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
assert!(db
|
||||
.mvcc_store
|
||||
.delete(
|
||||
@@ -470,7 +470,7 @@ fn test_dirty_read_deleted() {
|
||||
|
||||
// T3 reads row with ID 1, but doesn't see the delete because T2 hasn't committed.
|
||||
let conn3 = db.db.connect().unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.read().clone()).unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.load().clone()).unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
.read(
|
||||
@@ -492,7 +492,7 @@ fn test_fuzzy_read() {
|
||||
// T1 inserts a row with ID 1 and commits.
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "First");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -512,7 +512,7 @@ fn test_fuzzy_read() {
|
||||
|
||||
// T2 reads the row with ID 1 within an active transaction.
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
.read(
|
||||
@@ -528,7 +528,7 @@ fn test_fuzzy_read() {
|
||||
|
||||
// T3 updates the row and commits.
|
||||
let conn3 = db.db.connect().unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.read().clone()).unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.load().clone()).unwrap();
|
||||
let tx3_row = generate_simple_string_row((-2).into(), 1, "Second");
|
||||
db.mvcc_store.update(tx3, tx3_row).unwrap();
|
||||
commit_tx(db.mvcc_store.clone(), &conn3, tx3).unwrap();
|
||||
@@ -561,7 +561,7 @@ fn test_lost_update() {
|
||||
// T1 inserts a row with ID 1 and commits.
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -581,13 +581,13 @@ fn test_lost_update() {
|
||||
|
||||
// T2 attempts to update row ID 1 within an active transaction.
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let tx2_row = generate_simple_string_row((-2).into(), 1, "World");
|
||||
assert!(db.mvcc_store.update(tx2, tx2_row.clone()).unwrap());
|
||||
|
||||
// T3 also attempts to update row ID 1 within an active transaction.
|
||||
let conn3 = db.db.connect().unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.read().clone()).unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.load().clone()).unwrap();
|
||||
let tx3_row = generate_simple_string_row((-2).into(), 1, "Hello, world!");
|
||||
assert!(matches!(
|
||||
db.mvcc_store.update(tx3, tx3_row),
|
||||
@@ -595,7 +595,7 @@ fn test_lost_update() {
|
||||
));
|
||||
// hack: in the actual tursodb database we rollback the mvcc tx ourselves, so manually roll it back here
|
||||
db.mvcc_store
|
||||
.rollback_tx(tx3, conn3.pager.read().clone(), &conn3);
|
||||
.rollback_tx(tx3, conn3.pager.load().clone(), &conn3);
|
||||
|
||||
commit_tx(db.mvcc_store.clone(), &conn2, tx2).unwrap();
|
||||
assert!(matches!(
|
||||
@@ -604,7 +604,7 @@ fn test_lost_update() {
|
||||
));
|
||||
|
||||
let conn4 = db.db.connect().unwrap();
|
||||
let tx4 = db.mvcc_store.begin_tx(conn4.pager.read().clone()).unwrap();
|
||||
let tx4 = db.mvcc_store.begin_tx(conn4.pager.load().clone()).unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
.read(
|
||||
@@ -628,7 +628,7 @@ fn test_committed_visibility() {
|
||||
// let's add $10 to my account since I like money
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let tx1_row = generate_simple_string_row((-2).into(), 1, "10");
|
||||
db.mvcc_store.insert(tx1, tx1_row.clone()).unwrap();
|
||||
@@ -636,7 +636,7 @@ fn test_committed_visibility() {
|
||||
|
||||
// but I like more money, so let me try adding $10 more
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let tx2_row = generate_simple_string_row((-2).into(), 1, "20");
|
||||
assert!(db.mvcc_store.update(tx2, tx2_row.clone()).unwrap());
|
||||
let row = db
|
||||
@@ -654,7 +654,7 @@ fn test_committed_visibility() {
|
||||
|
||||
// can I check how much money I have?
|
||||
let conn3 = db.db.connect().unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.read().clone()).unwrap();
|
||||
let tx3 = db.mvcc_store.begin_tx(conn3.pager.load().clone()).unwrap();
|
||||
let row = db
|
||||
.mvcc_store
|
||||
.read(
|
||||
@@ -676,11 +676,11 @@ fn test_future_row() {
|
||||
|
||||
let tx1 = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
|
||||
let conn2 = db.db.connect().unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.read().clone()).unwrap();
|
||||
let tx2 = db.mvcc_store.begin_tx(conn2.pager.load().clone()).unwrap();
|
||||
let tx2_row = generate_simple_string_row((-2).into(), 1, "Hello");
|
||||
db.mvcc_store.insert(tx2, tx2_row).unwrap();
|
||||
|
||||
@@ -726,7 +726,7 @@ fn setup_test_db() -> (MvccTestDb, u64) {
|
||||
let db = MvccTestDb::new();
|
||||
let tx_id = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
|
||||
let table_id = MVTableId::new(-1);
|
||||
@@ -749,7 +749,7 @@ fn setup_test_db() -> (MvccTestDb, u64) {
|
||||
|
||||
let tx_id = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
(db, tx_id)
|
||||
}
|
||||
@@ -758,7 +758,7 @@ fn setup_lazy_db(initial_keys: &[i64]) -> (MvccTestDb, u64) {
|
||||
let db = MvccTestDb::new();
|
||||
let tx_id = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
|
||||
let table_id = -1;
|
||||
@@ -774,7 +774,7 @@ fn setup_lazy_db(initial_keys: &[i64]) -> (MvccTestDb, u64) {
|
||||
|
||||
let tx_id = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
(db, tx_id)
|
||||
}
|
||||
@@ -829,8 +829,8 @@ fn test_lazy_scan_cursor_basic() {
|
||||
db.mvcc_store.clone(),
|
||||
tx_id,
|
||||
table_id,
|
||||
db.conn.pager.read().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.read().clone(), table_id, 1)),
|
||||
db.conn.pager.load().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.load().clone(), table_id, 1)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -872,8 +872,8 @@ fn test_lazy_scan_cursor_with_gaps() {
|
||||
db.mvcc_store.clone(),
|
||||
tx_id,
|
||||
table_id,
|
||||
db.conn.pager.read().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.read().clone(), table_id, 1)),
|
||||
db.conn.pager.load().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.load().clone(), table_id, 1)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -924,8 +924,8 @@ fn test_cursor_basic() {
|
||||
db.mvcc_store.clone(),
|
||||
tx_id,
|
||||
table_id,
|
||||
db.conn.pager.read().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.read().clone(), table_id, 1)),
|
||||
db.conn.pager.load().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.load().clone(), table_id, 1)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -964,13 +964,13 @@ fn test_cursor_with_empty_table() {
|
||||
let db = MvccTestDb::new();
|
||||
{
|
||||
// FIXME: force page 1 initialization
|
||||
let pager = db.conn.pager.read().clone();
|
||||
let pager = db.conn.pager.load().clone();
|
||||
let tx_id = db.mvcc_store.begin_tx(pager.clone()).unwrap();
|
||||
commit_tx(db.mvcc_store.clone(), &db.conn, tx_id).unwrap();
|
||||
}
|
||||
let tx_id = db
|
||||
.mvcc_store
|
||||
.begin_tx(db.conn.pager.read().clone())
|
||||
.begin_tx(db.conn.pager.load().clone())
|
||||
.unwrap();
|
||||
let table_id = -1; // Empty table
|
||||
|
||||
@@ -979,8 +979,8 @@ fn test_cursor_with_empty_table() {
|
||||
db.mvcc_store.clone(),
|
||||
tx_id,
|
||||
table_id,
|
||||
db.conn.pager.read().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.read().clone(), table_id, 1)),
|
||||
db.conn.pager.load().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.load().clone(), table_id, 1)),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(cursor.is_empty());
|
||||
@@ -997,8 +997,8 @@ fn test_cursor_modification_during_scan() {
|
||||
db.mvcc_store.clone(),
|
||||
tx_id,
|
||||
table_id,
|
||||
db.conn.pager.read().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.read().clone(), table_id, 1)),
|
||||
db.conn.pager.load().clone(),
|
||||
Box::new(BTreeCursor::new(db.conn.pager.load().clone(), table_id, 1)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1202,7 +1202,7 @@ fn test_restart() {
|
||||
{
|
||||
let conn = db.connect();
|
||||
let mvcc_store = db.get_mvcc_store();
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
// insert table id -2 into sqlite_schema table (table_id -1)
|
||||
let data = ImmutableRecord::from_values(
|
||||
&[
|
||||
@@ -1240,13 +1240,13 @@ fn test_restart() {
|
||||
{
|
||||
let conn = db.connect();
|
||||
let mvcc_store = db.get_mvcc_store();
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let row = generate_simple_string_row((-2).into(), 2, "bar");
|
||||
|
||||
mvcc_store.insert(tx_id, row).unwrap();
|
||||
commit_tx(mvcc_store.clone(), &conn, tx_id).unwrap();
|
||||
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx_id = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let row = mvcc_store
|
||||
.read(tx_id, RowID::new((-2).into(), 2))
|
||||
.unwrap()
|
||||
|
||||
@@ -65,7 +65,7 @@ mod tests {
|
||||
let conn = db.get_db().connect().unwrap();
|
||||
let mvcc_store = db.get_db().mv_store.as_ref().unwrap().clone();
|
||||
for _ in 0..iterations {
|
||||
let tx = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let id = IDS.fetch_add(1, Ordering::SeqCst);
|
||||
let id = RowID {
|
||||
table_id: (-2).into(),
|
||||
@@ -74,7 +74,7 @@ mod tests {
|
||||
let row = generate_simple_string_row((-2).into(), id.row_id, "Hello");
|
||||
mvcc_store.insert(tx, row.clone()).unwrap();
|
||||
commit_tx_no_conn(&db, tx, &conn).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let committed_row = mvcc_store.read(tx, id).unwrap();
|
||||
commit_tx_no_conn(&db, tx, &conn).unwrap();
|
||||
assert_eq!(committed_row, Some(row));
|
||||
@@ -86,7 +86,7 @@ mod tests {
|
||||
let conn = db.get_db().connect().unwrap();
|
||||
let mvcc_store = db.get_db().mv_store.as_ref().unwrap().clone();
|
||||
for _ in 0..iterations {
|
||||
let tx = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let id = IDS.fetch_add(1, Ordering::SeqCst);
|
||||
let id = RowID {
|
||||
table_id: (-2).into(),
|
||||
@@ -95,7 +95,7 @@ mod tests {
|
||||
let row = generate_simple_string_row((-2).into(), id.row_id, "World");
|
||||
mvcc_store.insert(tx, row.clone()).unwrap();
|
||||
commit_tx_no_conn(&db, tx, &conn).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let committed_row = mvcc_store.read(tx, id).unwrap();
|
||||
commit_tx_no_conn(&db, tx, &conn).unwrap();
|
||||
assert_eq!(committed_row, Some(row));
|
||||
@@ -127,7 +127,7 @@ mod tests {
|
||||
let dropped = mvcc_store.drop_unused_row_versions();
|
||||
tracing::debug!("garbage collected {dropped} versions");
|
||||
}
|
||||
let tx = mvcc_store.begin_tx(conn.pager.read().clone()).unwrap();
|
||||
let tx = mvcc_store.begin_tx(conn.pager.load().clone()).unwrap();
|
||||
let id = i % 16;
|
||||
let id = RowID {
|
||||
table_id: (-2).into(),
|
||||
|
||||
@@ -513,7 +513,7 @@ mod tests {
|
||||
let db = MvccTestDbNoConn::new_with_random_db();
|
||||
let (io, pager) = {
|
||||
let conn = db.connect();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
let mvcc_store = db.get_mvcc_store();
|
||||
let tx_id = mvcc_store.begin_tx(pager.clone()).unwrap();
|
||||
// insert table id -2 into sqlite_schema table (table_id -1)
|
||||
@@ -580,7 +580,7 @@ mod tests {
|
||||
let db = MvccTestDbNoConn::new_with_random_db();
|
||||
let (io, pager) = {
|
||||
let conn = db.connect();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
let mvcc_store = db.get_mvcc_store();
|
||||
|
||||
let tx_id = mvcc_store.begin_tx(pager.clone()).unwrap();
|
||||
@@ -691,7 +691,7 @@ mod tests {
|
||||
let mut db = MvccTestDbNoConn::new_with_random_db();
|
||||
let pager = {
|
||||
let conn = db.connect();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
let mvcc_store = db.get_mvcc_store();
|
||||
|
||||
// insert table id -2 into sqlite_schema table (table_id -1)
|
||||
|
||||
@@ -7864,11 +7864,11 @@ mod tests {
|
||||
pos,
|
||||
&record,
|
||||
4096,
|
||||
conn.pager.read().clone(),
|
||||
conn.pager.load().clone(),
|
||||
&mut fill_cell_payload_state,
|
||||
)
|
||||
},
|
||||
&conn.pager.read().clone(),
|
||||
&conn.pager.load().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
insert_into_cell(page.get_contents(), &payload, pos, 4096).unwrap();
|
||||
@@ -8137,7 +8137,7 @@ mod tests {
|
||||
let io: Arc<dyn IO> = Arc::new(MemoryIO::new());
|
||||
let db = Database::open_file(io.clone(), ":memory:", false, false).unwrap();
|
||||
let conn = db.connect().unwrap();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
|
||||
// FIXME: handle page cache is full
|
||||
|
||||
@@ -8157,7 +8157,7 @@ mod tests {
|
||||
let io: Arc<dyn IO> = Arc::new(MemoryIO::new());
|
||||
let db = Database::open_file(io.clone(), ":memory:", false, false).unwrap();
|
||||
let conn = db.connect().unwrap();
|
||||
let pager = conn.pager.read().clone();
|
||||
let pager = conn.pager.load().clone();
|
||||
|
||||
let mut cursor = BTreeCursor::new(pager, 1, 5);
|
||||
let result = cursor.rewind()?;
|
||||
@@ -9626,11 +9626,11 @@ mod tests {
|
||||
cell_idx,
|
||||
&record,
|
||||
4096,
|
||||
conn.pager.read().clone(),
|
||||
conn.pager.load().clone(),
|
||||
&mut fill_cell_payload_state,
|
||||
)
|
||||
},
|
||||
&conn.pager.read().clone(),
|
||||
&conn.pager.load().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
if (free as usize) < payload.len() + 2 {
|
||||
@@ -9708,11 +9708,11 @@ mod tests {
|
||||
cell_idx,
|
||||
&record,
|
||||
4096,
|
||||
conn.pager.read().clone(),
|
||||
conn.pager.load().clone(),
|
||||
&mut fill_cell_payload_state,
|
||||
)
|
||||
},
|
||||
&conn.pager.read().clone(),
|
||||
&conn.pager.load().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
if (free as usize) < payload.len() - 2 {
|
||||
@@ -10081,11 +10081,11 @@ mod tests {
|
||||
0,
|
||||
&record,
|
||||
4096,
|
||||
conn.pager.read().clone(),
|
||||
conn.pager.load().clone(),
|
||||
&mut fill_cell_payload_state,
|
||||
)
|
||||
},
|
||||
&conn.pager.read().clone(),
|
||||
&conn.pager.load().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -10167,11 +10167,11 @@ mod tests {
|
||||
0,
|
||||
&record,
|
||||
4096,
|
||||
conn.pager.read().clone(),
|
||||
conn.pager.load().clone(),
|
||||
&mut fill_cell_payload_state,
|
||||
)
|
||||
},
|
||||
&conn.pager.read().clone(),
|
||||
&conn.pager.load().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
insert_into_cell(page.get_contents(), &payload, 0, 4096).unwrap();
|
||||
|
||||
@@ -2560,7 +2560,7 @@ pub mod test {
|
||||
for _i in 0..25 {
|
||||
let _ = conn.execute("insert into test (value) values (randomblob(1024)), (randomblob(1024)), (randomblob(1024))");
|
||||
}
|
||||
let pager = conn.pager.write();
|
||||
let pager = conn.pager.load();
|
||||
let _ = pager.cacheflush();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
|
||||
@@ -2651,7 +2651,7 @@ pub mod test {
|
||||
conn.execute("create table test(id integer primary key, value text)")
|
||||
.unwrap();
|
||||
bulk_inserts(&conn, 20, 3);
|
||||
let completions = conn.pager.write().cacheflush().unwrap();
|
||||
let completions = conn.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
@@ -2677,7 +2677,7 @@ pub mod test {
|
||||
// Run a RESTART checkpoint, should backfill everything and reset WAL counters,
|
||||
// but NOT truncate the file.
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let res = run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Restart);
|
||||
assert_eq!(res.num_attempted, mx_before);
|
||||
@@ -2723,7 +2723,7 @@ pub mod test {
|
||||
conn.execute("insert into test(value) values ('post_restart')")
|
||||
.unwrap();
|
||||
conn.pager
|
||||
.write()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -2746,14 +2746,14 @@ pub mod test {
|
||||
.execute("create table test(id integer primary key, value text)")
|
||||
.unwrap();
|
||||
bulk_inserts(&conn1.clone(), 15, 2);
|
||||
let completions = conn1.pager.write().cacheflush().unwrap();
|
||||
let completions = conn1.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
|
||||
// Force a read transaction that will freeze a lower read mark
|
||||
let readmark = {
|
||||
let pager = conn2.pager.write();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal2 = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal2.begin_read_tx().unwrap();
|
||||
wal2.get_max_frame()
|
||||
@@ -2761,14 +2761,14 @@ pub mod test {
|
||||
|
||||
// generate more frames that the reader will not see.
|
||||
bulk_inserts(&conn1.clone(), 15, 2);
|
||||
let completions = conn1.pager.write().cacheflush().unwrap();
|
||||
let completions = conn1.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
|
||||
// Run passive checkpoint, expect partial
|
||||
let (res1, max_before) = {
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let res = run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -2793,13 +2793,13 @@ pub mod test {
|
||||
);
|
||||
// Release reader
|
||||
{
|
||||
let pager = conn2.pager.write();
|
||||
let pager = conn2.pager.load();
|
||||
let wal2 = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal2.end_read_tx();
|
||||
}
|
||||
|
||||
// Second passive checkpoint should finish
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let res2 = run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -2823,7 +2823,7 @@ pub mod test {
|
||||
// Start a read transaction
|
||||
conn2
|
||||
.pager
|
||||
.write()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -2833,7 +2833,7 @@ pub mod test {
|
||||
|
||||
// checkpoint should succeed here because the wal is fully checkpointed (empty)
|
||||
// so the reader is using readmark0 to read directly from the db file.
|
||||
let p = conn1.pager.read();
|
||||
let p = conn1.pager.load();
|
||||
let mut w = p.wal.as_ref().unwrap().borrow_mut();
|
||||
loop {
|
||||
match w.checkpoint(&p, CheckpointMode::Restart) {
|
||||
@@ -2850,7 +2850,7 @@ pub mod test {
|
||||
}
|
||||
}
|
||||
drop(w);
|
||||
conn2.pager.write().end_read_tx();
|
||||
conn2.pager.load().end_read_tx();
|
||||
|
||||
conn1
|
||||
.execute("create table test(id integer primary key, value text)")
|
||||
@@ -2861,8 +2861,8 @@ pub mod test {
|
||||
.unwrap();
|
||||
}
|
||||
// now that we have some frames to checkpoint, try again
|
||||
conn2.pager.write().begin_read_tx().unwrap();
|
||||
let p = conn1.pager.read();
|
||||
conn2.pager.load().begin_read_tx().unwrap();
|
||||
let p = conn1.pager.load();
|
||||
let mut w = p.wal.as_ref().unwrap().borrow_mut();
|
||||
loop {
|
||||
match w.checkpoint(&p, CheckpointMode::Restart) {
|
||||
@@ -2894,7 +2894,7 @@ pub mod test {
|
||||
bulk_inserts(&conn, 10, 5);
|
||||
// Checkpoint with restart
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let result = run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Restart);
|
||||
assert!(result.everything_backfilled());
|
||||
@@ -2935,7 +2935,7 @@ pub mod test {
|
||||
|
||||
// R1 starts reading
|
||||
let r1_max_frame = {
|
||||
let pager = conn_r1.pager.write();
|
||||
let pager = conn_r1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_read_tx().unwrap();
|
||||
wal.get_max_frame()
|
||||
@@ -2944,7 +2944,7 @@ pub mod test {
|
||||
|
||||
// R2 starts reading, sees more frames than R1
|
||||
let r2_max_frame = {
|
||||
let pager = conn_r2.pager.write();
|
||||
let pager = conn_r2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_read_tx().unwrap();
|
||||
wal.get_max_frame()
|
||||
@@ -2952,7 +2952,7 @@ pub mod test {
|
||||
|
||||
// try passive checkpoint, should only checkpoint up to R1's position
|
||||
let checkpoint_result = {
|
||||
let pager = conn_writer.pager.read();
|
||||
let pager = conn_writer.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -2976,7 +2976,7 @@ pub mod test {
|
||||
assert_eq!(
|
||||
conn_r2
|
||||
.pager
|
||||
.read()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -3001,7 +3001,7 @@ pub mod test {
|
||||
let max_frame_before = wal_shared.read().max_frame.load(Ordering::SeqCst);
|
||||
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let _result = run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3034,7 +3034,7 @@ pub mod test {
|
||||
|
||||
// start a write transaction
|
||||
{
|
||||
let pager = conn2.pager.write();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let _ = wal.begin_read_tx().unwrap();
|
||||
wal.begin_write_tx().unwrap();
|
||||
@@ -3042,7 +3042,7 @@ pub mod test {
|
||||
|
||||
// should fail because writer lock is held
|
||||
let result = {
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.checkpoint(&pager, CheckpointMode::Restart)
|
||||
};
|
||||
@@ -3054,7 +3054,7 @@ pub mod test {
|
||||
|
||||
conn2
|
||||
.pager
|
||||
.read()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -3063,7 +3063,7 @@ pub mod test {
|
||||
// release write lock
|
||||
conn2
|
||||
.pager
|
||||
.read()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -3072,7 +3072,7 @@ pub mod test {
|
||||
|
||||
// now restart should succeed
|
||||
let result = {
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Restart)
|
||||
};
|
||||
@@ -3090,13 +3090,13 @@ pub mod test {
|
||||
.unwrap();
|
||||
|
||||
// Attempt to start a write transaction without a read transaction
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let _ = wal.begin_write_tx();
|
||||
}
|
||||
|
||||
fn check_read_lock_slot(conn: &Arc<Connection>, expected_slot: usize) -> bool {
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let wal = pager.wal.as_ref().unwrap().borrow();
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
@@ -3124,7 +3124,7 @@ pub mod test {
|
||||
stmt.step().unwrap();
|
||||
let frame = conn
|
||||
.pager
|
||||
.read()
|
||||
.load()
|
||||
.wal
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@@ -3152,7 +3152,7 @@ pub mod test {
|
||||
|
||||
// passive checkpoint #1
|
||||
let result1 = {
|
||||
let pager = conn_writer.pager.read();
|
||||
let pager = conn_writer.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3169,7 +3169,7 @@ pub mod test {
|
||||
|
||||
// passive checkpoint #2
|
||||
let result2 = {
|
||||
let pager = conn_writer.pager.read();
|
||||
let pager = conn_writer.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3218,7 +3218,7 @@ pub mod test {
|
||||
|
||||
// Do a TRUNCATE checkpoint
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3279,7 +3279,7 @@ pub mod test {
|
||||
|
||||
// Do a TRUNCATE checkpoint
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3317,7 +3317,7 @@ pub mod test {
|
||||
assert_eq!(hdr.page_size, 4096, "invalid page size");
|
||||
assert_eq!(hdr.checkpoint_seq, 1, "invalid checkpoint_seq");
|
||||
{
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3367,7 +3367,7 @@ pub mod test {
|
||||
.unwrap();
|
||||
// Start a read transaction on conn2
|
||||
{
|
||||
let pager = conn2.pager.write();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_read_tx().unwrap();
|
||||
}
|
||||
@@ -3375,7 +3375,7 @@ pub mod test {
|
||||
bulk_inserts(&conn1, 5, 5);
|
||||
// Try to start a write transaction on conn2 with a stale snapshot
|
||||
let result = {
|
||||
let pager = conn2.pager.read();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_write_tx()
|
||||
};
|
||||
@@ -3384,14 +3384,14 @@ pub mod test {
|
||||
|
||||
// End read transaction and start a fresh one
|
||||
{
|
||||
let pager = conn2.pager.read();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.end_read_tx();
|
||||
wal.begin_read_tx().unwrap();
|
||||
}
|
||||
// Now write transaction should work
|
||||
let result = {
|
||||
let pager = conn2.pager.read();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_write_tx()
|
||||
};
|
||||
@@ -3410,7 +3410,7 @@ pub mod test {
|
||||
bulk_inserts(&conn1, 5, 5);
|
||||
// Do a full checkpoint to move all data to DB file
|
||||
{
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(
|
||||
&mut *wal,
|
||||
@@ -3423,14 +3423,14 @@ pub mod test {
|
||||
|
||||
// Start a read transaction on conn2
|
||||
{
|
||||
let pager = conn2.pager.write();
|
||||
let pager = conn2.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_read_tx().unwrap();
|
||||
}
|
||||
// should use slot 0, as everything is backfilled
|
||||
assert!(check_read_lock_slot(&conn2, 0));
|
||||
{
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let wal = pager.wal.as_ref().unwrap().borrow();
|
||||
let frame = wal.find_frame(5, None);
|
||||
// since we hold readlock0, we should ignore the db file and find_frame should return none
|
||||
@@ -3438,7 +3438,7 @@ pub mod test {
|
||||
}
|
||||
// Try checkpoint, should fail because reader has slot 0
|
||||
{
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let result = wal.checkpoint(&pager, CheckpointMode::Restart);
|
||||
|
||||
@@ -3449,12 +3449,12 @@ pub mod test {
|
||||
}
|
||||
// End the read transaction
|
||||
{
|
||||
let pager = conn2.pager.read();
|
||||
let pager = conn2.pager.load();
|
||||
let wal = pager.wal.as_ref().unwrap().borrow();
|
||||
wal.end_read_tx();
|
||||
}
|
||||
{
|
||||
let pager = conn1.pager.read();
|
||||
let pager = conn1.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
let result = run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Restart);
|
||||
assert!(
|
||||
@@ -3475,7 +3475,7 @@ pub mod test {
|
||||
bulk_inserts(&conn, 8, 4);
|
||||
|
||||
// Ensure frames are flushed to the WAL
|
||||
let completions = conn.pager.write().cacheflush().unwrap();
|
||||
let completions = conn.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
@@ -3487,7 +3487,7 @@ pub mod test {
|
||||
|
||||
// Run FULL checkpoint - must backfill *all* frames up to mx_before
|
||||
let result = {
|
||||
let pager = conn.pager.read();
|
||||
let pager = conn.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Full)
|
||||
};
|
||||
@@ -3508,26 +3508,26 @@ pub mod test {
|
||||
|
||||
// First commit some data and flush (reader will snapshot here)
|
||||
bulk_inserts(&writer, 2, 3);
|
||||
let completions = writer.pager.write().cacheflush().unwrap();
|
||||
let completions = writer.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
|
||||
// Start a read transaction pinned at the current snapshot
|
||||
{
|
||||
let pager = reader.pager.write();
|
||||
let pager = reader.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
wal.begin_read_tx().unwrap();
|
||||
}
|
||||
let r_snapshot = {
|
||||
let pager = reader.pager.read();
|
||||
let pager = reader.pager.load();
|
||||
let wal = pager.wal.as_ref().unwrap().borrow();
|
||||
wal.get_max_frame()
|
||||
};
|
||||
|
||||
// Advance WAL beyond the reader's snapshot
|
||||
bulk_inserts(&writer, 3, 4);
|
||||
let completions = writer.pager.write().cacheflush().unwrap();
|
||||
let completions = writer.pager.load().cacheflush().unwrap();
|
||||
for c in completions {
|
||||
db.io.wait_for_completion(c).unwrap();
|
||||
}
|
||||
@@ -3536,7 +3536,7 @@ pub mod test {
|
||||
|
||||
// FULL must return Busy while a reader is stuck behind
|
||||
{
|
||||
let pager = writer.pager.read();
|
||||
let pager = writer.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
loop {
|
||||
match wal.checkpoint(&pager, CheckpointMode::Full) {
|
||||
@@ -3554,13 +3554,13 @@ pub mod test {
|
||||
|
||||
// Release the reader, now full mode should succeed and backfill everything
|
||||
{
|
||||
let pager = reader.pager.read();
|
||||
let pager = reader.pager.load();
|
||||
let wal = pager.wal.as_ref().unwrap().borrow();
|
||||
wal.end_read_tx();
|
||||
}
|
||||
|
||||
let result = {
|
||||
let pager = writer.pager.read();
|
||||
let pager = writer.pager.load();
|
||||
let mut wal = pager.wal.as_ref().unwrap().borrow_mut();
|
||||
run_checkpoint_until_done(&mut *wal, &pager, CheckpointMode::Full)
|
||||
};
|
||||
|
||||
@@ -408,7 +408,7 @@ pub fn op_checkpoint_inner(
|
||||
let step_result = program
|
||||
.connection
|
||||
.pager
|
||||
.write()
|
||||
.load()
|
||||
.wal_checkpoint_start(*checkpoint_mode);
|
||||
match step_result {
|
||||
Ok(IOResult::Done(result)) => {
|
||||
@@ -429,7 +429,7 @@ pub fn op_checkpoint_inner(
|
||||
let step_result = program
|
||||
.connection
|
||||
.pager
|
||||
.write()
|
||||
.load()
|
||||
.wal_checkpoint_finish(result.as_mut().unwrap());
|
||||
match step_result {
|
||||
Ok(IOResult::Done(())) => {
|
||||
@@ -7692,7 +7692,7 @@ pub fn op_open_ephemeral(
|
||||
let page_size =
|
||||
return_if_io!(with_header(pager, mv_store, program, |header| header.page_size));
|
||||
let conn = program.connection.clone();
|
||||
let io = conn.pager.read().io.clone();
|
||||
let io = conn.pager.load().io.clone();
|
||||
let rand_num = io.generate_random_number();
|
||||
let db_file;
|
||||
let db_file_io: Arc<dyn crate::IO>;
|
||||
|
||||
Reference in New Issue
Block a user