[pbs-devel] [PATCH proxmox-backup v2 05/12] backup_info: add generics and separate functions into impl blocks
Hannes Laimer
h.laimer at proxmox.com
Mon May 26 16:14:38 CEST 2025
Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
pbs-datastore/src/backup_info.rs | 583 ++++++++++++++++---------------
pbs-datastore/src/datastore.rs | 26 +-
2 files changed, 313 insertions(+), 296 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index d4732fdd..f3ca283c 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -18,7 +18,10 @@ use pbs_api_types::{
use pbs_config::{open_backup_lockfile, BackupLockGuard};
use crate::manifest::{BackupManifest, MANIFEST_LOCK_NAME};
-use crate::{DataBlob, DataStore};
+use crate::{
+ chunk_store::{CanRead, CanWrite},
+ DataBlob, DataStore,
+};
pub const DATASTORE_LOCKS_DIR: &str = "/run/proxmox-backup/locks";
@@ -34,14 +37,14 @@ pub(crate) static OLD_LOCKING: LazyLock<bool> = LazyLock::new(|| {
/// BackupGroup is a directory containing a list of BackupDir
#[derive(Clone)]
-pub struct BackupGroup {
- store: Arc<DataStore>,
+pub struct BackupGroup<T> {
+ store: Arc<DataStore<T>>,
ns: BackupNamespace,
group: pbs_api_types::BackupGroup,
}
-impl fmt::Debug for BackupGroup {
+impl<T> fmt::Debug for BackupGroup<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BackupGroup")
.field("store", &self.store.name())
@@ -51,45 +54,12 @@ impl fmt::Debug for BackupGroup {
}
}
-impl BackupGroup {
- pub(crate) fn new(
- store: Arc<DataStore>,
- ns: BackupNamespace,
- group: pbs_api_types::BackupGroup,
- ) -> Self {
- Self { store, ns, group }
- }
-
- /// Access the underlying [`BackupGroup`](pbs_api_types::BackupGroup).
- #[inline]
- pub fn group(&self) -> &pbs_api_types::BackupGroup {
- &self.group
- }
-
- #[inline]
- pub fn backup_ns(&self) -> &BackupNamespace {
- &self.ns
- }
-
- #[inline]
- pub fn backup_type(&self) -> BackupType {
- self.group.ty
- }
-
- #[inline]
- pub fn backup_id(&self) -> &str {
- &self.group.id
- }
-
- pub fn full_group_path(&self) -> PathBuf {
- self.store.group_path(&self.ns, &self.group)
- }
-
- pub fn relative_group_path(&self) -> PathBuf {
- let mut path = self.ns.path();
- path.push(self.group.ty.as_str());
- path.push(&self.group.id);
- path
+impl<T: CanRead> BackupGroup<T> {
+ /// Returns the backup owner.
+ ///
+ /// The backup owner is the entity who first created the backup group.
+ pub fn get_owner(&self) -> Result<Authid, Error> {
+ self.store.get_owner(&self.ns, self.as_ref())
}
/// Simple check whether a group exists. This does not check whether there are any snapshots,
@@ -98,7 +68,7 @@ impl BackupGroup {
self.full_group_path().exists()
}
- pub fn list_backups(&self) -> Result<Vec<BackupInfo>, Error> {
+ pub fn list_backups(&self) -> Result<Vec<BackupInfo<T>>, Error> {
let mut list = vec![];
let path = self.full_group_path();
@@ -130,7 +100,7 @@ impl BackupGroup {
}
/// Finds the latest backup inside a backup group
- pub fn last_backup(&self, only_finished: bool) -> Result<Option<BackupInfo>, Error> {
+ pub fn last_backup(&self, only_finished: bool) -> Result<Option<BackupInfo<T>>, Error> {
let backups = self.list_backups()?;
Ok(backups
.into_iter()
@@ -190,24 +160,13 @@ impl BackupGroup {
Ok(last)
}
+}
- pub fn matches(&self, filter: &GroupFilter) -> bool {
- self.group.matches(filter)
- }
-
- pub fn backup_dir(&self, time: i64) -> Result<BackupDir, Error> {
- BackupDir::with_group(self.clone(), time)
- }
-
- pub fn backup_dir_with_rfc3339<T: Into<String>>(
- &self,
- time_string: T,
- ) -> Result<BackupDir, Error> {
- BackupDir::with_rfc3339(self.clone(), time_string.into())
- }
-
- pub fn iter_snapshots(&self) -> Result<crate::ListSnapshots, Error> {
- crate::ListSnapshots::new(self.clone())
+impl<T: CanWrite> BackupGroup<T> {
+ /// Set the backup owner.
+ pub fn set_owner(&self, auth_id: &Authid, force: bool) -> Result<(), Error> {
+ self.store
+ .set_owner(&self.ns, self.as_ref(), auth_id, force)
}
/// Destroy the group inclusive all its backup snapshots (BackupDir's)
@@ -260,32 +219,6 @@ impl BackupGroup {
Ok(())
}
- /// Returns the backup owner.
- ///
- /// The backup owner is the entity who first created the backup group.
- pub fn get_owner(&self) -> Result<Authid, Error> {
- self.store.get_owner(&self.ns, self.as_ref())
- }
-
- /// Set the backup owner.
- pub fn set_owner(&self, auth_id: &Authid, force: bool) -> Result<(), Error> {
- self.store
- .set_owner(&self.ns, self.as_ref(), auth_id, force)
- }
-
- /// Returns a file name for locking a group.
- ///
- /// The lock file will be located in:
- /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}`
- /// where `rpath` is the relative path of the group.
- fn lock_path(&self) -> PathBuf {
- let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
-
- let rpath = Path::new(self.group.ty.as_str()).join(&self.group.id);
-
- path.join(lock_file_path_helper(&self.ns, rpath))
- }
-
/// Locks a group exclusively.
pub fn lock(&self) -> Result<BackupLockGuard, Error> {
if *OLD_LOCKING {
@@ -304,34 +237,108 @@ impl BackupGroup {
}
}
-impl AsRef<pbs_api_types::BackupNamespace> for BackupGroup {
+impl<T: Clone> BackupGroup<T> {
+ pub(crate) fn new(
+ store: Arc<DataStore<T>>,
+ ns: BackupNamespace,
+ group: pbs_api_types::BackupGroup,
+ ) -> Self {
+ Self { store, ns, group }
+ }
+
+ /// Access the underlying [`BackupGroup`](pbs_api_types::BackupGroup).
+ #[inline]
+ pub fn group(&self) -> &pbs_api_types::BackupGroup {
+ &self.group
+ }
+
+ #[inline]
+ pub fn backup_ns(&self) -> &BackupNamespace {
+ &self.ns
+ }
+
+ #[inline]
+ pub fn backup_type(&self) -> BackupType {
+ self.group.ty
+ }
+
+ #[inline]
+ pub fn backup_id(&self) -> &str {
+ &self.group.id
+ }
+
+ pub fn full_group_path(&self) -> PathBuf {
+ self.store.group_path(&self.ns, &self.group)
+ }
+
+ pub fn relative_group_path(&self) -> PathBuf {
+ let mut path = self.ns.path();
+ path.push(self.group.ty.as_str());
+ path.push(&self.group.id);
+ path
+ }
+
+ pub fn matches(&self, filter: &GroupFilter) -> bool {
+ self.group.matches(filter)
+ }
+
+ pub fn backup_dir(&self, time: i64) -> Result<BackupDir<T>, Error> {
+ BackupDir::with_group(self.clone(), time)
+ }
+
+ pub fn backup_dir_with_rfc3339<D: Into<String>>(
+ &self,
+ time_string: D,
+ ) -> Result<BackupDir<T>, Error> {
+ BackupDir::with_rfc3339(self.clone(), time_string.into())
+ }
+
+ pub fn iter_snapshots(&self) -> Result<crate::ListSnapshots, Error> {
+ crate::ListSnapshots::new(self.clone())
+ }
+
+ /// Returns a file name for locking a group.
+ ///
+ /// The lock file will be located in:
+ /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}`
+ /// where `rpath` is the relative path of the group.
+ fn lock_path(&self) -> PathBuf {
+ let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
+
+ let rpath = Path::new(self.group.ty.as_str()).join(&self.group.id);
+
+ path.join(lock_file_path_helper(&self.ns, rpath))
+ }
+}
+
+impl<T> AsRef<pbs_api_types::BackupNamespace> for BackupGroup<T> {
#[inline]
fn as_ref(&self) -> &pbs_api_types::BackupNamespace {
&self.ns
}
}
-impl AsRef<pbs_api_types::BackupGroup> for BackupGroup {
+impl<T> AsRef<pbs_api_types::BackupGroup> for BackupGroup<T> {
#[inline]
fn as_ref(&self) -> &pbs_api_types::BackupGroup {
&self.group
}
}
-impl From<&BackupGroup> for pbs_api_types::BackupGroup {
- fn from(group: &BackupGroup) -> pbs_api_types::BackupGroup {
+impl<T> From<&BackupGroup<T>> for pbs_api_types::BackupGroup {
+ fn from(group: &BackupGroup<T>) -> pbs_api_types::BackupGroup {
group.group.clone()
}
}
-impl From<BackupGroup> for pbs_api_types::BackupGroup {
- fn from(group: BackupGroup) -> pbs_api_types::BackupGroup {
+impl<T> From<BackupGroup<T>> for pbs_api_types::BackupGroup {
+ fn from(group: BackupGroup<T>) -> pbs_api_types::BackupGroup {
group.group
}
}
-impl From<BackupDir> for BackupGroup {
- fn from(dir: BackupDir) -> BackupGroup {
+impl<T> From<BackupDir<T>> for BackupGroup<T> {
+ fn from(dir: BackupDir<T>) -> BackupGroup<T> {
BackupGroup {
store: dir.store,
ns: dir.ns,
@@ -340,8 +347,8 @@ impl From<BackupDir> for BackupGroup {
}
}
-impl From<&BackupDir> for BackupGroup {
- fn from(dir: &BackupDir) -> BackupGroup {
+impl<T> From<&BackupDir<T>> for BackupGroup<T> {
+ fn from(dir: &BackupDir<T>) -> BackupGroup<T> {
BackupGroup {
store: Arc::clone(&dir.store),
ns: dir.ns.clone(),
@@ -354,15 +361,15 @@ impl From<&BackupDir> for BackupGroup {
///
/// We also call this a backup snaphost.
#[derive(Clone)]
-pub struct BackupDir {
- store: Arc<DataStore>,
+pub struct BackupDir<T> {
+ store: Arc<DataStore<T>>,
ns: BackupNamespace,
dir: pbs_api_types::BackupDir,
// backup_time as rfc3339
backup_time_string: String,
}
-impl fmt::Debug for BackupDir {
+impl<T> fmt::Debug for BackupDir<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BackupDir")
.field("store", &self.store.name())
@@ -373,102 +380,12 @@ impl fmt::Debug for BackupDir {
}
}
-impl BackupDir {
- /// Temporarily used for tests.
- #[doc(hidden)]
- pub fn new_test(dir: pbs_api_types::BackupDir) -> Self {
- Self {
- store: unsafe { DataStore::new_test() },
- backup_time_string: Self::backup_time_to_string(dir.time).unwrap(),
- ns: BackupNamespace::root(),
- dir,
- }
- }
-
- pub(crate) fn with_group(group: BackupGroup, backup_time: i64) -> Result<Self, Error> {
- let backup_time_string = Self::backup_time_to_string(backup_time)?;
- Ok(Self {
- store: group.store,
- ns: group.ns,
- dir: (group.group, backup_time).into(),
- backup_time_string,
- })
- }
-
- pub(crate) fn with_rfc3339(
- group: BackupGroup,
- backup_time_string: String,
- ) -> Result<Self, Error> {
- let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?;
- Ok(Self {
- store: group.store,
- ns: group.ns,
- dir: (group.group, backup_time).into(),
- backup_time_string,
- })
- }
-
- #[inline]
- pub fn backup_ns(&self) -> &BackupNamespace {
- &self.ns
- }
-
- #[inline]
- pub fn backup_type(&self) -> BackupType {
- self.dir.group.ty
- }
-
- #[inline]
- pub fn backup_id(&self) -> &str {
- &self.dir.group.id
- }
-
- #[inline]
- pub fn backup_time(&self) -> i64 {
- self.dir.time
- }
-
- pub fn backup_time_string(&self) -> &str {
- &self.backup_time_string
- }
-
- pub fn dir(&self) -> &pbs_api_types::BackupDir {
- &self.dir
- }
-
- pub fn group(&self) -> &pbs_api_types::BackupGroup {
- &self.dir.group
- }
-
- pub fn relative_path(&self) -> PathBuf {
- let mut path = self.ns.path();
- path.push(self.dir.group.ty.as_str());
- path.push(&self.dir.group.id);
- path.push(&self.backup_time_string);
- path
- }
-
- /// Returns the absolute path for backup_dir, using the cached formatted time string.
- pub fn full_path(&self) -> PathBuf {
- let mut path = self.store.base_path();
- path.push(self.relative_path());
- path
- }
-
- pub fn protected_file(&self) -> PathBuf {
- let mut path = self.full_path();
- path.push(".protected");
- path
- }
-
- pub fn is_protected(&self) -> bool {
- let path = self.protected_file();
- path.exists()
- }
-
- pub fn backup_time_to_string(backup_time: i64) -> Result<String, Error> {
- // fixme: can this fail? (avoid unwrap)
- proxmox_time::epoch_to_rfc3339_utc(backup_time)
+impl<T: CanRead> BackupDir<T> {
+ /// Returns the backup owner.
+ ///
+ /// The backup owner is the entity who first created the backup group.
+ pub fn get_owner(&self) -> Result<Authid, Error> {
+ self.store.get_owner(&self.ns, self.as_ref())
}
/// load a `DataBlob` from this snapshot's backup dir.
@@ -483,22 +400,38 @@ impl BackupDir {
.map_err(|err| format_err!("unable to load blob '{:?}' - {}", path, err))
}
- /// Returns the filename to lock a manifest
- ///
- /// Also creates the basedir. The lockfile is located in
- /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}.index.json.lck`
- /// where rpath is the relative path of the snapshot.
- fn manifest_lock_path(&self) -> PathBuf {
- let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
+ /// Acquires a shared lock on a snapshot.
+ pub fn lock_shared(&self) -> Result<BackupLockGuard, Error> {
+ if *OLD_LOCKING {
+ lock_dir_noblock_shared(
+ &self.full_path(),
+ "snapshot",
+ "backup is running or snapshot is in use, could not acquire shared lock",
+ )
+ .map(BackupLockGuard::from)
+ } else {
+ lock_helper(self.store.name(), &self.lock_path(), |p| {
+ open_backup_lockfile(p, Some(Duration::from_secs(0)), false)
+ .with_context(|| format!("unable to acquire shared snapshot lock {p:?}"))
+ })
+ }
+ }
- let rpath = Path::new(self.dir.group.ty.as_str())
- .join(&self.dir.group.id)
- .join(&self.backup_time_string)
- .join(MANIFEST_LOCK_NAME);
+ /// Load the manifest without a lock. Must not be written back.
+ pub fn load_manifest(&self) -> Result<(BackupManifest, u64), Error> {
+ let blob = self.load_blob(MANIFEST_BLOB_NAME.as_ref())?;
+ let raw_size = blob.raw_size();
+ let manifest = BackupManifest::try_from(blob)?;
+ Ok((manifest, raw_size))
+ }
- path.join(lock_file_path_helper(&self.ns, rpath))
+ /// Load the verify state from the manifest.
+ pub fn verify_state(&self) -> Result<Option<VerifyState>, anyhow::Error> {
+ Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state))
}
+}
+impl<T: CanWrite> BackupDir<T> {
/// Locks the manifest of a snapshot, for example, to update or delete it.
pub(crate) fn lock_manifest(&self) -> Result<BackupLockGuard, Error> {
let path = if *OLD_LOCKING {
@@ -523,21 +456,6 @@ impl BackupDir {
})
}
- /// Returns a file name for locking a snapshot.
- ///
- /// The lock file will be located in:
- /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}`
- /// where `rpath` is the relative path of the snapshot.
- fn lock_path(&self) -> PathBuf {
- let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
-
- let rpath = Path::new(self.dir.group.ty.as_str())
- .join(&self.dir.group.id)
- .join(&self.backup_time_string);
-
- path.join(lock_file_path_helper(&self.ns, rpath))
- }
-
/// Locks a snapshot exclusively.
pub fn lock(&self) -> Result<BackupLockGuard, Error> {
if *OLD_LOCKING {
@@ -555,23 +473,6 @@ impl BackupDir {
}
}
- /// Acquires a shared lock on a snapshot.
- pub fn lock_shared(&self) -> Result<BackupLockGuard, Error> {
- if *OLD_LOCKING {
- lock_dir_noblock_shared(
- &self.full_path(),
- "snapshot",
- "backup is running or snapshot is in use, could not acquire shared lock",
- )
- .map(BackupLockGuard::from)
- } else {
- lock_helper(self.store.name(), &self.lock_path(), |p| {
- open_backup_lockfile(p, Some(Duration::from_secs(0)), false)
- .with_context(|| format!("unable to acquire shared snapshot lock {p:?}"))
- })
- }
- }
-
/// Destroy the whole snapshot, bails if it's protected
///
/// Setting `force` to true skips locking and thus ignores if the backup is currently in use.
@@ -624,31 +525,6 @@ impl BackupDir {
Ok(())
}
- /// Get the datastore.
- pub fn datastore(&self) -> &Arc<DataStore> {
- &self.store
- }
-
- /// Returns the backup owner.
- ///
- /// The backup owner is the entity who first created the backup group.
- pub fn get_owner(&self) -> Result<Authid, Error> {
- self.store.get_owner(&self.ns, self.as_ref())
- }
-
- /// Lock the snapshot and open a reader.
- pub fn locked_reader(&self) -> Result<crate::SnapshotReader, Error> {
- crate::SnapshotReader::new_do(self.clone())
- }
-
- /// Load the manifest without a lock. Must not be written back.
- pub fn load_manifest(&self) -> Result<(BackupManifest, u64), Error> {
- let blob = self.load_blob(MANIFEST_BLOB_NAME.as_ref())?;
- let raw_size = blob.raw_size();
- let manifest = BackupManifest::try_from(blob)?;
- Ok((manifest, raw_size))
- }
-
/// Update the manifest of the specified snapshot. Never write a manifest directly,
/// only use this method - anything else may break locking guarantees.
pub fn update_manifest(
@@ -706,68 +582,203 @@ impl BackupDir {
Ok(())
}
+}
+
+impl<T> BackupDir<T> {
+ /// Temporarily used for tests.
+ #[doc(hidden)]
+ pub fn new_test(dir: pbs_api_types::BackupDir) -> Self {
+ Self {
+ store: DataStore::new_test(),
+ backup_time_string: Self::backup_time_to_string(dir.time).unwrap(),
+ ns: BackupNamespace::root(),
+ dir,
+ }
+ }
- /// Load the verify state from the manifest.
- pub fn verify_state(&self) -> Result<Option<VerifyState>, anyhow::Error> {
- Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state))
+ pub(crate) fn with_group(group: BackupGroup<T>, backup_time: i64) -> Result<Self, Error> {
+ let backup_time_string = Self::backup_time_to_string(backup_time)?;
+ Ok(Self {
+ store: group.store,
+ ns: group.ns,
+ dir: (group.group, backup_time).into(),
+ backup_time_string,
+ })
+ }
+
+ pub(crate) fn with_rfc3339(
+ group: BackupGroup<T>,
+ backup_time_string: String,
+ ) -> Result<Self, Error> {
+ let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?;
+ Ok(Self {
+ store: group.store,
+ ns: group.ns,
+ dir: (group.group, backup_time).into(),
+ backup_time_string,
+ })
+ }
+
+ #[inline]
+ pub fn backup_ns(&self) -> &BackupNamespace {
+ &self.ns
+ }
+
+ #[inline]
+ pub fn backup_type(&self) -> BackupType {
+ self.dir.group.ty
+ }
+
+ #[inline]
+ pub fn backup_id(&self) -> &str {
+ &self.dir.group.id
+ }
+
+ #[inline]
+ pub fn backup_time(&self) -> i64 {
+ self.dir.time
+ }
+
+ pub fn backup_time_string(&self) -> &str {
+ &self.backup_time_string
+ }
+
+ pub fn dir(&self) -> &pbs_api_types::BackupDir {
+ &self.dir
+ }
+
+ pub fn group(&self) -> &pbs_api_types::BackupGroup {
+ &self.dir.group
+ }
+
+ pub fn relative_path(&self) -> PathBuf {
+ let mut path = self.ns.path();
+ path.push(self.dir.group.ty.as_str());
+ path.push(&self.dir.group.id);
+ path.push(&self.backup_time_string);
+ path
+ }
+
+ /// Returns the absolute path for backup_dir, using the cached formatted time string.
+ pub fn full_path(&self) -> PathBuf {
+ let mut path = self.store.base_path();
+ path.push(self.relative_path());
+ path
+ }
+
+ pub fn protected_file(&self) -> PathBuf {
+ let mut path = self.full_path();
+ path.push(".protected");
+ path
+ }
+
+ pub fn is_protected(&self) -> bool {
+ let path = self.protected_file();
+ path.exists()
+ }
+
+ pub fn backup_time_to_string(backup_time: i64) -> Result<String, Error> {
+ // fixme: can this fail? (avoid unwrap)
+ proxmox_time::epoch_to_rfc3339_utc(backup_time)
+ }
+
+ /// Returns the filename to lock a manifest
+ ///
+ /// Also creates the basedir. The lockfile is located in
+ /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}.index.json.lck`
+ /// where rpath is the relative path of the snapshot.
+ fn manifest_lock_path(&self) -> PathBuf {
+ let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
+
+ let rpath = Path::new(self.dir.group.ty.as_str())
+ .join(&self.dir.group.id)
+ .join(&self.backup_time_string)
+ .join(MANIFEST_LOCK_NAME);
+
+ path.join(lock_file_path_helper(&self.ns, rpath))
+ }
+
+ /// Returns a file name for locking a snapshot.
+ ///
+ /// The lock file will be located in:
+ /// `${DATASTORE_LOCKS_DIR}/${datastore name}/${lock_file_path_helper(rpath)}`
+ /// where `rpath` is the relative path of the snapshot.
+ fn lock_path(&self) -> PathBuf {
+ let path = Path::new(DATASTORE_LOCKS_DIR).join(self.store.name());
+
+ let rpath = Path::new(self.dir.group.ty.as_str())
+ .join(&self.dir.group.id)
+ .join(&self.backup_time_string);
+
+ path.join(lock_file_path_helper(&self.ns, rpath))
+ }
+
+ /// Get the datastore.
+ pub fn datastore(&self) -> &Arc<DataStore<T>> {
+ &self.store
+ }
+
+ /// Lock the snapshot and open a reader.
+ pub fn locked_reader(&self) -> Result<crate::SnapshotReader, Error> {
+ crate::SnapshotReader::new_do(self.clone())
}
}
-impl AsRef<pbs_api_types::BackupNamespace> for BackupDir {
+impl<T> AsRef<pbs_api_types::BackupNamespace> for BackupDir<T> {
fn as_ref(&self) -> &pbs_api_types::BackupNamespace {
&self.ns
}
}
-impl AsRef<pbs_api_types::BackupDir> for BackupDir {
+impl<T> AsRef<pbs_api_types::BackupDir> for BackupDir<T> {
fn as_ref(&self) -> &pbs_api_types::BackupDir {
&self.dir
}
}
-impl AsRef<pbs_api_types::BackupGroup> for BackupDir {
+impl<T> AsRef<pbs_api_types::BackupGroup> for BackupDir<T> {
fn as_ref(&self) -> &pbs_api_types::BackupGroup {
&self.dir.group
}
}
-impl From<&BackupDir> for pbs_api_types::BackupGroup {
- fn from(dir: &BackupDir) -> pbs_api_types::BackupGroup {
+impl<T> From<&BackupDir<T>> for pbs_api_types::BackupGroup {
+ fn from(dir: &BackupDir<T>) -> pbs_api_types::BackupGroup {
dir.dir.group.clone()
}
}
-impl From<BackupDir> for pbs_api_types::BackupGroup {
- fn from(dir: BackupDir) -> pbs_api_types::BackupGroup {
+impl<T> From<BackupDir<T>> for pbs_api_types::BackupGroup {
+ fn from(dir: BackupDir<T>) -> pbs_api_types::BackupGroup {
dir.dir.group
}
}
-impl From<&BackupDir> for pbs_api_types::BackupDir {
- fn from(dir: &BackupDir) -> pbs_api_types::BackupDir {
+impl<T> From<&BackupDir<T>> for pbs_api_types::BackupDir {
+ fn from(dir: &BackupDir<T>) -> pbs_api_types::BackupDir {
dir.dir.clone()
}
}
-impl From<BackupDir> for pbs_api_types::BackupDir {
- fn from(dir: BackupDir) -> pbs_api_types::BackupDir {
+impl<T> From<BackupDir<T>> for pbs_api_types::BackupDir {
+ fn from(dir: BackupDir<T>) -> pbs_api_types::BackupDir {
dir.dir
}
}
/// Detailed Backup Information, lists files inside a BackupDir
#[derive(Clone, Debug)]
-pub struct BackupInfo {
+pub struct BackupInfo<T> {
/// the backup directory
- pub backup_dir: BackupDir,
+ pub backup_dir: BackupDir<T>,
/// List of data files
pub files: Vec<String>,
/// Protection Status
pub protected: bool,
}
-impl BackupInfo {
- pub fn new(backup_dir: BackupDir) -> Result<BackupInfo, Error> {
+impl<T: CanRead> BackupInfo<T> {
+ pub fn new(backup_dir: BackupDir<T>) -> Result<BackupInfo<T>, Error> {
let path = backup_dir.full_path();
let files = list_backup_files(libc::AT_FDCWD, &path)?;
@@ -779,8 +790,10 @@ impl BackupInfo {
protected,
})
}
+}
- pub fn sort_list(list: &mut [BackupInfo], ascendending: bool) {
+impl<T> BackupInfo<T> {
+ pub fn sort_list(list: &mut [BackupInfo<T>], ascendending: bool) {
if ascendending {
// oldest first
list.sort_unstable_by(|a, b| a.backup_dir.dir.time.cmp(&b.backup_dir.dir.time));
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 66a2e209..9356750b 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -303,7 +303,7 @@ impl<T: CanRead + 'static> DataStore<T> {
self: &Arc<DataStore<T>>,
ns: BackupNamespace,
ty: BackupType,
- ) -> Result<impl Iterator<Item = BackupGroup> + 'static, Error> {
+ ) -> Result<impl Iterator<Item = BackupGroup<T>> + 'static, Error> {
Ok(self.iter_backup_type(ns, ty)?.ok())
}
@@ -314,7 +314,7 @@ impl<T: CanRead + 'static> DataStore<T> {
pub fn iter_backup_groups_ok(
self: &Arc<DataStore<T>>,
ns: BackupNamespace,
- ) -> Result<impl Iterator<Item = BackupGroup> + 'static, Error> {
+ ) -> Result<impl Iterator<Item = BackupGroup<T>> + 'static, Error> {
Ok(self.iter_backup_groups(ns)?.ok())
}
}
@@ -644,7 +644,7 @@ impl<T: CanRead> DataStore<T> {
pub fn list_backup_groups(
self: &Arc<DataStore<T>>,
ns: BackupNamespace,
- ) -> Result<Vec<BackupGroup>, Error> {
+ ) -> Result<Vec<BackupGroup<T>>, Error> {
ListGroups::new(Arc::clone(self), ns)?.collect()
}
@@ -837,7 +837,7 @@ impl<T: CanRead> DataStore<T> {
ty: BackupType,
id: D,
time: i64,
- ) -> Result<BackupDir, Error>
+ ) -> Result<BackupDir<T>, Error>
where
D: Into<String>,
{
@@ -847,10 +847,10 @@ impl<T: CanRead> DataStore<T> {
/// Open a snapshot (backup directory) from this datastore with a cached rfc3339 time string.
pub fn backup_dir_with_rfc3339<D: Into<String>>(
self: &Arc<Self>,
- group: BackupGroup,
+ group: BackupGroup<T>,
time_string: D,
- ) -> Result<BackupDir, Error> {
- BackupDir::with_rfc3339(group, time_string.into())
+ ) -> Result<BackupDir<T>, Error> {
+ BackupDir::<T>::with_rfc3339(group, time_string.into())
}
/// Open a backup group from this datastore.
@@ -859,7 +859,7 @@ impl<T: CanRead> DataStore<T> {
ns: BackupNamespace,
ty: BackupType,
id: D,
- ) -> BackupGroup
+ ) -> BackupGroup<T>
where
D: Into<String>,
{
@@ -889,7 +889,7 @@ impl<T: CanRead> DataStore<T> {
self: &Arc<Self>,
ns: BackupNamespace,
dir: pbs_api_types::BackupDir,
- ) -> Result<BackupDir, Error> {
+ ) -> Result<BackupDir<T>, Error> {
BackupDir::with_group(self.backup_group(ns, dir.group), dir.time)
}
}
@@ -1258,7 +1258,7 @@ impl<T: CanWrite> DataStore<T> {
_ => bail!("exhausted retries and unexpected counter overrun"),
};
- let mut snapshots = match group.list_backups() {
+ let mut snapshots: Vec<BackupInfo<T>> = match group.list_backups() {
Ok(snapshots) => snapshots,
Err(err) => {
if group.exists() {
@@ -1526,7 +1526,11 @@ impl<T: CanWrite> DataStore<T> {
}
/// Updates the protection status of the specified snapshot.
- pub fn update_protection(&self, backup_dir: &BackupDir, protection: bool) -> Result<(), Error> {
+ pub fn update_protection(
+ &self,
+ backup_dir: &BackupDir<T>,
+ protection: bool,
+ ) -> Result<(), Error> {
let full_path = backup_dir.full_path();
if !full_path.exists() {
--
2.39.5
More information about the pbs-devel
mailing list