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:
parent
121f18efb7
commit
c7f481b642
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue