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