mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 00:45:37 +01:00
do not error in op_transaction if page 1 was not allocated
This commit is contained in:
@@ -65,6 +65,10 @@ pub enum LimboError {
|
||||
Conflict(String),
|
||||
#[error("Database schema changed")]
|
||||
SchemaUpdated,
|
||||
#[error(
|
||||
"Database is empty, header does not exist - page 1 should've been allocated before this"
|
||||
)]
|
||||
Page1NotAlloc,
|
||||
#[error("Transaction terminated")]
|
||||
TxTerminated,
|
||||
#[error("Write-write conflict")]
|
||||
|
||||
@@ -42,7 +42,6 @@ mod numeric;
|
||||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
use crate::storage::header_accessor::HeaderRef;
|
||||
use crate::translate::optimizer::optimize_plan;
|
||||
use crate::translate::pragma::TURSO_CDC_DEFAULT_TABLE_NAME;
|
||||
#[cfg(all(feature = "fs", feature = "conn_raw_api"))]
|
||||
@@ -311,9 +310,9 @@ impl Database {
|
||||
let pager = conn.pager.borrow().clone();
|
||||
|
||||
db.with_schema_mut(|schema| {
|
||||
let header_ref = pager.io.block(|| HeaderRef::from_pager(&pager))?;
|
||||
let header = header_ref.borrow();
|
||||
let header_schema_cookie = header.schema_cookie.get();
|
||||
let header_schema_cookie = pager
|
||||
.io
|
||||
.block(|| pager.with_header(|header| header.schema_cookie.get()))?;
|
||||
schema.schema_version = header_schema_cookie;
|
||||
let result = schema
|
||||
.make_from_btree(None, pager.clone(), &syms)
|
||||
|
||||
@@ -28,14 +28,12 @@ use super::wal::CheckpointMode;
|
||||
#[cfg(not(feature = "omit_autovacuum"))]
|
||||
use {crate::io::Buffer as IoBuffer, ptrmap::*};
|
||||
|
||||
struct HeaderRef(PageRef);
|
||||
pub struct HeaderRef(PageRef);
|
||||
|
||||
impl HeaderRef {
|
||||
pub fn from_pager(pager: &Pager) -> Result<IOResult<Self>> {
|
||||
if !pager.db_state.is_initialized() {
|
||||
return Err(LimboError::InternalError(
|
||||
"Database is empty, header does not exist - page 1 should've been allocated before this".to_string()
|
||||
));
|
||||
return Err(LimboError::Page1NotAlloc);
|
||||
}
|
||||
|
||||
let (page, _c) = pager.read_page(DatabaseHeader::PAGE_ID)?;
|
||||
@@ -65,9 +63,7 @@ pub struct HeaderRefMut(PageRef);
|
||||
impl HeaderRefMut {
|
||||
pub fn from_pager(pager: &Pager) -> Result<IOResult<Self>> {
|
||||
if !pager.db_state.is_initialized() {
|
||||
return Err(LimboError::InternalError(
|
||||
"Database is empty, header does not exist - page 1 should've been allocated before this".to_string(),
|
||||
));
|
||||
return Err(LimboError::Page1NotAlloc);
|
||||
}
|
||||
|
||||
let (page, _c) = pager.read_page(DatabaseHeader::PAGE_ID)?;
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::numeric::{NullableInteger, Numeric};
|
||||
use crate::schema::Table;
|
||||
use crate::storage::btree::{integrity_check, IntegrityCheckError, IntegrityCheckState};
|
||||
use crate::storage::database::DatabaseFile;
|
||||
use crate::storage::header_accessor::HeaderRef;
|
||||
use crate::storage::page_cache::DumbLruPageCache;
|
||||
use crate::storage::pager::{AtomicDbState, CreateBTreeFlags, DbState};
|
||||
use crate::storage::sqlite3_ondisk::read_varint;
|
||||
@@ -2009,9 +2008,9 @@ pub fn op_transaction(
|
||||
if state.mv_tx_id.is_none() {
|
||||
// We allocate the first page lazily in the first transaction.
|
||||
return_if_io!(pager.maybe_allocate_page1());
|
||||
let header_ref = pager.io.block(|| HeaderRef::from_pager(&pager))?;
|
||||
let header = header_ref.borrow();
|
||||
let header_schema_cookie = header.schema_cookie.get();
|
||||
let header_schema_cookie = pager
|
||||
.io
|
||||
.block(|| pager.with_header(|header| header.schema_cookie.get()))?;
|
||||
if header_schema_cookie != *schema_cookie {
|
||||
return Err(LimboError::SchemaUpdated);
|
||||
}
|
||||
@@ -2086,12 +2085,22 @@ pub fn op_transaction(
|
||||
}
|
||||
|
||||
// Can only read header if page 1 has been allocated already
|
||||
// begin_write_tx and begin_read_tx guarantee that happens
|
||||
let header_ref = pager.io.block(|| HeaderRef::from_pager(&pager))?;
|
||||
let header = header_ref.borrow();
|
||||
let header_schema_cookie = header.schema_cookie.get();
|
||||
if header_schema_cookie != *schema_cookie {
|
||||
return Err(LimboError::SchemaUpdated);
|
||||
// begin_write_tx that happens, but not begin_read_tx
|
||||
let res = pager
|
||||
.io
|
||||
.block(|| pager.with_header(|header| header.schema_cookie.get()));
|
||||
match res {
|
||||
Ok(header_schema_cookie) => {
|
||||
dbg!(header_schema_cookie, *schema_cookie);
|
||||
if header_schema_cookie != *schema_cookie {
|
||||
return Err(LimboError::SchemaUpdated);
|
||||
}
|
||||
}
|
||||
// This means we are starting a read_tx and we do not have a page 1 yet, so we just continue execution
|
||||
Err(LimboError::Page1NotAlloc) => {}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
|
||||
Reference in New Issue
Block a user