storage: Cache VFS RNG for crash simulation

We'll avoid re-initializing the RNG and instead cache it in a
thread-local.
next
Sayan Nandan 6 months ago
parent d7100daf8d
commit b603eb05d3
No known key found for this signature in database
GPG Key ID: 0EBD769024B24F0A

@ -401,7 +401,7 @@ macro_rules! local {
} }
macro_rules! local_mut { macro_rules! local_mut {
($ident:ident, $call:expr) => {{ ($ident:expr, $call:expr) => {{
#[inline(always)] #[inline(always)]
fn _f<T, U>(v: &::std::cell::RefCell<T>, f: impl FnOnce(&mut T) -> U) -> U { fn _f<T, U>(v: &::std::cell::RefCell<T>, f: impl FnOnce(&mut T) -> U) -> U {
f(&mut *v.borrow_mut()) f(&mut *v.borrow_mut())

@ -50,6 +50,7 @@ pub mod vfs_utils {
} }
local!( local!(
static RANDOM_WRITE_CRASH: WriteCrashKind = WriteCrashKind::None; static RANDOM_WRITE_CRASH: WriteCrashKind = WriteCrashKind::None;
pub(super) static RNG: Option<rand::rngs::ThreadRng> = None;
); );
/// WARNING: A random write crash automatically degrades to a [`WriteCrashKind::Zero`] as soon as it completes /// WARNING: A random write crash automatically degrades to a [`WriteCrashKind::Zero`] as soon as it completes
/// to prevent any further data writes (due to retries in /// to prevent any further data writes (due to retries in
@ -204,9 +205,18 @@ impl VFile {
Ok(bytes.len() as _) Ok(bytes.len() as _)
} }
vfs_utils::WriteCrashKind::Random => { vfs_utils::WriteCrashKind::Random => {
let actual_write_length = local_mut!(vfs_utils::RNG, |rng| {
match rng {
Some(ref mut rng) => test_utils::random_number(0, bytes.len(), rng),
None => {
let mut rng_ = rand::thread_rng();
let r = test_utils::random_number(0, bytes.len(), &mut rng_);
*rng = Some(rng_);
r
}
}
});
// write some random part of the buffer into this file // write some random part of the buffer into this file
let mut rng = rand::thread_rng();
let actual_write_length = test_utils::random_number(0, bytes.len(), &mut rng);
if self.pos + actual_write_length > self.data.len() { if self.pos + actual_write_length > self.data.len() {
self.data.resize(self.pos + actual_write_length, 0); self.data.resize(self.pos + actual_write_length, 0);
} }

@ -1531,6 +1531,7 @@ fn emulate_failure_for_rollback(
post_rollback(&db); post_rollback(&db);
RawJournalWriter::close_driver(&mut jrnl).unwrap(); RawJournalWriter::close_driver(&mut jrnl).unwrap();
} }
FileSystem::remove_file(journal_id).unwrap();
} }
#[test] #[test]
@ -1576,41 +1577,45 @@ fn rollback_write_zero_nonempty_log() {
#[test] #[test]
fn rollback_random_write_failure_empty_log() { fn rollback_random_write_failure_empty_log() {
emulate_failure_for_rollback( for _ in 0..100 {
"rollback_random_write_failure_empty_log", emulate_failure_for_rollback(
|db, jrnl| { "rollback_random_write_failure_empty_log",
vfs_utils::debug_enable_random_write_crash(); |db, jrnl| {
let r = db.push(jrnl, "hello, world"); vfs_utils::debug_enable_random_write_crash();
vfs_utils::debug_disable_write_crash(); let r = db.push(jrnl, "hello, world");
r vfs_utils::debug_disable_write_crash();
}, r
|e| match e.kind() { },
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {} |e| match e.kind() {
unexpected => panic!("expected write zero, got {unexpected:?}"), ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
}, unexpected => panic!("expected write zero, got {unexpected:?}"),
|db| assert_eq!(db.data().len(), 0), },
); |db| assert_eq!(db.data().len(), 0),
);
}
} }
#[test] #[test]
fn rollback_random_write_failure_log() { fn rollback_random_write_failure_log() {
emulate_failure_for_rollback( for _ in 0..100 {
"rollback_random_write_failure_log", emulate_failure_for_rollback(
|db, jrnl| { "rollback_random_write_failure_log",
// commit a single "good" event |db, jrnl| {
db.push(jrnl, "my good key")?; // commit a single "good" event
vfs_utils::debug_enable_random_write_crash(); db.push(jrnl, "my good key")?;
let r = db.push(jrnl, "this won't go in"); vfs_utils::debug_enable_random_write_crash();
vfs_utils::debug_disable_write_crash(); let r = db.push(jrnl, "this won't go in");
r vfs_utils::debug_disable_write_crash();
}, r
|e| match e.kind() { },
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {} |e| match e.kind() {
unexpected => panic!("expected write zero, got {unexpected:?}"), ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
}, unexpected => panic!("expected write zero, got {unexpected:?}"),
|db| { },
assert_eq!(db.data().len(), 1); |db| {
assert_eq!(db.data()[0], "my good key") assert_eq!(db.data().len(), 1);
}, assert_eq!(db.data()[0], "my good key")
) },
)
}
} }

Loading…
Cancel
Save