[thin_shrink] more test cases
This commit is contained in:
parent
4d7f9c7ddc
commit
470d0b7532
@ -1,4 +1,4 @@
|
|||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -459,8 +459,7 @@ pub fn shrink(
|
|||||||
eprintln!("{} free blocks.", free_blocks);
|
eprintln!("{} free blocks.", free_blocks);
|
||||||
|
|
||||||
if free_blocks < pass1.nr_high_blocks {
|
if free_blocks < pass1.nr_high_blocks {
|
||||||
// FIXME: return error
|
return Err(anyhow!("Insufficient space"));
|
||||||
panic!("Insufficient space");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaps = build_remaps(above, free);
|
let remaps = build_remaps(above, free);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use rand::Rng;
|
use rand::prelude::*;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -32,7 +32,7 @@ struct ThinWriteRef<'a, W: Write + Seek> {
|
|||||||
impl ThinBlock {
|
impl ThinBlock {
|
||||||
fn read_ref<R: Read + Seek>(&self, r: &mut R) -> Result<ThinReadRef> {
|
fn read_ref<R: Read + Seek>(&self, r: &mut R) -> Result<ThinReadRef> {
|
||||||
let mut rr = ThinReadRef {
|
let mut rr = ThinReadRef {
|
||||||
data: vec![0; self.block_size],
|
data: vec![0; self.block_size * 512],
|
||||||
};
|
};
|
||||||
let byte = self.data_block * (self.block_size as u64) * 512;
|
let byte = self.data_block * (self.block_size as u64) * 512;
|
||||||
r.seek(SeekFrom::Start(byte))?;
|
r.seek(SeekFrom::Start(byte))?;
|
||||||
@ -44,7 +44,7 @@ impl ThinBlock {
|
|||||||
ThinWriteRef {
|
ThinWriteRef {
|
||||||
file: w,
|
file: w,
|
||||||
block_byte: self.data_block * (self.block_size as u64) * 512,
|
block_byte: self.data_block * (self.block_size as u64) * 512,
|
||||||
data: vec![0; self.block_size],
|
data: vec![0; self.block_size * 512],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,10 +218,7 @@ impl<'a, W: Write + Seek> ThinVisitor for Stamper<'a, W> {
|
|||||||
fn thin_block(&mut self, b: &ThinBlock) -> Result<()> {
|
fn thin_block(&mut self, b: &ThinBlock) -> Result<()> {
|
||||||
let mut wr = b.zero_ref(self.data_file);
|
let mut wr = b.zero_ref(self.data_file);
|
||||||
let mut gen = Generator::new();
|
let mut gen = Generator::new();
|
||||||
gen.fill_buffer(
|
gen.fill_buffer(self.seed ^ (b.thin_id as u64) ^ b.thin_block, &mut wr.data)?;
|
||||||
self.seed ^ (b.thin_id as u64) ^ b.thin_block,
|
|
||||||
&mut wr.data[0..],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,7 +240,7 @@ impl<'a, R: Read + Seek> ThinVisitor for Verifier<'a, R> {
|
|||||||
fn thin_block(&mut self, b: &ThinBlock) -> Result<()> {
|
fn thin_block(&mut self, b: &ThinBlock) -> Result<()> {
|
||||||
let rr = b.read_ref(self.data_file)?;
|
let rr = b.read_ref(self.data_file)?;
|
||||||
let mut gen = Generator::new();
|
let mut gen = Generator::new();
|
||||||
if !gen.verify_buffer(self.seed ^ (b.thin_id as u64) ^ b.thin_block, &rr.data[0..])? {
|
if !gen.verify_buffer(self.seed ^ (b.thin_id as u64) ^ b.thin_block, &rr.data)? {
|
||||||
return Err(anyhow!("data verify failed for {:?}", b));
|
return Err(anyhow!("data verify failed for {:?}", b));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -322,7 +319,8 @@ fn test_shrink(scenario: &mut dyn Scenario) -> Result<()> {
|
|||||||
let seed = rng.gen::<u64>();
|
let seed = rng.gen::<u64>();
|
||||||
|
|
||||||
stamp(&xml_before, &data_path, seed)?;
|
stamp(&xml_before, &data_path, seed)?;
|
||||||
|
verify(&xml_before, &data_path, seed)?;
|
||||||
|
|
||||||
let new_nr_blocks = scenario.get_new_nr_blocks();
|
let new_nr_blocks = scenario.get_new_nr_blocks();
|
||||||
thinp::shrink::toplevel::shrink(&xml_before, &xml_after, &data_path, new_nr_blocks, true)?;
|
thinp::shrink::toplevel::shrink(&xml_before, &xml_after, &data_path, new_nr_blocks, true)?;
|
||||||
|
|
||||||
@ -435,4 +433,218 @@ fn shrink_single_partial_move() -> Result<()> {
|
|||||||
test_shrink(&mut s)
|
test_shrink(&mut s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_single_total_move() -> Result<()> {
|
||||||
|
let mut s = SingleThinS::new(2048, 1024, 1024 + 2048, 1280);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_insufficient_space() -> Result<()> {
|
||||||
|
let mut s = SingleThinS::new(0, 2048, 3000, 1280);
|
||||||
|
match test_shrink(&mut s) {
|
||||||
|
Ok(_) => Err(anyhow!("Shrink unexpectedly succeeded")),
|
||||||
|
Err(_) => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
struct FragmentedS {
|
||||||
|
nr_thins: u32,
|
||||||
|
thin_size: u64,
|
||||||
|
old_nr_data_blocks: u64,
|
||||||
|
new_nr_data_blocks: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FragmentedS {
|
||||||
|
fn new(nr_thins: u32, thin_size: u64) -> Self {
|
||||||
|
let old_size = (nr_thins as u64) * thin_size;
|
||||||
|
FragmentedS {
|
||||||
|
nr_thins,
|
||||||
|
thin_size,
|
||||||
|
old_nr_data_blocks: (nr_thins as u64) * thin_size,
|
||||||
|
new_nr_data_blocks: old_size * 3 / 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ThinRun {
|
||||||
|
thin_id: u32,
|
||||||
|
thin_begin: u64,
|
||||||
|
len: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Copy)]
|
||||||
|
struct MappedRun {
|
||||||
|
thin_id: u32,
|
||||||
|
thin_begin: u64,
|
||||||
|
data_begin: u64,
|
||||||
|
len: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_runs(thin_id: u32, total_len: u64, run_len: std::ops::Range<u64>) -> Vec<ThinRun> {
|
||||||
|
let mut runs = Vec::new();
|
||||||
|
let mut b = 0u64;
|
||||||
|
while b < total_len {
|
||||||
|
let len = u64::min(
|
||||||
|
total_len - b,
|
||||||
|
thread_rng().gen_range(run_len.start, run_len.end),
|
||||||
|
);
|
||||||
|
runs.push(ThinRun {
|
||||||
|
thin_id: thin_id,
|
||||||
|
thin_begin: b,
|
||||||
|
len,
|
||||||
|
});
|
||||||
|
b += len;
|
||||||
|
}
|
||||||
|
runs
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scenario for FragmentedS {
|
||||||
|
fn generate_xml(&mut self, v: &mut dyn xml::MetadataVisitor) -> Result<()> {
|
||||||
|
// Allocate each thin fully, in runs between 1 and 16.
|
||||||
|
let mut runs = Vec::new();
|
||||||
|
for thin in 0..self.nr_thins {
|
||||||
|
runs.append(&mut mk_runs(thin, self.thin_size, 1..17));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle
|
||||||
|
runs.shuffle(&mut rand::thread_rng());
|
||||||
|
|
||||||
|
// map across the data
|
||||||
|
let mut maps = Vec::new();
|
||||||
|
let mut b = 0;
|
||||||
|
for r in &runs {
|
||||||
|
maps.push(MappedRun {
|
||||||
|
thin_id: r.thin_id,
|
||||||
|
thin_begin: r.thin_begin,
|
||||||
|
data_begin: b,
|
||||||
|
len: r.len,
|
||||||
|
});
|
||||||
|
b += r.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop half the mappings, which leaves us free runs
|
||||||
|
let mut dropped = Vec::new();
|
||||||
|
for i in 0..maps.len() {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
dropped.push(maps[i].clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unshuffle. This isn't strictly necc. but makes the xml
|
||||||
|
// more readable.
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
maps.sort_by(|&l, &r| match l.thin_id.cmp(&r.thin_id) {
|
||||||
|
Ordering::Equal => l.thin_begin.cmp(&r.thin_begin),
|
||||||
|
o => o,
|
||||||
|
});
|
||||||
|
|
||||||
|
// write the xml
|
||||||
|
v.superblock_b(&common_sb(self.old_nr_data_blocks))?;
|
||||||
|
for thin in 0..self.nr_thins {
|
||||||
|
v.device_b(&xml::Device {
|
||||||
|
dev_id: thin,
|
||||||
|
mapped_blocks: self.thin_size,
|
||||||
|
transaction: 0,
|
||||||
|
creation_time: 0,
|
||||||
|
snap_time: 0,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
for m in &dropped {
|
||||||
|
if m.thin_id != thin {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.map(&xml::Map {
|
||||||
|
thin_begin: m.thin_begin,
|
||||||
|
data_begin: m.data_begin,
|
||||||
|
time: 0,
|
||||||
|
len: m.len,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.device_e()?;
|
||||||
|
}
|
||||||
|
v.superblock_e()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_new_nr_blocks(&self) -> u64 {
|
||||||
|
self.new_nr_data_blocks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_fragmented_thin_1() -> Result<()> {
|
||||||
|
let mut s = FragmentedS::new(1, 2048);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_fragmented_thin_2() -> Result<()> {
|
||||||
|
let mut s = FragmentedS::new(2, 2048);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_fragmented_thin_8() -> Result<()> {
|
||||||
|
let mut s = FragmentedS::new(2, 2048);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_fragmented_thin_64() -> Result<()> {
|
||||||
|
let mut s = FragmentedS::new(2, 2048);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Snapshots share mappings, not neccessarily the entire ranges.
|
||||||
|
struct SnapS {
|
||||||
|
len: u64,
|
||||||
|
nr_snaps: u32,
|
||||||
|
|
||||||
|
// Snaps will differ from the origin by this percentage
|
||||||
|
percent_change: usize,
|
||||||
|
old_nr_data_blocks: u64,
|
||||||
|
new_nr_data_blocks: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SnapS {
|
||||||
|
fn new(len: u64, nr_snaps: u32, percent_change: usize) -> Self {
|
||||||
|
let delta = len * (nr_snaps as u64) * (percent_change as u64) / 100;
|
||||||
|
let old_nr_data_blocks = len + 3 * delta;
|
||||||
|
let new_nr_data_blocks = len + 2 * delta;
|
||||||
|
|
||||||
|
SnapS {
|
||||||
|
len,
|
||||||
|
nr_snaps,
|
||||||
|
percent_change,
|
||||||
|
old_nr_data_blocks,
|
||||||
|
new_nr_data_blocks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scenario for SnapS {
|
||||||
|
fn generate_xml(&mut self, v: &mut dyn xml::MetadataVisitor) -> Result<()> {
|
||||||
|
let origin = mk_runs(0, self.len, 8..64);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_new_nr_blocks(&self) -> u64 {
|
||||||
|
self.new_nr_data_blocks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shrink_identical_snap() -> Result<()> {
|
||||||
|
let mut s = SnapS::new(1024, 1, 0);
|
||||||
|
test_shrink(&mut s)
|
||||||
|
}
|
||||||
|
*/
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user