[thin_shrink] Rewrites xml
Just need to do copying now
This commit is contained in:
parent
259eef9eee
commit
d8957e3d86
@ -1,6 +1,7 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use fixedbitset::{FixedBitSet, IndexRange};
|
use fixedbitset::{FixedBitSet, IndexRange};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::Write;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
|
||||||
use crate::shrink::xml;
|
use crate::shrink::xml;
|
||||||
@ -47,7 +48,7 @@ impl xml::MetadataVisitor for Pass1 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&mut self, m: xml::Map) -> Result<()> {
|
fn map(&mut self, m: &xml::Map) -> Result<()> {
|
||||||
for i in m.data_begin..(m.data_begin + m.len) {
|
for i in m.data_begin..(m.data_begin + m.len) {
|
||||||
if i > self.nr_blocks {
|
if i > self.nr_blocks {
|
||||||
self.nr_high_blocks += 1;
|
self.nr_high_blocks += 1;
|
||||||
@ -62,6 +63,80 @@ impl xml::MetadataVisitor for Pass1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------
|
||||||
|
|
||||||
|
// Writes remapped xml
|
||||||
|
struct Pass2<W: Write> {
|
||||||
|
writer: xml::XmlWriter<W>,
|
||||||
|
nr_blocks: u64,
|
||||||
|
remaps: Vec<(BlockRange, BlockRange)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> Pass2<W> {
|
||||||
|
fn new(w: W, nr_blocks: u64, remaps: Vec<(BlockRange, BlockRange)>) -> Pass2<W> {
|
||||||
|
Pass2 {
|
||||||
|
writer: xml::XmlWriter::new(w),
|
||||||
|
nr_blocks,
|
||||||
|
remaps,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(&self, r: BlockRange) -> Vec<BlockRange> {
|
||||||
|
let mut rmap = Vec::new();
|
||||||
|
|
||||||
|
// id
|
||||||
|
rmap.push(r.clone());
|
||||||
|
|
||||||
|
rmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> xml::MetadataVisitor for Pass2<W> {
|
||||||
|
fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<()> {
|
||||||
|
self.writer.superblock_b(sb)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn superblock_e(&mut self) -> Result<()> {
|
||||||
|
self.writer.superblock_e()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_b(&mut self, d: &xml::Device) -> Result<()> {
|
||||||
|
self.writer.device_b(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_e(&mut self) -> Result<()> {
|
||||||
|
self.writer.device_e()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&mut self, m: &xml::Map) -> Result<()> {
|
||||||
|
if m.data_begin + m.len < self.nr_blocks {
|
||||||
|
// no remapping needed.
|
||||||
|
self.writer.map(m)?;
|
||||||
|
} else {
|
||||||
|
let r = m.data_begin..(m.data_begin + m.len);
|
||||||
|
let remaps = remap(&r, &self.remaps);
|
||||||
|
let mut written = 0;
|
||||||
|
|
||||||
|
for r in remaps {
|
||||||
|
self.writer.map(&xml::Map {
|
||||||
|
thin_begin: m.thin_begin + written,
|
||||||
|
data_begin: r.start,
|
||||||
|
time: m.time,
|
||||||
|
len: range_len(&r),
|
||||||
|
})?;
|
||||||
|
written += range_len(&r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eof(&mut self) -> Result<()> {
|
||||||
|
self.writer.eof()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------
|
||||||
type BlockRange = std::ops::Range<u64>;
|
type BlockRange = std::ops::Range<u64>;
|
||||||
|
|
||||||
fn bits_to_ranges(bits: &FixedBitSet) -> Vec<BlockRange> {
|
fn bits_to_ranges(bits: &FixedBitSet) -> Vec<BlockRange> {
|
||||||
@ -141,7 +216,7 @@ fn ranges_total(rs: &Vec<BlockRange>) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assumes there is enough space to remap.
|
// Assumes there is enough space to remap.
|
||||||
fn remap_ranges(ranges: Vec<BlockRange>, free: Vec<BlockRange>) -> Vec<(BlockRange, BlockRange)> {
|
fn build_remaps(ranges: Vec<BlockRange>, free: Vec<BlockRange>) -> Vec<(BlockRange, BlockRange)> {
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
let mut remap = Vec::new();
|
let mut remap = Vec::new();
|
||||||
@ -161,12 +236,12 @@ fn remap_ranges(ranges: Vec<BlockRange>, free: Vec<BlockRange>) -> Vec<(BlockRan
|
|||||||
remap.push((r, f.start..(f.start + rlen)));
|
remap.push((r, f.start..(f.start + rlen)));
|
||||||
f_ = Some((f.start + rlen)..f.end);
|
f_ = Some((f.start + rlen)..f.end);
|
||||||
r_ = range_iter.next();
|
r_ = range_iter.next();
|
||||||
},
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
remap.push((r, f));
|
remap.push((r, f));
|
||||||
r_ = range_iter.next();
|
r_ = range_iter.next();
|
||||||
f_ = free_iter.next();
|
f_ = free_iter.next();
|
||||||
},
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
remap.push((r.start..(r.start + flen), f));
|
remap.push((r.start..(r.start + flen), f));
|
||||||
r_ = Some((r.start + flen)..r.end);
|
r_ = Some((r.start + flen)..r.end);
|
||||||
@ -178,17 +253,184 @@ fn remap_ranges(ranges: Vec<BlockRange>, free: Vec<BlockRange>) -> Vec<(BlockRan
|
|||||||
remap
|
remap
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shrink(input_file: &str, _output_file: &str, nr_blocks: u64) -> Result<()> {
|
fn overlaps(r1: &BlockRange, r2: &BlockRange, index: usize) -> Option<usize> {
|
||||||
|
if r1.start >= r2.end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if r2.start >= r1.end {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds the index of the first entry that overlaps r.
|
||||||
|
fn find_first(r: &BlockRange, remaps: &Vec<(BlockRange, BlockRange)>) -> Option<usize> {
|
||||||
|
if remaps.len() == 0 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
match remaps.binary_search_by_key(&r.start, |(from, _)| from.start) {
|
||||||
|
Ok(n) => Some(n),
|
||||||
|
Err(n) => {
|
||||||
|
if n == 0 {
|
||||||
|
let (from, _) = &remaps[n];
|
||||||
|
overlaps(&r, &from, n)
|
||||||
|
} else if n == remaps.len() {
|
||||||
|
let (from, _) = &remaps[n - 1];
|
||||||
|
overlaps(&r, from, n - 1)
|
||||||
|
} else {
|
||||||
|
// Need to check the previous entry
|
||||||
|
let (from, _) = &remaps[n - 1];
|
||||||
|
overlaps(&r, &from, n - 1).or_else(|| {
|
||||||
|
let (from, to) = &remaps[n];
|
||||||
|
overlaps(&r, &from, n)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(r: &BlockRange) -> bool {
|
||||||
|
r.start == r.end
|
||||||
|
}
|
||||||
|
|
||||||
|
// remaps must be in sorted order by from.start.
|
||||||
|
fn remap(r: &BlockRange, remaps: &Vec<(BlockRange, BlockRange)>) -> Vec<BlockRange> {
|
||||||
|
let mut remap = Vec::new();
|
||||||
|
let mut r = r.start..r.end;
|
||||||
|
|
||||||
|
if let Some(index) = find_first(&r, &remaps) {
|
||||||
|
let mut index = index;
|
||||||
|
loop {
|
||||||
|
let (from, to) = &remaps[index];
|
||||||
|
println!("from = {:?}", from);
|
||||||
|
|
||||||
|
// There may be a prefix that doesn't overlap with 'from'
|
||||||
|
if r.start < from.start {
|
||||||
|
println!("pushing prefix");
|
||||||
|
let len = u64::min(range_len(&r), from.start - r.start);
|
||||||
|
remap.push(r.start..(r.start + len));
|
||||||
|
r = (r.start + len)..r.end;
|
||||||
|
|
||||||
|
if is_empty(&r) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let to = (to.start + (r.start - from.start))..to.end;
|
||||||
|
let from = r.start..from.end;
|
||||||
|
println!("to = {:?}", to);
|
||||||
|
let rlen = range_len(&r);
|
||||||
|
let flen = range_len(&from);
|
||||||
|
|
||||||
|
let len = u64::min(rlen, flen);
|
||||||
|
println!("pushing overlap");
|
||||||
|
remap.push(to.start..(to.start + len));
|
||||||
|
|
||||||
|
r = (r.start + len)..r.end;
|
||||||
|
if is_empty(&r) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if len == flen {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == remaps.len() {
|
||||||
|
remap.push(r.start..r.end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remap.push(r.start..r.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
remap
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remap_test() {
|
||||||
|
struct Test {
|
||||||
|
remaps: Vec<(BlockRange, BlockRange)>,
|
||||||
|
input: BlockRange,
|
||||||
|
output: Vec<BlockRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = [
|
||||||
|
Test {
|
||||||
|
remaps: vec![],
|
||||||
|
input: 0..1,
|
||||||
|
output: vec![0..1],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![],
|
||||||
|
input: 100..1000,
|
||||||
|
output: vec![100..1000],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 0..5,
|
||||||
|
output: vec![0..5],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 10..20,
|
||||||
|
output: vec![110..120],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 5..15,
|
||||||
|
output: vec![5..10, 110..115],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 5..25,
|
||||||
|
output: vec![5..10, 110..120, 20..25],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 15..25,
|
||||||
|
output: vec![115..120, 20..25],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120)],
|
||||||
|
input: 25..35,
|
||||||
|
output: vec![25..35],
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
remaps: vec![(10..20, 110..120), (30..40, 230..240)],
|
||||||
|
input: 0..50,
|
||||||
|
output: vec![0..10, 110..120, 20..30, 230..240, 40..50],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for t in &tests {
|
||||||
|
let rs = remap(&t.input, &t.remaps);
|
||||||
|
assert_eq!(rs, t.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_xml<MV: xml::MetadataVisitor>(input_path: &str, pass: &mut MV) -> Result<()> {
|
||||||
let input = OpenOptions::new()
|
let input = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(false)
|
.write(false)
|
||||||
.custom_flags(libc::O_EXCL)
|
.custom_flags(libc::O_EXCL)
|
||||||
.open(input_file)?;
|
.open(input_path)?;
|
||||||
|
|
||||||
// let mut visitor = xml::XmlWriter::new(std::io::stdout());
|
xml::read(input, pass)?;
|
||||||
// let mut visitor = xml::NoopVisitor::new();
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shrink(input_path: &str, output_path: &str, nr_blocks: u64) -> Result<()> {
|
||||||
let mut pass1 = Pass1::new(nr_blocks);
|
let mut pass1 = Pass1::new(nr_blocks);
|
||||||
xml::read(input, &mut pass1)?;
|
process_xml(input_path, &mut pass1);
|
||||||
eprintln!("{} blocks need moving", pass1.nr_high_blocks);
|
eprintln!("{} blocks need moving", pass1.nr_high_blocks);
|
||||||
|
|
||||||
let mut free_blocks = 0u64;
|
let mut free_blocks = 0u64;
|
||||||
@ -220,9 +462,19 @@ pub fn shrink(input_file: &str, _output_file: &str, nr_blocks: u64) -> Result<()
|
|||||||
panic!("Insufficient space");
|
panic!("Insufficient space");
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaps = remap_ranges(above, free);
|
let remaps = build_remaps(above, free);
|
||||||
eprintln!("remappings {:?}.", remaps);
|
eprintln!("remappings {:?}.", remaps);
|
||||||
|
|
||||||
|
let output = OpenOptions::new()
|
||||||
|
.read(false)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(output_path)?;
|
||||||
|
let mut pass2 = Pass2::new(output, nr_blocks, remaps);
|
||||||
|
eprint!("writing new xml...");
|
||||||
|
process_xml(input_path, &mut pass2)?;
|
||||||
|
eprintln!("done.");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ pub trait MetadataVisitor {
|
|||||||
fn device_b(&mut self, d: &Device) -> Result<()>;
|
fn device_b(&mut self, d: &Device) -> Result<()>;
|
||||||
fn device_e(&mut self) -> Result<()>;
|
fn device_e(&mut self) -> Result<()>;
|
||||||
|
|
||||||
fn map(&mut self, m: Map) -> Result<()>;
|
fn map(&mut self, m: &Map) -> Result<()>;
|
||||||
|
|
||||||
fn eof(&mut self) -> Result<()>;
|
fn eof(&mut self) -> Result<()>;
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ impl MetadataVisitor for NoopVisitor {
|
|||||||
fn device_b(&mut self, _d: &Device) -> Result<()> {Ok(())}
|
fn device_b(&mut self, _d: &Device) -> Result<()> {Ok(())}
|
||||||
fn device_e(&mut self) -> Result<()> {Ok(())}
|
fn device_e(&mut self) -> Result<()> {Ok(())}
|
||||||
|
|
||||||
fn map(&mut self, _m: Map) -> Result<()> {Ok(())}
|
fn map(&mut self, m: &Map) -> Result<()> {Ok(())}
|
||||||
|
|
||||||
fn eof(&mut self) -> Result<()> {Ok(())}
|
fn eof(&mut self) -> Result<()> {Ok(())}
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ impl<W: Write> MetadataVisitor for XmlWriter<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&mut self, m: Map) -> Result<()> {
|
fn map(&mut self, m: &Map) -> Result<()> {
|
||||||
match m.len {
|
match m.len {
|
||||||
1 => {
|
1 => {
|
||||||
let tag = b"single_mapping";
|
let tag = b"single_mapping";
|
||||||
@ -352,8 +352,8 @@ where
|
|||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
Ok(Event::Empty(ref e)) => match e.name() {
|
Ok(Event::Empty(ref e)) => match e.name() {
|
||||||
b"single_mapping" => visitor.map(parse_single_map(e)?)?,
|
b"single_mapping" => visitor.map(&parse_single_map(e)?)?,
|
||||||
b"range_mapping" => visitor.map(parse_range_map(e)?)?,
|
b"range_mapping" => visitor.map(&parse_range_map(e)?)?,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
Ok(Event::Text(_)) => {}
|
Ok(Event::Text(_)) => {}
|
||||||
|
Loading…
Reference in New Issue
Block a user