From c7f481b6425ec4c3a7b51f2eb4eb7b42c24d4b90 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 13 Feb 2019 15:51:27 +0100 Subject: [PATCH] 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 --- src/backup/chunk_store.rs | 141 +++++++++----------------------------- 1 file changed, 32 insertions(+), 109 deletions(-) diff --git a/src/backup/chunk_store.rs b/src/backup/chunk_store.rs index 34d06e40..452ed03f 100644 --- a/src/backup/chunk_store.rs +++ b/src/backup/chunk_store.rs @@ -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>> - >, - subdir_fd: RawFd, - progress: Option, -} - -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 { - 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>> - })); - 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 { - 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>(path: P) -> PathBuf { @@ -285,6 +191,33 @@ impl ChunkStore { Ok(()) } + pub fn get_chunk_iterator<'a>( + base_handle: &'a nix::dir::Dir, + ) -> impl Iterator> + '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() {