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:
		@ -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() {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user