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 8A4431FF15C for ; Fri, 14 Nov 2025 14:19:09 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A65C713665; Fri, 14 Nov 2025 14:20:05 +0100 (CET) From: Christian Ebner To: pbs-devel@lists.proxmox.com Date: Fri, 14 Nov 2025 14:18:57 +0100 Message-ID: <20251114131901.441650-18-c.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20251114131901.441650-1-c.ebner@proxmox.com> References: <20251114131901.441650-1-c.ebner@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1763126341057 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.048 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 Subject: [pbs-devel] [PATCH proxmox-backup v6 17/21] chunk store: add helpers marking missing local chunk markers as expected X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" writes or removes a `.using` marker file in place of an expected but missing local store cache chunk marker file for s3 backed datastores. These markers will be used to identify chunks which are still in-use and not bad, but the local store does not contain the marker file (e.g. because the cache might be empty due to datastore re-creation from s3 bucket). These markers will be set in phase 1 of garbage collection and replaced with the expected marker file by either a concurrent chunk insert or if the listing of chunk in phase 2 of garbage collection detects the chunk to be present on the s3 object store. Phase 3 will clean up the files after falling out of the cutoff window, given that the extension is chosen to fit the filename criteria. Signed-off-by: Christian Ebner --- pbs-datastore/src/chunk_store.rs | 42 ++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/pbs-datastore/src/chunk_store.rs b/pbs-datastore/src/chunk_store.rs index 20f71efef..f10415d1f 100644 --- a/pbs-datastore/src/chunk_store.rs +++ b/pbs-datastore/src/chunk_store.rs @@ -721,18 +721,56 @@ impl ChunkStore { /// Safety: chunk store mutex must be held! pub(crate) unsafe fn replace_chunk_with_marker(&self, digest: &[u8; 32]) -> Result<(), Error> { let (chunk_path, digest_str) = self.chunk_path(digest); + Self::create_marker_file(&chunk_path) + .map_err(|err| format_err!("clear chunk failed for {digest_str} - {err}"))?; + Ok(()) + } + + /// Helper to generate new empty marker file + fn create_marker_file(path: &Path) -> Result<(), Error> { let mut create_options = CreateOptions::new(); if nix::unistd::Uid::effective().is_root() { let uid = pbs_config::backup_user()?.uid; let gid = pbs_config::backup_group()?.gid; create_options = create_options.owner(uid).group(gid); } + proxmox_sys::fs::replace_file(&path, &[], create_options, false) + } - proxmox_sys::fs::replace_file(&chunk_path, &[], create_options, false) - .map_err(|err| format_err!("clear chunk failed for {digest_str} - {err}"))?; + /// Mark chunk as expected to be present by writing a file the chunk store. + /// + /// Used to mark chunks which are found in index files during phase 1 of garbage collection + /// for s3 datastores, but the marker file is not present and it is seemingly not a bad chunk. + /// This might happen if the local store cache is empty after datastore re-creation. + pub(crate) fn mark_chunk_as_expected(&self, digest: &[u8; 32]) -> Result<(), Error> { + let marker_path = self.chunk_expected_marker_path(digest); + Self::create_marker_file(&marker_path) + .map_err(|err| format_err!("mark chunk failed for {} - {err}", hex::encode(digest)))?; Ok(()) } + /// Remove chunk as required mark by removing file the chunk store. + /// + /// Returns true if the file was present and removed, false if the file did not exist. + pub(crate) fn clear_chunk_expected_mark(&self, digest: &[u8; 32]) -> Result { + let marker_path = self.chunk_expected_marker_path(digest); + if let Err(err) = std::fs::remove_file(marker_path) { + if err.kind() != std::io::ErrorKind::NotFound { + return Err(err.into()); + } else { + return Ok(false); + } + } + Ok(true) + } + + /// Helper to generate marker file path for expected chunks + fn chunk_expected_marker_path(&self, digest: &[u8; 32]) -> PathBuf { + let (mut path, _digest_str) = self.chunk_path(digest); + path.set_extension("using"); + path + } + /// Removes a chunk marker file from the `LocalDatastoreLruCache`s chunk store. /// /// Callers must hold the per-chunk file lock in order to avoid races with renaming of corrupt -- 2.47.3 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel