[pbs-devel] [PATCH proxmox-backup RFC 05/10] backup_info: add generics and separate functions into impl blocks

Hannes Laimer h.laimer at proxmox.com
Tue Sep 3 14:33:56 CEST 2024


Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
 pbs-datastore/src/backup_info.rs | 179 ++++++++++++++++---------------
 1 file changed, 93 insertions(+), 86 deletions(-)

diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 414ec878..d353f9d6 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -12,6 +12,7 @@ use pbs_api_types::{
 };
 use pbs_config::{open_backup_lockfile, BackupLockGuard};
 
+use crate::chunk_store::{CanRead, CanWrite};
 use crate::manifest::{
     BackupManifest, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME, MANIFEST_LOCK_NAME,
 };
@@ -49,14 +50,14 @@ impl BackupGroupDeleteStats {
 
 /// 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: CanRead> fmt::Debug for BackupGroup<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_struct("BackupGroup")
             .field("store", &self.store.name())
@@ -66,9 +67,9 @@ impl fmt::Debug for BackupGroup {
     }
 }
 
-impl BackupGroup {
+impl<T: Clone> BackupGroup<T> {
     pub(crate) fn new(
-        store: Arc<DataStore>,
+        store: Arc<DataStore<T>>,
         ns: BackupNamespace,
         group: pbs_api_types::BackupGroup,
     ) -> Self {
@@ -106,14 +107,30 @@ impl BackupGroup {
         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())
+    }
+}
 
+impl<T: CanRead> BackupGroup<T> {
     /// Simple check whether a group exists. This does not check whether there are any snapshots,
     /// but rather it simply checks whether the directory exists.
     pub fn exists(&self) -> bool {
         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();
@@ -145,7 +162,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()
@@ -206,23 +223,23 @@ 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 iter_snapshots(&self) -> Result<crate::ListSnapshots<T>, Error> {
+        crate::ListSnapshots::new(self.clone())
     }
 
-    pub fn backup_dir_with_rfc3339<T: Into<String>>(
-        &self,
-        time_string: T,
-    ) -> Result<BackupDir, Error> {
-        BackupDir::with_rfc3339(self.clone(), time_string.into())
+    /// 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())
     }
+}
 
-    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)
@@ -254,49 +271,36 @@ impl BackupGroup {
 
         Ok(delete_stats)
     }
-
-    /// 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)
-    }
 }
 
-impl AsRef<pbs_api_types::BackupNamespace> for BackupGroup {
+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,
@@ -305,8 +309,8 @@ impl From<BackupDir> for BackupGroup {
     }
 }
 
-impl From<&BackupDir> for BackupGroup {
-    fn from(dir: &BackupDir) -> BackupGroup {
+impl<T: CanRead> From<&BackupDir<T>> for BackupGroup<T> {
+    fn from(dir: &BackupDir<T>) -> BackupGroup<T> {
         BackupGroup {
             store: Arc::clone(&dir.store),
             ns: dir.ns.clone(),
@@ -319,15 +323,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())
@@ -338,19 +342,21 @@ impl fmt::Debug for BackupDir {
     }
 }
 
-impl BackupDir {
+impl<T> BackupDir<T> {
     /// Temporarily used for tests.
     #[doc(hidden)]
     pub fn new_test(dir: pbs_api_types::BackupDir) -> Self {
         Self {
-            store: unsafe { DataStore::new_test() },
+            store: 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> {
+impl<T> BackupDir<T> {
+    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,
@@ -361,7 +367,7 @@ impl BackupDir {
     }
 
     pub(crate) fn with_rfc3339(
-        group: BackupGroup,
+        group: BackupGroup<T>,
         backup_time_string: String,
     ) -> Result<Self, Error> {
         let backup_time = proxmox_time::parse_rfc3339(&backup_time_string)?;
@@ -436,18 +442,6 @@ impl BackupDir {
         proxmox_time::epoch_to_rfc3339_utc(backup_time)
     }
 
-    /// load a `DataBlob` from this snapshot's backup dir.
-    pub fn load_blob(&self, filename: &str) -> Result<DataBlob, Error> {
-        let mut path = self.full_path();
-        path.push(filename);
-
-        proxmox_lang::try_block!({
-            let mut file = std::fs::File::open(&path)?;
-            DataBlob::load_from_reader(&mut file)
-        })
-        .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
@@ -502,19 +496,25 @@ impl BackupDir {
     }
 
     /// Get the datastore.
-    pub fn datastore(&self) -> &Arc<DataStore> {
+    pub fn datastore(&self) -> &Arc<DataStore<T>> {
         &self.store
     }
+}
+impl<T: CanRead> BackupDir<T> {
+    /// load a `DataBlob` from this snapshot's backup dir.
+    pub fn load_blob(&self, filename: &str) -> Result<DataBlob, Error> {
+        let mut path = self.full_path();
+        path.push(filename);
 
-    /// 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())
+        proxmox_lang::try_block!({
+            let mut file = std::fs::File::open(&path)?;
+            DataBlob::load_from_reader(&mut file)
+        })
+        .map_err(|err| format_err!("unable to load blob '{:?}' - {}", path, err))
     }
 
     /// Lock the snapshot and open a reader.
-    pub fn locked_reader(&self) -> Result<crate::SnapshotReader, Error> {
+    pub fn locked_reader(&self) -> Result<crate::SnapshotReader<T>, Error> {
         crate::SnapshotReader::new_do(self.clone())
     }
 
@@ -525,7 +525,15 @@ impl BackupDir {
         let manifest = BackupManifest::try_from(blob)?;
         Ok((manifest, raw_size))
     }
+    /// 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())
+    }
+}
 
+impl<T: CanWrite> BackupDir<T> {
     /// 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(
@@ -584,62 +592,61 @@ impl BackupDir {
         Ok(())
     }
 }
-
-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<Self, Error> {
         let path = backup_dir.full_path();
 
         let files = list_backup_files(libc::AT_FDCWD, &path)?;
@@ -652,7 +659,7 @@ impl BackupInfo {
         })
     }
 
-    pub fn sort_list(list: &mut [BackupInfo], ascendending: bool) {
+    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));
-- 
2.39.2





More information about the pbs-devel mailing list