[thin_shrink] Very simple copier implementation

This commit is contained in:
Joe Thornber 2020-06-25 16:50:11 +01:00
parent fcf44d46b7
commit 27c6e36f5c
2 changed files with 68 additions and 11 deletions

View File

@ -1,14 +1,59 @@
use anyhow::Result; use anyhow::Result;
use std::fs::OpenOptions;
use std::io::{Seek, SeekFrom, Write, Read};
use std::os::unix::fs::OpenOptionsExt;
pub type Sector = u64; pub type Sector = u64;
#[derive(Debug)]
pub struct Region { pub struct Region {
src: Sector, pub src: Sector,
dest: Sector, pub dest: Sector,
len: Sector, pub len: Sector,
}
fn copy_step<W>(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<W>(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<Region>) -> 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)?;
} }
// FIXME: pass in
pub fn copy(path: &str, regions: &Vec<Region>) -> Result<()> {
Ok(()) Ok(())
} }

View File

@ -19,6 +19,7 @@ struct Pass1 {
/// High blocks are beyond the new, reduced end of the pool. These /// High blocks are beyond the new, reduced end of the pool. These
/// will need to be moved. /// will need to be moved.
nr_high_blocks: u64, nr_high_blocks: u64,
block_size: Option<u64>,
} }
impl Pass1 { impl Pass1 {
@ -27,6 +28,7 @@ impl Pass1 {
allocated_blocks: FixedBitSet::with_capacity(0), allocated_blocks: FixedBitSet::with_capacity(0),
nr_blocks, nr_blocks,
nr_high_blocks: 0, nr_high_blocks: 0,
block_size: None,
} }
} }
} }
@ -34,6 +36,7 @@ impl Pass1 {
impl xml::MetadataVisitor for Pass1 { impl xml::MetadataVisitor for Pass1 {
fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<()> { fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<()> {
self.allocated_blocks.grow(sb.nr_data_blocks as usize); self.allocated_blocks.grow(sb.nr_data_blocks as usize);
self.block_size = Some(sb.data_block_size as u64);
Ok(()) Ok(())
} }
@ -414,8 +417,17 @@ mod tests {
} }
} }
fn build_copy_regions(remaps: &Vec<(BlockRange, BlockRange)>) -> Vec<Region> { fn build_copy_regions(remaps: &Vec<(BlockRange, BlockRange)>, block_size: u64) -> Vec<Region> {
let rs = Vec::new(); 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 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); let remaps = build_remaps(above, free);
eprintln!("remappings {:?}.", remaps); eprintln!("remappings {:?}.", remaps);
let regions = build_copy_regions(&remaps); let regions = build_copy_regions(&remaps, pass1.block_size.unwrap() as u64);
eprint!("Copying data..."); //eprint!("Copying data...");
copier::copy(data_path, &regions); copier::copy(data_path, &regions)?;
eprintln!("done."); //eprintln!("done.");
let output = OpenOptions::new() let output = OpenOptions::new()
.read(false) .read(false)