Add test
This commit is contained in:
committed by
Julien Cretin
parent
67fa8bee0b
commit
daa16d948f
@@ -453,6 +453,12 @@ impl StoreDriverOn {
|
|||||||
self.apply(StoreOperation::Transaction { updates })
|
self.apply(StoreOperation::Transaction { updates })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies a clear operation to the store and model without interruption.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn clear(&mut self, min_key: usize) -> Result<(), StoreInvariant> {
|
||||||
|
self.apply(StoreOperation::Clear { min_key })
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that the store and model are in sync.
|
/// Checks that the store and model are in sync.
|
||||||
pub fn check(&self) -> Result<(), StoreInvariant> {
|
pub fn check(&self) -> Result<(), StoreInvariant> {
|
||||||
self.recover_check(&[])
|
self.recover_check(&[])
|
||||||
@@ -610,4 +616,12 @@ impl<'a> StoreInterruption<'a> {
|
|||||||
corrupt: Box::new(|_, _| {}),
|
corrupt: Box::new(|_, _| {}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds an interruption without corruption.
|
||||||
|
pub fn pure(delay: usize) -> StoreInterruption<'a> {
|
||||||
|
StoreInterruption {
|
||||||
|
delay,
|
||||||
|
corrupt: Box::new(|_, _| {}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
use persistent_store::{BufferOptions, StoreDriverOff, StoreInterruption, StoreOperation};
|
use persistent_store::{
|
||||||
|
BufferOptions, StoreDriverOff, StoreDriverOn, StoreInterruption, StoreOperation,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn interrupted_overflowing_compaction() {
|
fn interrupted_overflowing_compaction() {
|
||||||
|
let num_pages = 7;
|
||||||
let options = BufferOptions {
|
let options = BufferOptions {
|
||||||
word_size: 4,
|
word_size: 4,
|
||||||
page_size: 32,
|
page_size: 32,
|
||||||
@@ -9,7 +12,6 @@ fn interrupted_overflowing_compaction() {
|
|||||||
max_page_erases: 3,
|
max_page_erases: 3,
|
||||||
strict_mode: true,
|
strict_mode: true,
|
||||||
};
|
};
|
||||||
let num_pages = 7;
|
|
||||||
let mut driver = StoreDriverOff::new(options, num_pages).power_on().unwrap();
|
let mut driver = StoreDriverOff::new(options, num_pages).power_on().unwrap();
|
||||||
let v = driver.model().format().virt_size() as usize;
|
let v = driver.model().format().virt_size() as usize;
|
||||||
let c = driver.model().format().total_capacity() as usize;
|
let c = driver.model().format().total_capacity() as usize;
|
||||||
@@ -39,13 +41,81 @@ fn interrupted_overflowing_compaction() {
|
|||||||
// We trigger 2 interrupted overflowing compactions, which would move the last non-deleted entry
|
// We trigger 2 interrupted overflowing compactions, which would move the last non-deleted entry
|
||||||
// out of the window unless additional compactions are done to restore the overflow.
|
// out of the window unless additional compactions are done to restore the overflow.
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
let interruption = StoreInterruption {
|
match driver.partial_apply(
|
||||||
delay: 0,
|
StoreOperation::Prepare { length: 1 },
|
||||||
corrupt: Box::new(|old, new| old.copy_from_slice(new)),
|
StoreInterruption::pure(1),
|
||||||
};
|
) {
|
||||||
match driver.partial_apply(StoreOperation::Prepare { length: 1 }, interruption) {
|
|
||||||
Ok((None, d)) => driver = d.power_on().unwrap(),
|
Ok((None, d)) => driver = d.power_on().unwrap(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_compaction_with_max_prefix() {
|
||||||
|
let num_pages = 7;
|
||||||
|
let options = BufferOptions {
|
||||||
|
word_size: 4,
|
||||||
|
page_size: 32,
|
||||||
|
max_word_writes: 2,
|
||||||
|
max_page_erases: 3,
|
||||||
|
strict_mode: true,
|
||||||
|
};
|
||||||
|
let mut driver = StoreDriverOff::new(options, num_pages).power_on().unwrap();
|
||||||
|
let max_key = driver.model().format().max_key() as usize;
|
||||||
|
let max_value_len = driver.model().format().max_value_len() as usize;
|
||||||
|
let n = driver.model().format().num_pages() as usize;
|
||||||
|
let v = driver.model().format().virt_size() as usize;
|
||||||
|
let c = driver.model().format().total_capacity() as usize;
|
||||||
|
let q = driver.model().format().virt_page_size() as usize;
|
||||||
|
let m = driver.model().format().max_prefix_len() as usize;
|
||||||
|
let get_tail = |driver: &StoreDriverOn| driver.store().lifetime().unwrap().used();
|
||||||
|
let mut last_tail = 0;
|
||||||
|
let mut check_lifetime = |driver: &StoreDriverOn, used| {
|
||||||
|
last_tail += used;
|
||||||
|
assert_eq!(get_tail(driver), last_tail);
|
||||||
|
};
|
||||||
|
|
||||||
|
// We fill the first page with q + m words of padding. In particular, the last entry overlaps
|
||||||
|
// the next page with m words.
|
||||||
|
for _ in 0..q - 1 {
|
||||||
|
driver.clear(max_key).unwrap();
|
||||||
|
}
|
||||||
|
driver.insert(0, &vec![0; max_value_len]).unwrap();
|
||||||
|
driver.remove(0).unwrap();
|
||||||
|
check_lifetime(&driver, q + m);
|
||||||
|
|
||||||
|
// We fill the store with non-deleted entries making sure the last entry always overlaps the
|
||||||
|
// next page with m words for the first 3 pages.
|
||||||
|
let mut k = 0;
|
||||||
|
for _ in 0..c {
|
||||||
|
let tail = get_tail(&driver);
|
||||||
|
if tail % q == q - 1 && tail < 4 * q {
|
||||||
|
driver.insert(k, &vec![0; max_value_len]).unwrap();
|
||||||
|
} else {
|
||||||
|
driver.insert(k, &[]).unwrap();
|
||||||
|
}
|
||||||
|
k += 1;
|
||||||
|
}
|
||||||
|
// We lost 1 word of lifetime because of compacting the first page.
|
||||||
|
check_lifetime(&driver, c + 1);
|
||||||
|
|
||||||
|
// We fill the store with padding until compaction would trigger.
|
||||||
|
for _ in 0..n - 1 {
|
||||||
|
driver.clear(max_key).unwrap();
|
||||||
|
}
|
||||||
|
check_lifetime(&driver, n - 1);
|
||||||
|
assert_eq!(get_tail(&driver), q + m + v);
|
||||||
|
|
||||||
|
// We interrupt all compactions to check the invariant between each compaction.
|
||||||
|
for _ in 0..n - 1 {
|
||||||
|
match driver.partial_apply(
|
||||||
|
StoreOperation::Clear { min_key: max_key },
|
||||||
|
StoreInterruption::pure(1),
|
||||||
|
) {
|
||||||
|
Ok((None, d)) => driver = d.power_on().unwrap(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_lifetime(&mut driver, c + n - 1);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user