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::sync::Mutex; | ||||||
|  |  | ||||||
| use std::fs::File; | use std::fs::File; | ||||||
| use std::os::unix::io::{AsRawFd, RawFd}; | use std::os::unix::io::AsRawFd; | ||||||
|  |  | ||||||
| use crate::tools; | use crate::tools; | ||||||
| use crate::tools::borrow::Tied; |  | ||||||
|  |  | ||||||
| pub struct GarbageCollectionStatus { | pub struct GarbageCollectionStatus { | ||||||
|     pub used_bytes: usize, |     pub used_bytes: usize, | ||||||
| @ -58,99 +57,6 @@ fn digest_to_prefix(digest: &[u8]) -> PathBuf { | |||||||
|     path.into() |     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 { | impl ChunkStore { | ||||||
|  |  | ||||||
|     fn chunk_dir<P: AsRef<Path>>(path: P) -> PathBuf { |     fn chunk_dir<P: AsRef<Path>>(path: P) -> PathBuf { | ||||||
| @ -285,6 +191,33 @@ impl ChunkStore { | |||||||
|         Ok(()) |         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> { |     pub fn sweep_unused_chunks(&self, status: &mut GarbageCollectionStatus) -> Result<(), Error> { | ||||||
|  |  | ||||||
|         use nix::dir::Dir; |         use nix::dir::Dir; | ||||||
| @ -299,22 +232,12 @@ impl ChunkStore { | |||||||
|                               self.name, self.chunk_dir, err), |                               self.name, self.chunk_dir, err), | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let mut verbose = true; |  | ||||||
|         let now = unsafe { libc::time(std::ptr::null_mut()) }; |         let now = unsafe { libc::time(std::ptr::null_mut()) }; | ||||||
|         let iter = ChunkIterator::with_progress( |  | ||||||
|             base_handle, |         for entry in Self::get_chunk_iterator(&base_handle) { | ||||||
|             |p| eprintln!("percentage done: {}", p), |  | ||||||
|         ); |  | ||||||
|         for entry in iter { |  | ||||||
|             let (dirfd, entry) = match entry { |             let (dirfd, entry) = match entry { | ||||||
|                 Ok(entry) => entry, |                 Ok(entry) => (entry.parent_fd(), entry), | ||||||
|                 Err(e) => { |                 Err(_) => continue, // ignore errors | ||||||
|                     if verbose { |  | ||||||
|                         eprintln!("Error iterating through chunks: {}", e); |  | ||||||
|                         verbose = false; |  | ||||||
|                     } |  | ||||||
|                     continue; // ignore |  | ||||||
|                 } |  | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             let file_type = match entry.file_type() { |             let file_type = match entry.file_type() { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user