api-types: add namespace to BackupGroup

Make it easier by adding an helper accepting either group or
directory

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Wolfgang Bumiller
2022-04-21 15:04:59 +02:00
committed by Thomas Lamprecht
parent 42103c467d
commit 8c74349b08
22 changed files with 431 additions and 319 deletions

View File

@ -12,7 +12,7 @@ fn run() -> Result<(), Error> {
let store = unsafe { DataStore::open_path("", &base, None)? };
for group in store.iter_backup_groups()? {
for group in store.iter_backup_groups(Default::default())? {
let group = group?;
println!("found group {}", group);

View File

@ -217,11 +217,10 @@ impl From<BackupGroup> for pbs_api_types::BackupGroup {
}
}
impl std::fmt::Display for BackupGroup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let backup_type = self.backup_type();
let id = self.backup_id();
write!(f, "{}/{}", backup_type, id)
impl fmt::Display for BackupGroup {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.group, f)
}
}
@ -446,8 +445,8 @@ impl From<BackupDir> for pbs_api_types::BackupDir {
}
}
impl std::fmt::Display for BackupDir {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for BackupDir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.dir.group, self.backup_time_string)
}
}

View File

@ -17,8 +17,8 @@ use proxmox_sys::WorkerTaskContext;
use proxmox_sys::{task_log, task_warn};
use pbs_api_types::{
Authid, BackupType, ChunkOrder, DataStoreConfig, DatastoreTuning, GarbageCollectionStatus,
HumanByte, Operation, BACKUP_DATE_REGEX, BACKUP_ID_REGEX, UPID,
Authid, BackupNamespace, BackupType, ChunkOrder, DataStoreConfig, DatastoreTuning,
GarbageCollectionStatus, HumanByte, Operation, BACKUP_DATE_REGEX, BACKUP_ID_REGEX, UPID,
};
use pbs_config::ConfigVersionCache;
@ -348,6 +348,16 @@ impl DataStore {
self.inner.chunk_store.base_path()
}
pub fn namespace_path(&self, ns: &BackupNamespace) -> PathBuf {
let mut path = self.base_path();
path.reserve(ns.path_len());
for part in ns.components() {
path.push("ns");
path.push(part);
}
path
}
/// Cleanup a backup directory
///
/// Removes all files not mentioned in the manifest.
@ -517,6 +527,10 @@ impl DataStore {
) -> Result<(Authid, DirLockGuard), Error> {
// create intermediate path first:
let mut full_path = self.base_path();
for ns in backup_group.ns.components() {
full_path.push("ns");
full_path.push(ns);
}
full_path.push(backup_group.ty.as_str());
std::fs::create_dir_all(&full_path)?;
@ -579,8 +593,11 @@ impl DataStore {
///
/// The iterated item is still a Result that can contain errors from rather unexptected FS or
/// parsing errors.
pub fn iter_backup_groups(self: &Arc<DataStore>) -> Result<ListGroups, Error> {
ListGroups::new(Arc::clone(self))
pub fn iter_backup_groups(
self: &Arc<DataStore>,
ns: BackupNamespace,
) -> Result<ListGroups, Error> {
ListGroups::new(Arc::clone(self), ns)
}
/// Get a streaming iter over top-level backup groups of a datatstore, filtered by Ok results
@ -589,10 +606,11 @@ impl DataStore {
/// logged. Can be useful in iterator chain commands
pub fn iter_backup_groups_ok(
self: &Arc<DataStore>,
ns: BackupNamespace,
) -> Result<impl Iterator<Item = BackupGroup> + 'static, Error> {
let this = Arc::clone(self);
Ok(
ListGroups::new(Arc::clone(&self))?.filter_map(move |group| match group {
ListGroups::new(Arc::clone(&self), ns)?.filter_map(move |group| match group {
Ok(group) => Some(group),
Err(err) => {
log::error!("list groups error on datastore {} - {}", this.name(), err);
@ -605,8 +623,11 @@ impl DataStore {
/// Get a in-memory vector for all top-level backup groups of a datatstore
///
/// NOTE: using the iterator directly is most often more efficient w.r.t. memory usage
pub fn list_backup_groups(self: &Arc<DataStore>) -> Result<Vec<BackupGroup>, Error> {
ListGroups::new(Arc::clone(self))?.collect()
pub fn list_backup_groups(
self: &Arc<DataStore>,
ns: BackupNamespace,
) -> Result<Vec<BackupGroup>, Error> {
ListGroups::new(Arc::clone(self), ns)?.collect()
}
pub fn list_images(&self) -> Result<Vec<PathBuf>, Error> {
@ -1047,11 +1068,16 @@ impl DataStore {
}
/// Open a backup group from this datastore.
pub fn backup_group_from_parts<T>(self: &Arc<Self>, ty: BackupType, id: T) -> BackupGroup
pub fn backup_group_from_parts<T>(
self: &Arc<Self>,
ns: BackupNamespace,
ty: BackupType,
id: T,
) -> BackupGroup
where
T: Into<String>,
{
self.backup_group((ty, id.into()).into())
self.backup_group((ns, ty, id.into()).into())
}
/// Open a backup group from this datastore by backup group path such as `vm/100`.
@ -1069,6 +1095,7 @@ impl DataStore {
/// Open a snapshot (backup directory) from this datastore.
pub fn backup_dir_from_parts<T>(
self: &Arc<Self>,
ns: BackupNamespace,
ty: BackupType,
id: T,
time: i64,
@ -1076,7 +1103,7 @@ impl DataStore {
where
T: Into<String>,
{
self.backup_dir((ty, id.into(), time).into())
self.backup_dir((ns, ty, id.into(), time).into())
}
/// Open a snapshot (backup directory) from this datastore with a cached rfc3339 time string.
@ -1143,15 +1170,19 @@ impl Iterator for ListSnapshots {
/// A iterator for a (single) level of Backup Groups
pub struct ListGroups {
store: Arc<DataStore>,
ns: BackupNamespace,
type_fd: proxmox_sys::fs::ReadDir,
id_state: Option<(BackupType, proxmox_sys::fs::ReadDir)>,
}
impl ListGroups {
pub fn new(store: Arc<DataStore>) -> Result<Self, Error> {
pub fn new(store: Arc<DataStore>, ns: BackupNamespace) -> Result<Self, Error> {
let mut base_path = store.base_path().to_owned();
base_path.push(ns.path());
Ok(ListGroups {
type_fd: proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &store.base_path())?,
type_fd: proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &base_path)?,
store,
ns,
id_state: None,
})
}
@ -1183,7 +1214,7 @@ impl Iterator for ListGroups {
if BACKUP_ID_REGEX.is_match(name) {
return Some(Ok(BackupGroup::new(
Arc::clone(&self.store),
(group_type, name.to_owned()).into(),
(self.ns.clone(), group_type, name.to_owned()).into(),
)));
}
}