backup: add ChunkIterator

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-02-12 10:10:22 +01:00
parent 6ed25cbe3a
commit 4070096c6a
1 changed files with 79 additions and 1 deletions

View File

@ -7,9 +7,10 @@ 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; use std::os::unix::io::{AsRawFd, RawFd};
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,
@ -56,6 +57,83 @@ 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,
}
impl ChunkIterator {
fn new(base_dir: nix::dir::Dir) -> Self {
ChunkIterator {
base_dir,
index: 0,
subdir: None,
subdir_fd: 0,
}
}
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;
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 {