datastore: implement Iterator for backup group listing

While currently it's still only used in a collected() way, most call
sites can be switched over to use the iterator directly, as often
they already convert the not-so-cheap, in-memory vector back in
.into_iter() anyway.

somewhat also preparatory (yak shaving) work for namespaces

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2022-04-15 11:02:36 +02:00
parent 72f8154571
commit de015ce7e1
2 changed files with 74 additions and 29 deletions

View File

@ -554,34 +554,7 @@ impl DataStore {
/// Get a in-memory vector for all top-level backup groups of a datatstore
pub fn list_backup_groups(&self) -> Result<Vec<BackupGroup>, Error> {
let mut list = Vec::new();
proxmox_sys::fs::scandir(
libc::AT_FDCWD,
&self.base_path(),
&BACKUP_TYPE_REGEX,
|l0_fd, backup_type, file_type| {
if file_type != nix::dir::Type::Directory {
return Ok(());
}
proxmox_sys::fs::scandir(
l0_fd,
backup_type,
&BACKUP_ID_REGEX,
|_, backup_id, file_type| {
if file_type != nix::dir::Type::Directory {
return Ok(());
}
list.push(BackupGroup::new(backup_type, backup_id));
Ok(())
},
)
},
)?;
Ok(list)
ListGroups::new(self.base_path())?.collect()
}
pub fn list_images(&self) -> Result<Vec<PathBuf>, Error> {
@ -1065,3 +1038,75 @@ impl DataStore {
Ok(chunk_list)
}
}
/// A iterator for a (single) level of Backup Groups
pub struct ListGroups {
type_fd: proxmox_sys::fs::ReadDir,
id_state: Option<(String, proxmox_sys::fs::ReadDir)>,
}
impl ListGroups {
pub fn new(base_path: PathBuf) -> Result<Self, Error> {
Ok(ListGroups {
type_fd: proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &base_path)?,
id_state: None,
})
}
}
impl Iterator for ListGroups {
type Item = Result<BackupGroup, Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((ref group_type, ref mut id_fd)) = self.id_state {
let item = match id_fd.next() {
Some(item) => item,
None => {
self.id_state = None;
continue; // exhausted all IDs for the current group type, try others
}
};
match item {
Ok(ref entry) => {
if let Ok(name) = entry.file_name().to_str() {
match entry.file_type() {
Some(nix::dir::Type::Directory) => {} // OK
_ => continue,
}
if BACKUP_ID_REGEX.is_match(name) {
return Some(Ok(BackupGroup::new(group_type, name)));
}
}
continue; // file did not match regex or isn't valid utf-8
}
Err(err) => return Some(Err(err)),
}
} else {
let item = self.type_fd.next()?;
match item {
Ok(ref entry) => {
if let Ok(name) = entry.file_name().to_str() {
match entry.file_type() {
Some(nix::dir::Type::Directory) => {} // OK
_ => continue,
}
if BACKUP_TYPE_REGEX.is_match(name) {
// found a backup group type, descend into it to scan all IDs in it
// by switching to the id-state branch
let base_fd = entry.parent_fd();
let id_dirfd = match proxmox_sys::fs::read_subdir(base_fd, name) {
Ok(dirfd) => dirfd,
Err(err) => return Some(Err(err.into())),
};
self.id_state = Some((name.to_owned(), id_dirfd));
}
}
continue; // file did not match regex or isn't valid utf-8
}
Err(err) => return Some(Err(err)),
}
}
}
}
}

View File

@ -204,7 +204,7 @@ pub use manifest::BackupManifest;
pub use store_progress::StoreProgress;
mod datastore;
pub use datastore::{check_backup_owner, DataStore};
pub use datastore::{check_backup_owner, DataStore, ListGroups};
mod snapshot_reader;
pub use snapshot_reader::SnapshotReader;