|
|
|
@ -81,39 +81,46 @@ impl IChunker for FastCdcChunker {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(unknown_lints,explicit_counter_loop)]
|
|
|
|
|
#[allow(unknown_lints,explicit_counter_loop,needless_range_loop)]
|
|
|
|
|
fn chunk<R: Read, W: Write>(&mut self, r: &mut R, mut w: &mut W) -> Result<ChunkerStatus, ChunkerError> {
|
|
|
|
|
let mut max;
|
|
|
|
|
let mut hash = 0u64;
|
|
|
|
|
let mut pos = 0;
|
|
|
|
|
let gear = &self.gear;
|
|
|
|
|
let buffer = &mut self.buffer;
|
|
|
|
|
let min_size = self.min_size;
|
|
|
|
|
let mask_short = self.mask_short;
|
|
|
|
|
let mask_long = self.mask_long;
|
|
|
|
|
let avg_size = self.avg_size;
|
|
|
|
|
let max_size = self.max_size;
|
|
|
|
|
loop {
|
|
|
|
|
// Fill the buffer, there might be some bytes still in there from last chunk
|
|
|
|
|
max = try!(r.read(&mut self.buffer[self.buffered..]).map_err(ChunkerError::Read)) + self.buffered;
|
|
|
|
|
max = try!(r.read(&mut buffer[self.buffered..]).map_err(ChunkerError::Read)) + self.buffered;
|
|
|
|
|
// If nothing to do, finish
|
|
|
|
|
if max == 0 {
|
|
|
|
|
return Ok(ChunkerStatus::Finished)
|
|
|
|
|
}
|
|
|
|
|
for i in 0..max {
|
|
|
|
|
if pos >= self.min_size {
|
|
|
|
|
if pos >= min_size {
|
|
|
|
|
// Hash update
|
|
|
|
|
hash = (hash << 1).wrapping_add(self.gear[self.buffer[i] as usize]);
|
|
|
|
|
hash = (hash << 1).wrapping_add(gear[buffer[i] as usize]);
|
|
|
|
|
// 3 options for break point
|
|
|
|
|
// 1) mask_short matches and chunk is smaller than average
|
|
|
|
|
// 2) mask_long matches and chunk is longer or equal to average
|
|
|
|
|
// 3) chunk reached max_size
|
|
|
|
|
if pos < self.avg_size && hash & self.mask_short == 0
|
|
|
|
|
|| pos >= self.avg_size && hash & self.mask_long == 0
|
|
|
|
|
|| pos >= self.max_size {
|
|
|
|
|
if pos < avg_size && hash & mask_short == 0
|
|
|
|
|
|| pos >= avg_size && hash & mask_long == 0
|
|
|
|
|
|| pos >= max_size {
|
|
|
|
|
// Write all bytes from this chunk out to sink and store rest for next chunk
|
|
|
|
|
try!(w.write_all(&self.buffer[..i+1]).map_err(ChunkerError::Write));
|
|
|
|
|
unsafe { ptr::copy(self.buffer[i+1..].as_ptr(), self.buffer.as_mut_ptr(), max-i-1) };
|
|
|
|
|
try!(w.write_all(&buffer[..i+1]).map_err(ChunkerError::Write));
|
|
|
|
|
unsafe { ptr::copy(buffer[i+1..].as_ptr(), buffer.as_mut_ptr(), max-i-1) };
|
|
|
|
|
self.buffered = max-i-1;
|
|
|
|
|
return Ok(ChunkerStatus::Continue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pos += 1;
|
|
|
|
|
}
|
|
|
|
|
try!(w.write_all(&self.buffer[..max]).map_err(ChunkerError::Write));
|
|
|
|
|
try!(w.write_all(&buffer[..max]).map_err(ChunkerError::Write));
|
|
|
|
|
self.buffered = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|