Skip to content

Commit

Permalink
Panic isn't a clean shutdown
Browse files Browse the repository at this point in the history
When shutting down due to a panic, don't mark the database as clean;
just treat it like a crash and let the recovery code run next time.
This avoids page leaks and possibly other database corruption, depending
on where the panic happens.
  • Loading branch information
mconst authored and cberner committed Nov 1, 2024
1 parent e413256 commit 07ebf79
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/tree_store/page_store/page_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(debug_assertions)]
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

// Regions have a maximum size of 4GiB. A `4GiB - overhead` value is the largest that can be represented,
// because the leaf node format uses 32bit offsets
Expand Down Expand Up @@ -991,6 +992,10 @@ impl TransactionalMemory {

impl Drop for TransactionalMemory {
fn drop(&mut self) {
if thread::panicking() {
return;
}

// Commit any non-durable transactions that are outstanding
if self.read_from_secondary.load(Ordering::Acquire)
&& !self.needs_recovery.load(Ordering::Acquire)
Expand Down Expand Up @@ -1097,4 +1102,22 @@ mod test {
.unwrap();
assert!(db.check_integrity().unwrap());
}

// Make sure the database remains consistent after a panic
#[test]
#[cfg(panic = "unwind")]
fn panic() {
let tmpfile = crate::create_tempfile();
let table_definition: TableDefinition<u32, &[u8]> = TableDefinition::new("x");

let _ = std::panic::catch_unwind(|| {
let db = Database::create(&tmpfile).unwrap();
let txn = db.begin_write().unwrap();
txn.open_table(table_definition).unwrap();
panic!();
});

let mut db = Database::open(tmpfile).unwrap();
assert!(db.check_integrity().unwrap());
}
}

0 comments on commit 07ebf79

Please sign in to comment.