From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 24B681FF143 for ; Sat, 25 Apr 2026 16:10:15 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 7B3CA1D8C; Sat, 25 Apr 2026 16:10:14 +0200 (CEST) From: Christian Ebner To: pbs-devel@lists.proxmox.com Subject: [PATCH proxmox-backup 2/3] sync: use log sender for logging when fetching client log Date: Sat, 25 Apr 2026 16:09:26 +0200 Message-ID: <20260425140927.928214-3-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260425140927.928214-1-c.ebner@proxmox.com> References: <20260425140927.928214-1-c.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1777126087015 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.070 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 4N3FMVMVA664P6HZEUDFBOOQYJVTLJE5 X-Message-ID-Hash: 4N3FMVMVA664P6HZEUDFBOOQYJVTLJE5 X-MailFrom: c.ebner@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: For the log messages to be correctly logged and prefixed, extend the trait method for fetching the client log by the log sender and use that for logging. Since the local source reader does not yet log this, store a full pbs_datastore::BackupDir instead of the pbs_api_types::BackupDir, which is a superset thereof and already contains a reference to the datastore required by the reader. Signed-off-by: Christian Ebner --- src/server/pull.rs | 4 +++- src/server/sync.rs | 58 +++++++++++++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/server/pull.rs b/src/server/pull.rs index 6bb5995cc..d37998f56 100644 --- a/src/server/pull.rs +++ b/src/server/pull.rs @@ -679,9 +679,10 @@ async fn pull_snapshot<'a>( let fetch_log = async || { if !client_log_name.exists() { reader - .try_fetch_client_log(&client_log_name) + .try_fetch_client_log(&client_log_name, Arc::clone(&log_sender)) .await .with_context(|| prefix.clone())?; + if client_log_name.exists() { if let DatastoreBackend::S3(s3_client) = backend { let object_key = pbs_datastore::s3::object_key_from_path( @@ -704,6 +705,7 @@ async fn pull_snapshot<'a>( } } } + Ok::<(), Error>(()) }; let cleanup = async || { diff --git a/src/server/sync.rs b/src/server/sync.rs index ad537129b..d8eec844e 100644 --- a/src/server/sync.rs +++ b/src/server/sync.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::io::{Seek, Write}; use std::ops::Deref; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -104,7 +104,11 @@ pub(crate) trait SyncSourceReader: Send + Sync { async fn load_file_into(&self, filename: &str, into: &Path) -> Result, Error>; /// Tries to fetch the client log from the source and save it into a local file. - async fn try_fetch_client_log(&self, to_path: &Path) -> Result<(), Error>; + async fn try_fetch_client_log( + &self, + to_path: &Path, + log_sender: Arc, + ) -> Result<(), Error>; fn skip_chunk_sync(&self, target_store_name: &str) -> bool; } @@ -117,8 +121,7 @@ pub(crate) struct RemoteSourceReader { pub(crate) struct LocalSourceReader { // must not be accessed/made pub, this is just a hack for Send+Sync _dir_lock: Arc>, - pub(crate) path: PathBuf, - pub(crate) datastore: Arc, + pub(crate) dir: pbs_datastore::BackupDir, } #[async_trait::async_trait] @@ -168,7 +171,11 @@ impl SyncSourceReader for RemoteSourceReader { Ok(DataBlob::load_from_reader(&mut tmp_file).ok()) } - async fn try_fetch_client_log(&self, to_path: &Path) -> Result<(), Error> { + async fn try_fetch_client_log( + &self, + to_path: &Path, + log_sender: Arc, + ) -> Result<(), Error> { let mut tmp_path = to_path.to_owned(); tmp_path.set_extension("tmp"); @@ -189,11 +196,16 @@ impl SyncSourceReader for RemoteSourceReader { if let Err(err) = std::fs::rename(&tmp_path, to_path) { bail!("Atomic rename file {to_path:?} failed - {err}"); } - info!( - "Snapshot {snapshot}: got backup log file {client_log_name}", - snapshot = &self.dir, - client_log_name = client_log_name.deref() - ); + log_sender + .log( + Level::INFO, + format!( + "Snapshot {}: got backup log file {}", + self.dir, + client_log_name.deref() + ), + ) + .await?; } Ok(()) @@ -211,7 +223,8 @@ impl SyncSourceReader for LocalSourceReader { crypt_config: Option>, crypt_mode: CryptMode, ) -> Result, Error> { - let chunk_reader = LocalChunkReader::new(self.datastore.clone(), crypt_config, crypt_mode)?; + let chunk_reader = + LocalChunkReader::new(self.dir.datastore().clone(), crypt_config, crypt_mode)?; Ok(Arc::new(chunk_reader)) } @@ -222,21 +235,35 @@ impl SyncSourceReader for LocalSourceReader { .truncate(true) .read(true) .open(into)?; - let mut from_path = self.path.clone(); + let mut from_path = self.dir.full_path(); from_path.push(filename); tmp_file.write_all(std::fs::read(from_path)?.as_slice())?; tmp_file.rewind()?; Ok(DataBlob::load_from_reader(&mut tmp_file).ok()) } - async fn try_fetch_client_log(&self, to_path: &Path) -> Result<(), Error> { + async fn try_fetch_client_log( + &self, + to_path: &Path, + log_sender: Arc, + ) -> Result<(), Error> { self.load_file_into(CLIENT_LOG_BLOB_NAME.as_ref(), to_path) .await?; + log_sender + .log( + Level::INFO, + format!( + "Snapshot {}: got backup log file {}", + self.dir.dir(), + CLIENT_LOG_BLOB_NAME.as_ref(), + ), + ) + .await?; Ok(()) } fn skip_chunk_sync(&self, target_store_name: &str) -> bool { - self.datastore.name() == target_store_name + self.dir.datastore().name() == target_store_name } } @@ -496,8 +523,7 @@ impl SyncSource for LocalSource { .with_context(|| format!("while reading snapshot '{dir:?}' for a sync job"))?; Ok(Arc::new(LocalSourceReader { _dir_lock: Arc::new(Mutex::new(guard)), - path: dir.full_path(), - datastore: dir.datastore().clone(), + dir, })) } } -- 2.47.3