backup: replace ChunkIterator

Instead we just build the iterator using our
tools::fs::read_subdir iterator as follows:
Use the index range (0..0x10000) as an iterator, map() it
to yield a subdirectory iterator for each index, then
flatten it.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-02-13 15:51:27 +01:00
parent 121f18efb7
commit c7f481b642
1 changed files with 32 additions and 109 deletions

View File

@ -7,10 +7,9 @@ use openssl::sha;
use std::sync::Mutex;
use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::io::AsRawFd;
use crate::tools;
use crate::tools::borrow::Tied;
pub struct GarbageCollectionStatus {
pub used_bytes: usize,
@ -58,99 +57,6 @@ fn digest_to_prefix(digest: &[u8]) -> PathBuf {
path.into()
}
// This is one thing which would actually get nicer with futures & tokio-fs...
pub struct ChunkIterator {
base_dir: nix::dir::Dir,
index: usize,
subdir: Option<
Tied<nix::dir::Dir, Iterator<Item = nix::Result<nix::dir::Entry>>>
>,
subdir_fd: RawFd,
progress: Option<fn(u8)>,
}
impl ChunkIterator {
fn new(base_dir: nix::dir::Dir) -> Self {
ChunkIterator {
base_dir,
index: 0,
subdir: None,
subdir_fd: 0,
progress: None,
}
}
fn with_progress(base_dir: nix::dir::Dir, progress: fn(u8)) -> Self {
let mut me = Self::new(base_dir);
me.progress = Some(progress);
me
}
fn next_subdir(&mut self) -> Result<bool, Error> {
if self.index == 0x10000 {
return Ok(false);
}
let l1name = PathBuf::from(format!("{:04x}", self.index));
self.index += 1;
if let Some(cb) = self.progress {
let prev = ((self.index-1) * 100) / 0x10000;
let now = (self.index * 100) / 0x10000;
if prev != now {
cb(now as u8);
}
}
use nix::dir::{Dir, Entry};
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
match Dir::openat(self.base_dir.as_raw_fd(), &l1name, OFlag::O_RDONLY, Mode::empty()) {
Ok(dir) => {
self.subdir_fd = dir.as_raw_fd();
self.subdir = Some(Tied::new(dir, |dir| {
Box::new(unsafe { (*dir).iter() })
as Box<Iterator<Item = nix::Result<Entry>>>
}));
return Ok(true);
}
Err(err) => {
self.index = 0x10000;
bail!("unable to open chunk dir {:?}: {}", l1name, err);
}
}
}
}
impl Iterator for ChunkIterator {
type Item = Result<(RawFd, nix::dir::Entry), Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.subdir {
None => {
match self.next_subdir() {
Ok(true) => continue, // Enter the Some case
Ok(false) => return None,
Err(e) => return Some(Err(e)),
}
}
Some(ref mut dir) => {
let dir = dir.as_mut();
match dir.next() {
Some(Ok(entry)) => return Some(Ok((self.subdir_fd, entry))),
Some(Err(e)) => return Some(Err(e.into())),
None => {
// Go to the next directory
self.subdir = None;
continue;
}
}
}
}
}
}
}
impl ChunkStore {
fn chunk_dir<P: AsRef<Path>>(path: P) -> PathBuf {
@ -285,6 +191,33 @@ impl ChunkStore {
Ok(())
}
pub fn get_chunk_iterator<'a>(
base_handle: &'a nix::dir::Dir,
) -> impl Iterator<Item = Result<tools::fs::ReadDirEntry, Error>> + 'a {
let mut verbose = true;
let mut last_percentage = 0;
(0..0x10000).filter_map(move |index| {
let percentage = (index * 100) / 0x10000;
if last_percentage != percentage {
last_percentage = percentage;
eprintln!("percentage done: {}", percentage);
}
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),
}
})
.flatten()
}
pub fn sweep_unused_chunks(&self, status: &mut GarbageCollectionStatus) -> Result<(), Error> {
use nix::dir::Dir;
@ -299,22 +232,12 @@ impl ChunkStore {
self.name, self.chunk_dir, err),
};
let mut verbose = true;
let now = unsafe { libc::time(std::ptr::null_mut()) };
let iter = ChunkIterator::with_progress(
base_handle,
|p| eprintln!("percentage done: {}", p),
);
for entry in iter {
for entry in Self::get_chunk_iterator(&base_handle) {
let (dirfd, entry) = match entry {
Ok(entry) => entry,
Err(e) => {
if verbose {
eprintln!("Error iterating through chunks: {}", e);
verbose = false;
}
continue; // ignore
}
Ok(entry) => (entry.parent_fd(), entry),
Err(_) => continue, // ignore errors
};
let file_type = match entry.file_type() {