From 27c6e36f5cff99287e6aae47788dfdde5f8b2320 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 25 Jun 2020 16:50:11 +0100 Subject: [PATCH] [thin_shrink] Very simple copier implementation --- src/shrink/copier.rs | 55 ++++++++++++++++++++++++++++++++++++++---- src/shrink/toplevel.rs | 24 +++++++++++++----- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/shrink/copier.rs b/src/shrink/copier.rs index 3df0042..9fca58a 100644 --- a/src/shrink/copier.rs +++ b/src/shrink/copier.rs @@ -1,14 +1,59 @@ use anyhow::Result; +use std::fs::OpenOptions; +use std::io::{Seek, SeekFrom, Write, Read}; +use std::os::unix::fs::OpenOptionsExt; pub type Sector = u64; +#[derive(Debug)] pub struct Region { - src: Sector, - dest: Sector, - len: Sector, + pub src: Sector, + pub dest: Sector, + pub len: Sector, } -// FIXME: pass in -pub fn copy(path: &str, regions: &Vec) -> Result<()> { + +fn copy_step(file: &mut W, src_byte: u64, dest_byte: u64, len: usize) -> Result<()> +where + W: Write + Seek + Read, +{ + let mut buf = vec![0; len]; + file.seek(SeekFrom::Start(src_byte))?; + file.read_exact(&mut buf[0..])?; + file.seek(SeekFrom::Start(dest_byte))?; + file.write_all(&buf)?; + Ok(()) +} + +fn copy_region(file: &mut W, r: &Region) -> Result<()> +where + W: Write + Seek + Read, +{ + const MAX_BYTES: Sector = 1024 * 1024 * 64; + + let src_bytes = r.src * 512; + let dest_bytes = r.dest * 512; + let len_bytes = r.len * 512; + let mut written = 0; + while written != len_bytes { + let step = u64::min(len_bytes - written, MAX_BYTES); + copy_step(file, src_bytes + written, dest_bytes + written, step as usize)?; + written += step; + } + Ok(()) +} + +pub fn copy(path: &str, regions: &Vec) -> Result<()> { + let mut input = OpenOptions::new() + .read(true) + .write(true) + //.custom_flags(libc::O_DIRECT) + .open(path)?; + + for r in regions { + eprintln!("copying {:?}", r); + copy_region(&mut input, r)?; + } + Ok(()) } diff --git a/src/shrink/toplevel.rs b/src/shrink/toplevel.rs index 9aa800b..bddc448 100644 --- a/src/shrink/toplevel.rs +++ b/src/shrink/toplevel.rs @@ -19,6 +19,7 @@ struct Pass1 { /// High blocks are beyond the new, reduced end of the pool. These /// will need to be moved. nr_high_blocks: u64, + block_size: Option, } impl Pass1 { @@ -27,6 +28,7 @@ impl Pass1 { allocated_blocks: FixedBitSet::with_capacity(0), nr_blocks, nr_high_blocks: 0, + block_size: None, } } } @@ -34,6 +36,7 @@ impl Pass1 { impl xml::MetadataVisitor for Pass1 { fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<()> { self.allocated_blocks.grow(sb.nr_data_blocks as usize); + self.block_size = Some(sb.data_block_size as u64); Ok(()) } @@ -414,8 +417,17 @@ mod tests { } } -fn build_copy_regions(remaps: &Vec<(BlockRange, BlockRange)>) -> Vec { - let rs = Vec::new(); +fn build_copy_regions(remaps: &Vec<(BlockRange, BlockRange)>, block_size: u64) -> Vec { + let mut rs = Vec::new(); + + for (from, to) in remaps { + rs.push(Region { + src: from.start * block_size, + dest: to.start * block_size, + len: range_len(&from) * block_size, + }); + } + rs } @@ -467,10 +479,10 @@ pub fn shrink(input_path: &str, output_path: &str, data_path: &str, nr_blocks: u let remaps = build_remaps(above, free); eprintln!("remappings {:?}.", remaps); - let regions = build_copy_regions(&remaps); - eprint!("Copying data..."); - copier::copy(data_path, ®ions); - eprintln!("done."); + let regions = build_copy_regions(&remaps, pass1.block_size.unwrap() as u64); + //eprint!("Copying data..."); + copier::copy(data_path, ®ions)?; + //eprintln!("done."); let output = OpenOptions::new() .read(false)