use super::{Device, FileDevice, MemoryDevice, PageOps, UpdateList};
use crate::allocator::free_list::{FreeList, SKIPPED_EXP};
use crate::error::PERes;
use std::io::{Read, Write};
use tempfile::Builder;
fn temp_disk_ref(name: &str) -> FileDevice {
FileDevice::new(
Builder::new()
.prefix(name)
.suffix(".persy")
.tempfile()
.unwrap()
.reopen()
.unwrap(),
)
.unwrap()
}
fn create_load_flush_page_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let pg = device.load_page(page).unwrap();
device.flush_page(&mut pg.clone_write()).unwrap();
}
fn set_get_next_free_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_free_page(page).unwrap();
pg.set_next_free(30);
device.flush_free_page(&pg).unwrap();
let pg1 = &mut device.load_free_page(page).unwrap();
let val = pg1.get_next_free();
assert_eq!(val, 30);
}
fn free_page_load_flush_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_free_page(page).unwrap();
pg.set_next_free(30);
pg.set_prev_free(40);
device.flush_free_page(pg).unwrap();
let pg1 = &mut device.load_free_page(page).unwrap();
let val = pg1.get_next_free();
assert_eq!(val, 30);
let val = pg1.get_prev_free();
assert_eq!(val, 40);
}
fn get_size_page_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_page(page).unwrap();
let sz = pg.get_size_exp();
assert_eq!(sz, 5);
}
fn write_read_page_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
{
let pg = &mut device.load_page(page).unwrap().clone_write();
pg.write_all(&[10]).unwrap();
device.flush_page(pg).unwrap();
}
{
let pg = &mut device.load_page(page).unwrap();
let mut data = [0; 1];
pg.read_exact(&mut data).unwrap();
assert_eq!(data[0], 10);
let sz = pg.get_size_exp();
assert_eq!(sz, 5);
}
}
struct PanicCase {}
impl UpdateList for PanicCase {
fn update(&mut self, _: u8, _: u64) -> PERes<u64> {
panic!("should not put the free in the free list")
}
fn remove(&mut self, _: u8, _: u64, _: u64, _: bool) -> PERes<()> {
panic!("should not put the free in the free list")
}
fn remove_last(&mut self, _: u8, _: u64, _: u64, _: bool) -> PERes<()> {
panic!("should not put the free in the free list")
}
}
fn create_load_trim_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_page(page).unwrap().clone_write();
device.flush_page(pg).unwrap();
device.trim_or_free_page(page, &mut PanicCase {}).unwrap();
assert!(device.load_page(page).is_err());
}
fn create_load_two_trim_device(device: &mut dyn Device) {
let _not_free = device.create_page(5).unwrap().get_index();
let page = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_page(page).unwrap().clone_write();
device.flush_page(pg).unwrap();
let page_1 = device.create_page(5).unwrap().get_index();
let pg = &mut device.load_page(page_1).unwrap().clone_write();
device.flush_page(pg).unwrap();
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
device.trim_or_free_page(page_1, &mut IgnoreCase {}).unwrap();
assert!(device.load_page(page).is_err());
}
struct IgnoreCase {}
impl UpdateList for IgnoreCase {
fn update(&mut self, _: u8, _: u64) -> PERes<u64> {
Ok(0)
}
fn remove(&mut self, _: u8, _: u64, _: u64, _: bool) -> PERes<()> {
Ok(())
}
fn remove_last(&mut self, _: u8, _: u64, _: u64, _: bool) -> PERes<()> {
Ok(())
}
}
fn create_not_trim_not_last_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let _page_after = device.create_page(5).unwrap();
let pg = &mut device.load_page(page).unwrap().clone_write();
device.flush_page(pg).unwrap();
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
let load_page = device.load_page(page);
assert!(load_page.is_ok());
assert!(load_page.unwrap().is_free().unwrap());
}
fn create_reuse_page_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let _page_after = device.create_page(5).unwrap();
let pg = &mut device.load_page(page).unwrap().clone_write();
device.flush_page(pg).unwrap();
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
let load_page = device.load_page(page);
assert!(load_page.unwrap().is_free().unwrap());
device.mark_allocated(page).unwrap();
let load_page = device.load_page(page);
assert!(!load_page.unwrap().is_free().unwrap());
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
let load_page = device.load_page(page);
assert!(load_page.is_ok());
assert!(load_page.unwrap().is_free().unwrap());
}
fn create_reuse_trim_page_device(device: &mut dyn Device) {
let page = device.create_page(5).unwrap().get_index();
let free_after = device.create_page(5).unwrap();
let pg = &mut device.load_page(page).unwrap().clone_write();
device.flush_page(pg).unwrap();
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
let load_page = device.load_page(page);
assert!(load_page.unwrap().is_free().unwrap());
device.mark_allocated(page).unwrap();
let load_page = device.load_page(page);
assert!(!load_page.unwrap().is_free().unwrap());
device
.trim_or_free_page(free_after.get_index(), &mut IgnoreCase {})
.unwrap();
device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
let load_page = device.load_page(page);
assert!(load_page.is_err());
}
fn free_tracking_device(device: &mut dyn Device) {
let mut update_list = FreeList::default();
let _first_0 = device.create_page(5).unwrap().get_index();
let page = device.create_page(5).unwrap().get_index();
let second_page = device.create_page(5).unwrap().get_index();
let free_to_clean = device.create_page(5).unwrap().get_index();
device.trim_or_free_page(page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], page);
device.trim_or_free_page(second_page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], second_page);
let next = device.mark_allocated(second_page).unwrap();
assert_eq!(next, 0);
let next = device.mark_allocated(page).unwrap();
assert_eq!(next, second_page);
update_list.heads[5 - SKIPPED_EXP] = 0;
update_list.tails[5 - SKIPPED_EXP] = 0;
device.trim_or_free_page(free_to_clean, &mut update_list).unwrap();
device.trim_or_free_page(page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], page);
device.trim_or_free_page(second_page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], 0);
let load_page = device.load_page(page);
assert!(load_page.is_err());
let load_page = device.load_page_if_exists(page).unwrap();
assert!(load_page.is_none());
let load_page = device.load_page(second_page);
assert!(load_page.is_err());
let load_page = device.load_page_if_exists(second_page).unwrap();
assert!(load_page.is_none());
}
fn free_tracking_on_trim_device(device: &mut dyn Device) {
let mut update_list = FreeList::default();
let _place_older_0 = device.create_page(5).unwrap().get_index();
let first_page = device.create_page(5).unwrap().get_index();
let _second_page = device.create_page(5).unwrap().get_index();
let third_page = device.create_page(5).unwrap().get_index();
let forth_page = device.create_page(5).unwrap().get_index();
device.trim_or_free_page(first_page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], first_page);
assert_eq!(update_list.tails[5 - SKIPPED_EXP], first_page);
device.trim_or_free_page(third_page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], third_page);
assert_eq!(update_list.tails[5 - SKIPPED_EXP], first_page);
device.trim_or_free_page(forth_page, &mut update_list).unwrap();
assert_eq!(update_list.heads[5 - SKIPPED_EXP], first_page);
assert_eq!(update_list.tails[5 - SKIPPED_EXP], first_page);
let load_page = device.load_free_page(first_page).unwrap();
assert_eq!(load_page.get_next_free(), 0);
assert_eq!(load_page.get_prev_free(), 0);
}
#[test]
fn create_load_flush_page_disk() {
create_load_flush_page_device(&mut temp_disk_ref("disk_ref.raw"));
}
#[test]
fn create_load_flush_page_memory() {
create_load_flush_page_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn set_get_next_free_disk() {
set_get_next_free_device(&mut temp_disk_ref("set_free.raw"));
}
#[test]
fn set_get_next_free_memory() {
set_get_next_free_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn get_size_page_disk() {
get_size_page_device(&mut temp_disk_ref("get_size.raw"));
}
#[test]
fn get_size_page_memory() {
get_size_page_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn write_read_page_disk() {
write_read_page_device(&mut temp_disk_ref("write_read.raw"));
}
#[test]
fn write_read_page_memory() {
write_read_page_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn create_load_trim_disk() {
create_load_trim_device(&mut temp_disk_ref("disk_ref_trim.raw"));
}
#[test]
fn create_load_trim_memory() {
create_load_trim_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn create_two_load_trim_disk() {
create_load_two_trim_device(&mut temp_disk_ref("disk_ref_two_trim.raw"));
}
#[test]
fn create_two_load_trim_memory() {
create_load_two_trim_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn create_not_trim_not_last_disk() {
create_not_trim_not_last_device(&mut temp_disk_ref("disk_ref_no_trim.raw"));
}
#[test]
fn create_not_trim_not_last_memory() {
create_not_trim_not_last_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn create_reuse_page_disk() {
create_reuse_page_device(&mut temp_disk_ref("disk_ref_no_trim.raw"));
}
#[test]
fn create_reuse_page_memory() {
create_reuse_page_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn create_reuse_trim_page_disk() {
create_reuse_trim_page_device(&mut temp_disk_ref("disk_ref_no_trim.raw"));
}
#[test]
fn create_reuse_trim_page_memory() {
create_reuse_trim_page_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn free_tracking_disk() {
free_tracking_device(&mut temp_disk_ref("disk_ref_no_trim.raw"));
}
#[test]
fn free_tracking_memory() {
free_tracking_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn free_tracking_on_trim_disk() {
free_tracking_on_trim_device(&mut temp_disk_ref("disk_ref_trim.raw"));
}
#[test]
fn free_tracking_on_trim_memory() {
free_tracking_on_trim_device(&mut MemoryDevice::new(None).unwrap());
}
#[test]
fn free_page_load_flush_disk() {
free_page_load_flush_device(&mut temp_disk_ref("disk_load_flush_free.raw"));
}
#[test]
fn free_page_load_flush_memory() {
free_page_load_flush_device(&mut MemoryDevice::new(None).unwrap());
}