Skip to content

Commit

Permalink
storage: Cache VFS RNG for crash simulation
Browse files Browse the repository at this point in the history
We'll avoid re-initializing the RNG and instead cache it in a
thread-local.
  • Loading branch information
ohsayan committed Apr 7, 2024
1 parent d7100da commit b603eb0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 36 deletions.
2 changes: 1 addition & 1 deletion server/src/engine/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ macro_rules! local {
}

macro_rules! local_mut {
($ident:ident, $call:expr) => {{
($ident:expr, $call:expr) => {{
#[inline(always)]
fn _f<T, U>(v: &::std::cell::RefCell<T>, f: impl FnOnce(&mut T) -> U) -> U {
f(&mut *v.borrow_mut())
Expand Down
14 changes: 12 additions & 2 deletions server/src/engine/storage/common/interface/vfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub mod vfs_utils {
}
local!(
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
/// to prevent any further data writes (due to retries in
Expand Down Expand Up @@ -204,9 +205,18 @@ impl VFile {
Ok(bytes.len() as _)
}
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
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() {
self.data.resize(self.pos + actual_write_length, 0);
}
Expand Down
71 changes: 38 additions & 33 deletions server/src/engine/storage/v2/raw/journal/raw/tests/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,7 @@ fn emulate_failure_for_rollback(
post_rollback(&db);
RawJournalWriter::close_driver(&mut jrnl).unwrap();
}
FileSystem::remove_file(journal_id).unwrap();
}

#[test]
Expand Down Expand Up @@ -1576,41 +1577,45 @@ fn rollback_write_zero_nonempty_log() {

#[test]
fn rollback_random_write_failure_empty_log() {
emulate_failure_for_rollback(
"rollback_random_write_failure_empty_log",
|db, jrnl| {
vfs_utils::debug_enable_random_write_crash();
let r = db.push(jrnl, "hello, world");
vfs_utils::debug_disable_write_crash();
r
},
|e| match e.kind() {
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
unexpected => panic!("expected write zero, got {unexpected:?}"),
},
|db| assert_eq!(db.data().len(), 0),
);
for _ in 0..100 {
emulate_failure_for_rollback(
"rollback_random_write_failure_empty_log",
|db, jrnl| {
vfs_utils::debug_enable_random_write_crash();
let r = db.push(jrnl, "hello, world");
vfs_utils::debug_disable_write_crash();
r
},
|e| match e.kind() {
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
unexpected => panic!("expected write zero, got {unexpected:?}"),
},
|db| assert_eq!(db.data().len(), 0),
);
}
}

#[test]
fn rollback_random_write_failure_log() {
emulate_failure_for_rollback(
"rollback_random_write_failure_log",
|db, jrnl| {
// commit a single "good" event
db.push(jrnl, "my good key")?;
vfs_utils::debug_enable_random_write_crash();
let r = db.push(jrnl, "this won't go in");
vfs_utils::debug_disable_write_crash();
r
},
|e| match e.kind() {
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
unexpected => panic!("expected write zero, got {unexpected:?}"),
},
|db| {
assert_eq!(db.data().len(), 1);
assert_eq!(db.data()[0], "my good key")
},
)
for _ in 0..100 {
emulate_failure_for_rollback(
"rollback_random_write_failure_log",
|db, jrnl| {
// commit a single "good" event
db.push(jrnl, "my good key")?;
vfs_utils::debug_enable_random_write_crash();
let r = db.push(jrnl, "this won't go in");
vfs_utils::debug_disable_write_crash();
r
},
|e| match e.kind() {
ErrorKind::IoError(io) if io.kind() == IoErrorKind::WriteZero => {}
unexpected => panic!("expected write zero, got {unexpected:?}"),
},
|db| {
assert_eq!(db.data().len(), 1);
assert_eq!(db.data()[0], "my good key")
},
)
}
}

0 comments on commit b603eb0

Please sign in to comment.