backup/chunk_store: rework chunk iterator

We can now use iter::from_fn() which makes for a much nicer
logic. The only thing better is going to be when we can use
generators with `yield`.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-07-04 10:51:52 +02:00
parent 99168f43e6
commit a3f3e91da2

View File

@ -200,40 +200,68 @@ impl ChunkStore {
self.name, self.chunk_dir, err),
};
let mut verbose = true;
let mut done = false;
let mut inner: Option<tools::fs::ReadDir> = None;
let mut at = 0;
let mut percentage = 0;
Ok(std::iter::from_fn(move || {
if done {
return None;
}
Ok((0..0x10000).filter_map(move |index| {
let percentage = (index * 100) / 0x10000;
let subdir: &str = &format!("{:04x}", index);
match tools::fs::read_subdir(base_handle.as_raw_fd(), subdir) {
Err(e) => {
if verbose {
eprintln!("Error iterating through chunks: {}", e);
verbose = false;
}
None
}
Ok(iter) => Some(iter.map(move |item| (item, percentage))),
}
})
.flatten()
.filter(|(entry, _percentage)| {
// Check that the file name is actually a hash! (64 hex digits)
let entry = match entry {
Err(_) => return true, // pass errors onwards
Ok(ref entry) => entry,
};
loop {
if let Some(ref mut inner) = inner {
match inner.next() {
Some(Ok(entry)) => {
// skip files if they're not a hash
let bytes = entry.file_name().to_bytes();
if bytes.len() != 64 {
return false;
continue;
}
for b in bytes {
if !b.is_ascii_hexdigit() {
return false;
if !bytes.iter().all(u8::is_ascii_hexdigit) {
continue;
}
return Some((Ok(entry), percentage));
}
Some(Err(err)) => {
// stop after first error
done = true;
// and pass the error through:
return Some((Err(err), percentage));
}
None => (), // open next directory
}
}
true
}))
inner = None;
if at == 0x10000 {
done = true;
return None;
}
let subdir: &str = &format!("{:04x}", at);
percentage = (at * 100) / 0x10000;
at += 1;
match tools::fs::read_subdir(base_handle.as_raw_fd(), subdir) {
Ok(dir) => {
inner = Some(dir);
// start reading:
continue;
}
Err(ref err) if err.as_errno() == Some(nix::errno::Errno::ENOENT) => {
// non-existing directories are okay, just keep going:
continue;
}
Err(err) => {
// other errors are fatal, so end our iteration
done = true;
// and pass the error through:
return Some((Err(err.into()), percentage));
}
}
}
}).fuse())
}
pub fn oldest_writer(&self) -> Option<i64> {