all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v2 06/12] pbs-datastore: add generics and separate functions into impl blocks
Date: Mon, 26 May 2025 16:14:39 +0200	[thread overview]
Message-ID: <20250526141445.228717-7-h.laimer@proxmox.com> (raw)
In-Reply-To: <20250526141445.228717-1-h.laimer@proxmox.com>

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
 pbs-datastore/src/backup_info.rs        | 18 ++---
 pbs-datastore/src/datastore.rs          | 12 ++--
 pbs-datastore/src/dynamic_index.rs      | 22 +++---
 pbs-datastore/src/fixed_index.rs        | 50 +++++++-------
 pbs-datastore/src/hierarchy.rs          | 92 ++++++++++++++-----------
 pbs-datastore/src/local_chunk_reader.rs | 13 ++--
 pbs-datastore/src/prune.rs              | 19 +++--
 pbs-datastore/src/snapshot_reader.rs    | 25 +++----
 8 files changed, 134 insertions(+), 117 deletions(-)

diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index f3ca283c..25d8fc08 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -160,6 +160,10 @@ impl<T: CanRead> BackupGroup<T> {
 
         Ok(last)
     }
+
+    pub fn iter_snapshots(&self) -> Result<crate::ListSnapshots<T>, Error> {
+        crate::ListSnapshots::new(self.clone())
+    }
 }
 
 impl<T: CanWrite> BackupGroup<T> {
@@ -293,10 +297,6 @@ impl<T: Clone> BackupGroup<T> {
         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:
@@ -429,6 +429,11 @@ impl<T: CanRead> BackupDir<T> {
     pub fn verify_state(&self) -> Result<Option<VerifyState>, anyhow::Error> {
         Ok(self.load_manifest()?.0.verify_state()?.map(|svs| svs.state))
     }
+
+    /// Lock the snapshot and open a reader.
+    pub fn locked_reader(&self) -> Result<crate::SnapshotReader<T>, Error> {
+        crate::SnapshotReader::new_do(self.clone())
+    }
 }
 
 impl<T: CanWrite> BackupDir<T> {
@@ -717,11 +722,6 @@ impl<T> BackupDir<T> {
     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<T> AsRef<pbs_api_types::BackupNamespace> for BackupDir<T> {
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 9356750b..cb2d2172 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -600,7 +600,7 @@ impl<T: CanRead> DataStore<T> {
     pub fn iter_backup_ns(
         self: &Arc<DataStore<T>>,
         ns: BackupNamespace,
-    ) -> Result<ListNamespaces, Error> {
+    ) -> Result<ListNamespaces<T>, Error> {
         ListNamespaces::new(Arc::clone(self), ns)
     }
 
@@ -611,7 +611,7 @@ impl<T: CanRead> DataStore<T> {
     pub fn recursive_iter_backup_ns(
         self: &Arc<DataStore<T>>,
         ns: BackupNamespace,
-    ) -> Result<ListNamespacesRecursive, Error> {
+    ) -> Result<ListNamespacesRecursive<T>, Error> {
         ListNamespacesRecursive::new(Arc::clone(self), ns)
     }
 
@@ -623,7 +623,7 @@ impl<T: CanRead> DataStore<T> {
         self: &Arc<DataStore<T>>,
         ns: BackupNamespace,
         ty: BackupType,
-    ) -> Result<ListGroupsType, Error> {
+    ) -> Result<ListGroupsType<T>, Error> {
         ListGroupsType::new(Arc::clone(self), ns, ty)
     }
 
@@ -634,7 +634,7 @@ impl<T: CanRead> DataStore<T> {
     pub fn iter_backup_groups(
         self: &Arc<DataStore<T>>,
         ns: BackupNamespace,
-    ) -> Result<ListGroups, Error> {
+    ) -> Result<ListGroups<T>, Error> {
         ListGroups::new(Arc::clone(self), ns)
     }
 
@@ -900,7 +900,7 @@ impl<T: CanWrite> DataStore<T> {
         filename: P,
         size: usize,
         chunk_size: usize,
-    ) -> Result<FixedIndexWriter, Error> {
+    ) -> Result<FixedIndexWriter<T>, Error> {
         let index = FixedIndexWriter::create(
             self.inner.chunk_store.clone(),
             filename.as_ref(),
@@ -914,7 +914,7 @@ impl<T: CanWrite> DataStore<T> {
     pub fn create_dynamic_writer<P: AsRef<Path>>(
         &self,
         filename: P,
-    ) -> Result<DynamicIndexWriter, Error> {
+    ) -> Result<DynamicIndexWriter<T>, Error> {
         let index = DynamicIndexWriter::create(self.inner.chunk_store.clone(), filename.as_ref())?;
 
         Ok(index)
diff --git a/pbs-datastore/src/dynamic_index.rs b/pbs-datastore/src/dynamic_index.rs
index 8e9cb116..dbf99faa 100644
--- a/pbs-datastore/src/dynamic_index.rs
+++ b/pbs-datastore/src/dynamic_index.rs
@@ -18,7 +18,7 @@ use pxar::accessor::{MaybeReady, ReadAt, ReadAtOperation};
 use pbs_tools::lru_cache::LruCache;
 
 use crate::chunk_stat::ChunkStat;
-use crate::chunk_store::ChunkStore;
+use crate::chunk_store::{CanWrite, ChunkStore};
 use crate::data_blob::{DataBlob, DataChunkBuilder};
 use crate::file_formats;
 use crate::index::{ChunkReadInfo, IndexFile};
@@ -275,8 +275,8 @@ impl IndexFile for DynamicIndexReader {
 }
 
 /// Create dynamic index files (`.dixd`)
-pub struct DynamicIndexWriter {
-    store: Arc<ChunkStore>,
+pub struct DynamicIndexWriter<T> {
+    store: Arc<ChunkStore<T>>,
     _lock: ProcessLockSharedGuard,
     writer: BufWriter<File>,
     closed: bool,
@@ -287,14 +287,14 @@ pub struct DynamicIndexWriter {
     pub ctime: i64,
 }
 
-impl Drop for DynamicIndexWriter {
+impl<T> Drop for DynamicIndexWriter<T> {
     fn drop(&mut self) {
         let _ = std::fs::remove_file(&self.tmp_filename); // ignore errors
     }
 }
 
-impl DynamicIndexWriter {
-    pub fn create(store: Arc<ChunkStore>, path: &Path) -> Result<Self, Error> {
+impl<T: CanWrite> DynamicIndexWriter<T> {
+    pub fn create(store: Arc<ChunkStore<T>>, path: &Path) -> Result<Self, Error> {
         let shared_lock = store.try_shared_lock()?;
 
         let full_path = store.relative_path(path);
@@ -394,8 +394,8 @@ impl DynamicIndexWriter {
 /// Writer which splits a binary stream into dynamic sized chunks
 ///
 /// And store the resulting chunk list into the index file.
-pub struct DynamicChunkWriter {
-    index: DynamicIndexWriter,
+pub struct DynamicChunkWriter<T: CanWrite> {
+    index: DynamicIndexWriter<T>,
     closed: bool,
     chunker: ChunkerImpl,
     stat: ChunkStat,
@@ -404,8 +404,8 @@ pub struct DynamicChunkWriter {
     chunk_buffer: Vec<u8>,
 }
 
-impl DynamicChunkWriter {
-    pub fn new(index: DynamicIndexWriter, chunk_size: usize) -> Self {
+impl<T: CanWrite> DynamicChunkWriter<T> {
+    pub fn new(index: DynamicIndexWriter<T>, chunk_size: usize) -> Self {
         Self {
             index,
             closed: false,
@@ -490,7 +490,7 @@ impl DynamicChunkWriter {
     }
 }
 
-impl Write for DynamicChunkWriter {
+impl<T: CanWrite> Write for DynamicChunkWriter<T> {
     fn write(&mut self, data: &[u8]) -> std::result::Result<usize, std::io::Error> {
         let chunker = &mut self.chunker;
 
diff --git a/pbs-datastore/src/fixed_index.rs b/pbs-datastore/src/fixed_index.rs
index d4bfcb51..8db9f440 100644
--- a/pbs-datastore/src/fixed_index.rs
+++ b/pbs-datastore/src/fixed_index.rs
@@ -214,8 +214,8 @@ impl IndexFile for FixedIndexReader {
     }
 }
 
-pub struct FixedIndexWriter {
-    store: Arc<ChunkStore>,
+pub struct FixedIndexWriter<T> {
+    store: Arc<ChunkStore<T>>,
     file: File,
     _lock: ProcessLockSharedGuard,
     filename: PathBuf,
@@ -229,9 +229,9 @@ pub struct FixedIndexWriter {
 }
 
 // `index` is mmap()ed which cannot be thread-local so should be sendable
-unsafe impl Send for FixedIndexWriter {}
+unsafe impl<T> Send for FixedIndexWriter<T> {}
 
-impl Drop for FixedIndexWriter {
+impl<T> Drop for FixedIndexWriter<T> {
     fn drop(&mut self) {
         let _ = std::fs::remove_file(&self.tmp_filename); // ignore errors
         if let Err(err) = self.unmap() {
@@ -240,10 +240,30 @@ impl Drop for FixedIndexWriter {
     }
 }
 
-impl FixedIndexWriter {
+impl<T> FixedIndexWriter<T> {
+    fn unmap(&mut self) -> Result<(), Error> {
+        if self.index.is_null() {
+            return Ok(());
+        }
+
+        let index_size = self.index_length * 32;
+
+        if let Err(err) =
+            unsafe { nix::sys::mman::munmap(self.index as *mut std::ffi::c_void, index_size) }
+        {
+            bail!("unmap file {:?} failed - {}", self.tmp_filename, err);
+        }
+
+        self.index = std::ptr::null_mut();
+
+        Ok(())
+    }
+}
+
+impl<T: crate::chunk_store::CanWrite> FixedIndexWriter<T> {
     #[allow(clippy::cast_ptr_alignment)]
     pub fn create(
-        store: Arc<ChunkStore>,
+        store: Arc<ChunkStore<T>>,
         path: &Path,
         size: usize,
         chunk_size: usize,
@@ -320,24 +340,6 @@ impl FixedIndexWriter {
         self.index_length
     }
 
-    fn unmap(&mut self) -> Result<(), Error> {
-        if self.index.is_null() {
-            return Ok(());
-        }
-
-        let index_size = self.index_length * 32;
-
-        if let Err(err) =
-            unsafe { nix::sys::mman::munmap(self.index as *mut std::ffi::c_void, index_size) }
-        {
-            bail!("unmap file {:?} failed - {}", self.tmp_filename, err);
-        }
-
-        self.index = std::ptr::null_mut();
-
-        Ok(())
-    }
-
     pub fn close(&mut self) -> Result<[u8; 32], Error> {
         if self.index.is_null() {
             bail!("cannot close already closed index file.");
diff --git a/pbs-datastore/src/hierarchy.rs b/pbs-datastore/src/hierarchy.rs
index e0bf8441..b331d1de 100644
--- a/pbs-datastore/src/hierarchy.rs
+++ b/pbs-datastore/src/hierarchy.rs
@@ -9,16 +9,17 @@ use pbs_api_types::{BackupNamespace, BackupType, BACKUP_DATE_REGEX, BACKUP_ID_RE
 use proxmox_sys::fs::get_file_type;
 
 use crate::backup_info::{BackupDir, BackupGroup};
+use crate::chunk_store::CanRead;
 use crate::DataStore;
 
 /// A iterator for all BackupDir's (Snapshots) in a BackupGroup
-pub struct ListSnapshots {
-    group: BackupGroup,
+pub struct ListSnapshots<T: CanRead> {
+    group: BackupGroup<T>,
     fd: proxmox_sys::fs::ReadDir,
 }
 
-impl ListSnapshots {
-    pub fn new(group: BackupGroup) -> Result<Self, Error> {
+impl<T: CanRead> ListSnapshots<T> {
+    pub fn new(group: BackupGroup<T>) -> Result<Self, Error> {
         let group_path = group.full_group_path();
         Ok(ListSnapshots {
             fd: proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &group_path)
@@ -28,8 +29,8 @@ impl ListSnapshots {
     }
 }
 
-impl Iterator for ListSnapshots {
-    type Item = Result<BackupDir, Error>;
+impl<T: CanRead> Iterator for ListSnapshots<T> {
+    type Item = Result<BackupDir<T>, Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
@@ -64,21 +65,25 @@ impl Iterator for ListSnapshots {
 }
 
 /// An iterator for a single backup group type.
-pub struct ListGroupsType {
-    store: Arc<DataStore>,
+pub struct ListGroupsType<T> {
+    store: Arc<DataStore<T>>,
     ns: BackupNamespace,
     ty: BackupType,
     dir: proxmox_sys::fs::ReadDir,
 }
 
-impl ListGroupsType {
-    pub fn new(store: Arc<DataStore>, ns: BackupNamespace, ty: BackupType) -> Result<Self, Error> {
+impl<T: CanRead> ListGroupsType<T> {
+    pub fn new(
+        store: Arc<DataStore<T>>,
+        ns: BackupNamespace,
+        ty: BackupType,
+    ) -> Result<Self, Error> {
         Self::new_at(libc::AT_FDCWD, store, ns, ty)
     }
 
     fn new_at(
         fd: RawFd,
-        store: Arc<DataStore>,
+        store: Arc<DataStore<T>>,
         ns: BackupNamespace,
         ty: BackupType,
     ) -> Result<Self, Error> {
@@ -90,13 +95,13 @@ impl ListGroupsType {
         })
     }
 
-    pub(crate) fn ok(self) -> ListGroupsOk<Self> {
+    pub(crate) fn ok(self) -> ListGroupsOk<Self, T> {
         ListGroupsOk::new(self)
     }
 }
 
-impl Iterator for ListGroupsType {
-    type Item = Result<BackupGroup, Error>;
+impl<T: CanRead> Iterator for ListGroupsType<T> {
+    type Item = Result<BackupGroup<T>, Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
@@ -134,15 +139,15 @@ impl Iterator for ListGroupsType {
 }
 
 /// A iterator for a (single) level of Backup Groups
-pub struct ListGroups {
-    store: Arc<DataStore>,
+pub struct ListGroups<T> {
+    store: Arc<DataStore<T>>,
     ns: BackupNamespace,
     type_fd: proxmox_sys::fs::ReadDir,
-    id_state: Option<ListGroupsType>,
+    id_state: Option<ListGroupsType<T>>,
 }
 
-impl ListGroups {
-    pub fn new(store: Arc<DataStore>, ns: BackupNamespace) -> Result<Self, Error> {
+impl<T: CanRead> ListGroups<T> {
+    pub fn new(store: Arc<DataStore<T>>, ns: BackupNamespace) -> Result<Self, Error> {
         Ok(Self {
             type_fd: proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &store.namespace_path(&ns))?,
             store,
@@ -151,13 +156,13 @@ impl ListGroups {
         })
     }
 
-    pub(crate) fn ok(self) -> ListGroupsOk<Self> {
+    pub(crate) fn ok(self) -> ListGroupsOk<Self, T> {
         ListGroupsOk::new(self)
     }
 }
 
-impl Iterator for ListGroups {
-    type Item = Result<BackupGroup, Error>;
+impl<T: CanRead> Iterator for ListGroups<T> {
+    type Item = Result<BackupGroup<T>, Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
@@ -217,36 +222,36 @@ pub(crate) trait GroupIter {
     fn store_name(&self) -> &str;
 }
 
-impl GroupIter for ListGroups {
+impl<T: CanRead> GroupIter for ListGroups<T> {
     fn store_name(&self) -> &str {
         self.store.name()
     }
 }
 
-impl GroupIter for ListGroupsType {
+impl<T: CanRead> GroupIter for ListGroupsType<T> {
     fn store_name(&self) -> &str {
         self.store.name()
     }
 }
 
-pub(crate) struct ListGroupsOk<I>(Option<I>)
+pub(crate) struct ListGroupsOk<I, T: CanRead>(Option<I>)
 where
-    I: GroupIter + Iterator<Item = Result<BackupGroup, Error>>;
+    I: GroupIter + Iterator<Item = Result<BackupGroup<T>, Error>>;
 
-impl<I> ListGroupsOk<I>
+impl<I, T: CanRead> ListGroupsOk<I, T>
 where
-    I: GroupIter + Iterator<Item = Result<BackupGroup, Error>>,
+    I: GroupIter + Iterator<Item = Result<BackupGroup<T>, Error>>,
 {
     fn new(inner: I) -> Self {
         Self(Some(inner))
     }
 }
 
-impl<I> Iterator for ListGroupsOk<I>
+impl<I, T: CanRead> Iterator for ListGroupsOk<I, T>
 where
-    I: GroupIter + Iterator<Item = Result<BackupGroup, Error>>,
+    I: GroupIter + Iterator<Item = Result<BackupGroup<T>, Error>>,
 {
-    type Item = BackupGroup;
+    type Item = BackupGroup<T>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(iter) = &mut self.0 {
@@ -269,19 +274,21 @@ where
 }
 
 /// A iterator for a (single) level of Namespaces
-pub struct ListNamespaces {
+pub struct ListNamespaces<T> {
     ns: BackupNamespace,
     base_path: PathBuf,
     ns_state: Option<proxmox_sys::fs::ReadDir>,
+    _marker: std::marker::PhantomData<T>,
 }
 
-impl ListNamespaces {
+impl<T: CanRead> ListNamespaces<T> {
     /// construct a new single-level namespace iterator on a datastore with an optional anchor ns
-    pub fn new(store: Arc<DataStore>, ns: BackupNamespace) -> Result<Self, Error> {
+    pub fn new(store: Arc<DataStore<T>>, ns: BackupNamespace) -> Result<Self, Error> {
         Ok(ListNamespaces {
             ns,
             base_path: store.base_path(),
             ns_state: None,
+            _marker: std::marker::PhantomData,
         })
     }
 
@@ -293,11 +300,12 @@ impl ListNamespaces {
             ns: ns.unwrap_or_default(),
             base_path: path,
             ns_state: None,
+            _marker: std::marker::PhantomData,
         })
     }
 }
 
-impl Iterator for ListNamespaces {
+impl<T: CanRead> Iterator for ListNamespaces<T> {
     type Item = Result<BackupNamespace, Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -361,18 +369,18 @@ impl Iterator for ListNamespaces {
 /// can be useful for searching all backup groups from a certain anchor, as that can contain
 /// sub-namespaces but also groups on its own level, so otherwise one would need to special case
 /// the ones from the own level.
-pub struct ListNamespacesRecursive {
-    store: Arc<DataStore>,
+pub struct ListNamespacesRecursive<T> {
+    store: Arc<DataStore<T>>,
     /// the starting namespace we search downward from
     ns: BackupNamespace,
     /// the maximal recursion depth from the anchor start ns (depth == 0) downwards
     max_depth: u8,
-    state: Option<Vec<ListNamespaces>>, // vector to avoid code recursion
+    state: Option<Vec<ListNamespaces<T>>>, // vector to avoid code recursion
 }
 
-impl ListNamespacesRecursive {
+impl<T: CanRead> ListNamespacesRecursive<T> {
     /// Creates an recursive namespace iterator.
-    pub fn new(store: Arc<DataStore>, ns: BackupNamespace) -> Result<Self, Error> {
+    pub fn new(store: Arc<DataStore<T>>, ns: BackupNamespace) -> Result<Self, Error> {
         Self::new_max_depth(store, ns, pbs_api_types::MAX_NAMESPACE_DEPTH)
     }
 
@@ -383,7 +391,7 @@ impl ListNamespacesRecursive {
     /// Depth is counted relatively, that means not from the datastore as anchor, but from `ns`,
     /// and it will be clamped to `min(depth, MAX_NAMESPACE_DEPTH - ns.depth())` automatically.
     pub fn new_max_depth(
-        store: Arc<DataStore>,
+        store: Arc<DataStore<T>>,
         ns: BackupNamespace,
         max_depth: usize,
     ) -> Result<Self, Error> {
@@ -403,7 +411,7 @@ impl ListNamespacesRecursive {
     }
 }
 
-impl Iterator for ListNamespacesRecursive {
+impl<T: CanRead> Iterator for ListNamespacesRecursive<T> {
     type Item = Result<BackupNamespace, Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
diff --git a/pbs-datastore/src/local_chunk_reader.rs b/pbs-datastore/src/local_chunk_reader.rs
index 05a70c06..ccdde9f1 100644
--- a/pbs-datastore/src/local_chunk_reader.rs
+++ b/pbs-datastore/src/local_chunk_reader.rs
@@ -7,20 +7,21 @@ use anyhow::{bail, Error};
 use pbs_api_types::CryptMode;
 use pbs_tools::crypt_config::CryptConfig;
 
+use crate::chunk_store::CanRead;
 use crate::data_blob::DataBlob;
 use crate::read_chunk::{AsyncReadChunk, ReadChunk};
 use crate::DataStore;
 
 #[derive(Clone)]
-pub struct LocalChunkReader {
-    store: Arc<DataStore>,
+pub struct LocalChunkReader<T: CanRead> {
+    store: Arc<DataStore<T>>,
     crypt_config: Option<Arc<CryptConfig>>,
     crypt_mode: CryptMode,
 }
 
-impl LocalChunkReader {
+impl<T: CanRead> LocalChunkReader<T> {
     pub fn new(
-        store: Arc<DataStore>,
+        store: Arc<DataStore<T>>,
         crypt_config: Option<Arc<CryptConfig>>,
         crypt_mode: CryptMode,
     ) -> Self {
@@ -47,7 +48,7 @@ impl LocalChunkReader {
     }
 }
 
-impl ReadChunk for LocalChunkReader {
+impl<T: CanRead> ReadChunk for LocalChunkReader<T> {
     fn read_raw_chunk(&self, digest: &[u8; 32]) -> Result<DataBlob, Error> {
         let chunk = self.store.load_chunk(digest)?;
         self.ensure_crypt_mode(chunk.crypt_mode()?)?;
@@ -63,7 +64,7 @@ impl ReadChunk for LocalChunkReader {
     }
 }
 
-impl AsyncReadChunk for LocalChunkReader {
+impl<T: CanRead + Send + Sync> AsyncReadChunk for LocalChunkReader<T> {
     fn read_raw_chunk<'a>(
         &'a self,
         digest: &'a [u8; 32],
diff --git a/pbs-datastore/src/prune.rs b/pbs-datastore/src/prune.rs
index 7b6f9f75..a8eb511b 100644
--- a/pbs-datastore/src/prune.rs
+++ b/pbs-datastore/src/prune.rs
@@ -5,6 +5,8 @@ use anyhow::Error;
 
 use pbs_api_types::KeepOptions;
 
+use crate::chunk_store::CanRead;
+
 use super::BackupInfo;
 
 #[derive(Clone, Copy, PartialEq, Eq)]
@@ -36,9 +38,9 @@ impl std::fmt::Display for PruneMark {
     }
 }
 
-fn mark_selections<F: Fn(&BackupInfo) -> Result<String, Error>>(
+fn mark_selections<F: Fn(&BackupInfo<T>) -> Result<String, Error>, T: CanRead>(
     mark: &mut HashMap<PathBuf, PruneMark>,
-    list: &[BackupInfo],
+    list: &[BackupInfo<T>],
     keep: usize,
     select_id: F,
 ) -> Result<(), Error> {
@@ -82,7 +84,10 @@ fn mark_selections<F: Fn(&BackupInfo) -> Result<String, Error>>(
     Ok(())
 }
 
-fn remove_incomplete_snapshots(mark: &mut HashMap<PathBuf, PruneMark>, list: &[BackupInfo]) {
+fn remove_incomplete_snapshots<T: CanRead>(
+    mark: &mut HashMap<PathBuf, PruneMark>,
+    list: &[BackupInfo<T>],
+) {
     let mut keep_unfinished = true;
     for info in list.iter() {
         // backup is considered unfinished if there is no manifest
@@ -104,10 +109,10 @@ fn remove_incomplete_snapshots(mark: &mut HashMap<PathBuf, PruneMark>, list: &[B
 }
 
 /// This filters incomplete and kept backups.
-pub fn compute_prune_info(
-    mut list: Vec<BackupInfo>,
+pub fn compute_prune_info<T: CanRead>(
+    mut list: Vec<BackupInfo<T>>,
     options: &KeepOptions,
-) -> Result<Vec<(BackupInfo, PruneMark)>, Error> {
+) -> Result<Vec<(BackupInfo<T>, PruneMark)>, Error> {
     let mut mark = HashMap::new();
 
     BackupInfo::sort_list(&mut list, false);
@@ -154,7 +159,7 @@ pub fn compute_prune_info(
         })?;
     }
 
-    let prune_info: Vec<(BackupInfo, PruneMark)> = list
+    let prune_info: Vec<(BackupInfo<T>, PruneMark)> = list
         .into_iter()
         .map(|info| {
             let backup_id = info.backup_dir.relative_path();
diff --git a/pbs-datastore/src/snapshot_reader.rs b/pbs-datastore/src/snapshot_reader.rs
index 5da0533c..d604507d 100644
--- a/pbs-datastore/src/snapshot_reader.rs
+++ b/pbs-datastore/src/snapshot_reader.rs
@@ -16,6 +16,7 @@ use pbs_api_types::{
 };
 
 use crate::backup_info::BackupDir;
+use crate::chunk_store::CanRead;
 use crate::dynamic_index::DynamicIndexReader;
 use crate::fixed_index::FixedIndexReader;
 use crate::index::IndexFile;
@@ -24,8 +25,8 @@ use crate::DataStore;
 /// Helper to access the contents of a datastore backup snapshot
 ///
 /// This make it easy to iterate over all used chunks and files.
-pub struct SnapshotReader {
-    snapshot: BackupDir,
+pub struct SnapshotReader<T: CanRead> {
+    snapshot: BackupDir<T>,
     datastore_name: String,
     file_list: Vec<String>,
     locked_dir: Dir,
@@ -35,17 +36,17 @@ pub struct SnapshotReader {
     _lock: BackupLockGuard,
 }
 
-impl SnapshotReader {
+impl<T: CanRead> SnapshotReader<T> {
     /// Lock snapshot, reads the manifest and returns a new instance
     pub fn new(
-        datastore: Arc<DataStore>,
+        datastore: Arc<DataStore<T>>,
         ns: BackupNamespace,
         snapshot: pbs_api_types::BackupDir,
     ) -> Result<Self, Error> {
         Self::new_do(datastore.backup_dir(ns, snapshot)?)
     }
 
-    pub(crate) fn new_do(snapshot: BackupDir) -> Result<Self, Error> {
+    pub(crate) fn new_do(snapshot: BackupDir<T>) -> Result<Self, Error> {
         let datastore = snapshot.datastore();
         let snapshot_path = snapshot.full_path();
 
@@ -94,7 +95,7 @@ impl SnapshotReader {
     }
 
     /// Return the snapshot directory
-    pub fn snapshot(&self) -> &BackupDir {
+    pub fn snapshot(&self) -> &BackupDir<T> {
         &self.snapshot
     }
 
@@ -124,7 +125,7 @@ impl SnapshotReader {
     pub fn chunk_iterator<F: Fn(&[u8; 32]) -> bool>(
         &self,
         skip_fn: F,
-    ) -> Result<SnapshotChunkIterator<F>, Error> {
+    ) -> Result<SnapshotChunkIterator<F, T>, Error> {
         SnapshotChunkIterator::new(self, skip_fn)
     }
 }
@@ -134,15 +135,15 @@ impl SnapshotReader {
 /// Note: The iterator returns a `Result`, and the iterator state is
 /// undefined after the first error. So it make no sense to continue
 /// iteration after the first error.
-pub struct SnapshotChunkIterator<'a, F: Fn(&[u8; 32]) -> bool> {
-    snapshot_reader: &'a SnapshotReader,
+pub struct SnapshotChunkIterator<'a, F: Fn(&[u8; 32]) -> bool, T: CanRead> {
+    snapshot_reader: &'a SnapshotReader<T>,
     todo_list: Vec<String>,
     skip_fn: F,
     #[allow(clippy::type_complexity)]
     current_index: Option<(Rc<Box<dyn IndexFile + Send>>, usize, Vec<(usize, u64)>)>,
 }
 
-impl<F: Fn(&[u8; 32]) -> bool> Iterator for SnapshotChunkIterator<'_, F> {
+impl<F: Fn(&[u8; 32]) -> bool, T: CanRead> Iterator for SnapshotChunkIterator<'_, F, T> {
     type Item = Result<[u8; 32], Error>;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -189,8 +190,8 @@ impl<F: Fn(&[u8; 32]) -> bool> Iterator for SnapshotChunkIterator<'_, F> {
     }
 }
 
-impl<'a, F: Fn(&[u8; 32]) -> bool> SnapshotChunkIterator<'a, F> {
-    pub fn new(snapshot_reader: &'a SnapshotReader, skip_fn: F) -> Result<Self, Error> {
+impl<'a, F: Fn(&[u8; 32]) -> bool, T: CanRead> SnapshotChunkIterator<'a, F, T> {
+    pub fn new(snapshot_reader: &'a SnapshotReader<T>, skip_fn: F) -> Result<Self, Error> {
         let mut todo_list = Vec::new();
 
         for filename in snapshot_reader.file_list() {
-- 
2.39.5



_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


  parent reply	other threads:[~2025-05-26 14:15 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-26 14:14 [pbs-devel] [PATCH proxmox-backup v2 00/12] introduce typestate for datastore/chunkstore Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 01/12] chunkstore: add CanRead and CanWrite trait Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 02/12] chunkstore: separate functions into impl block Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 03/12] datastore: add generics and new lookup functions Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 04/12] datastore: separate functions into impl block Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 05/12] backup_info: add generics and separate functions into impl blocks Hannes Laimer
2025-05-26 14:14 ` Hannes Laimer [this message]
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 07/12] api: backup: env: add generics and separate functions into impl block Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 08/12] api/backup/bin/server/tape: add missing generics Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 09/12] examples/tests: " Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 10/12] api: admin: pull datastore loading out of check_privs helper Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 11/12] datastore: move `fn gc_running` out of DataStoreImpl Hannes Laimer
2025-05-26 14:14 ` [pbs-devel] [PATCH proxmox-backup v2 12/12] api/server: replace datastore_lookup with new, state-typed datastore returning functions Hannes Laimer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250526141445.228717-7-h.laimer@proxmox.com \
    --to=h.laimer@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal