[PATCH proxmox-backup v2 17/27] sync: push: add helper for loading known chunks from previous snapshot

Christian Ebner
2026-04-10T16:55:31Z

Loading of known chunks only makes sense for snapshots which do not
need encryption while pushing. To check this move the known chunk
loading into a common helper method and distinguish dynamic/fixed
index for loading based on archive type.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
src/server/push.rs | 65 ++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 20 deletions(-)

diff --git a/src/server/push.rs b/src/server/push.rs
index 02718b7b6..9b7a4adcb 100644
--- a/src/server/push.rs
+++ b/src/server/push.rs
@@ -808,6 +808,41 @@ pub(crate) async fn push_group(
Ok(stats)
}

+async fn load_previous_snapshot_known_chunks(
+ params: &PushParameters,
+ upload_options: &UploadOptions,
+ backup_writer: &BackupWriter,
+ archive_name: &BackupArchiveName,
+ known_chunks: Arc<Mutex<HashSet<[u8; 32]>>>,
+) {
+ if let Some(manifest) = upload_options.previous_manifest.as_ref() {
+ if let Some(crypt_config) = &params.crypt_config {
+ if let Ok(Some(fingerprint)) = manifest.fingerprint() {
+ if *fingerprint.bytes() == crypt_config.fingerprint() {
+ // needs encryption during push, cannot reuse chunks from previous manifest
+ return;
+ }
+ }
+ }
+
+ // Add known chunks, ignore errors since archive might not be present and it is better
+ // to proceed on unrelated errors than to fail here.
+ match archive_name.archive_type() {
+ ArchiveType::FixedIndex => {
+ let _res = backup_writer
+ .download_previous_fixed_index(archive_name, manifest, known_chunks)
+ .await;
+ }
+ ArchiveType::DynamicIndex => {
+ let _res = backup_writer
+ .download_previous_dynamic_index(archive_name, manifest, known_chunks)
+ .await;
+ }
+ ArchiveType::Blob => (),
+ };
+ }
+}
+
/// Push snapshot to target
///
/// Creates a new snapshot on the target and pushes the content of the source snapshot to the
@@ -902,6 +937,16 @@ pub(crate) async fn push_snapshot(
path.push(&entry.filename);
if path.try_exists()? {
let archive_name = BackupArchiveName::from_path(&entry.filename)?;
+
+ load_previous_snapshot_known_chunks(
+ params,
+ &upload_options,
+ &backup_writer,
+ &archive_name,
+ known_chunks.clone(),
+ )
+ .await;
+
match archive_name.archive_type() {
ArchiveType::Blob => {
let backup_stats = if encrypt_using_key.is_some() {
@@ -932,16 +977,6 @@ pub(crate) async fn push_snapshot(
});
}
ArchiveType::DynamicIndex => {
- if let Some(manifest) = upload_options.previous_manifest.as_ref() {
- // Add known chunks, ignore errors since archive might not be present
- let _res = backup_writer
- .download_previous_dynamic_index(
- &archive_name,
- manifest,
- known_chunks.clone(),
- )
- .await;
- }
let index = DynamicIndexReader::open(&path)?;
let chunk_reader = reader
.chunk_reader(entry.chunk_crypt_mode())
@@ -969,16 +1004,6 @@ pub(crate) async fn push_snapshot(
});
}
ArchiveType::FixedIndex => {
- if let Some(manifest) = upload_options.previous_manifest.as_ref() {
- // Add known chunks, ignore errors since archive might not be present
- let _res = backup_writer
- .download_previous_fixed_index(
- &archive_name,
- manifest,
- known_chunks.clone(),
- )
- .await;
- }
let index = FixedIndexReader::open(&path)?;
let chunk_reader = reader
.chunk_reader(entry.chunk_crypt_mode())
--
2.47.3