[thin_shrink] Very simple copier implementation
This commit is contained in:
		| @@ -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, | ||||||
| } | } | ||||||
|  |  | ||||||
| // FIXME: pass in |  | ||||||
| pub fn copy(path: &str, regions: &Vec<Region>) -> Result<()> { | 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)?; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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, ®ions); |     copier::copy(data_path, ®ions)?; | ||||||
|     eprintln!("done."); |     //eprintln!("done."); | ||||||
|  |  | ||||||
|     let output = OpenOptions::new() |     let output = OpenOptions::new() | ||||||
|         .read(false) |         .read(false) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user