* [PATCH proxmox-backup 1/4] move group: use human-readable snapshot timestamp in check
2026-04-27 12:02 [PATCH proxmox-backup 0/4] move group/namespace logging improvements Fabian Grünbichler
@ 2026-04-27 12:02 ` Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 2/4] move group: split overly long error message Fabian Grünbichler
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Fabian Grünbichler @ 2026-04-27 12:02 UTC (permalink / raw)
To: pbs-devel
before:
2026-04-27T13:39:44+02:00: TASK ERROR: cannot merge group 'ct/999' from 'foo' into 'bar': snapshot time overlap (oldest source: 1678867213, conflicting target: 1774348044)
after:
2026-04-27T13:42:03+02:00: TASK ERROR: cannot merge group 'ct/999' from 'foo' into 'bar': snapshot time overlap (oldest source: 2023-03-15T08:00:13Z, conflicting target: 2026-03-24T10:27:24Z)
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
pbs-datastore/src/backup_info.rs | 35 ++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 69949c511..5f61890ed 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -291,24 +291,35 @@ impl BackupGroup {
);
}
- let src_oldest = self
- .iter_snapshots()?
- .filter_map(Result::ok)
- .map(|s| s.backup_time())
- .min();
+ let (src_oldest, src_oldest_str) = self.iter_snapshots()?.filter_map(Result::ok).fold(
+ (i64::MAX, String::new()),
+ |(min, min_str), s| {
+ let curr = s.backup_time();
+ if curr < min {
+ (curr, s.backup_time_string.clone())
+ } else {
+ (min, min_str)
+ }
+ },
+ );
- if let Some(src_oldest) = src_oldest {
+ if src_oldest != i64::MAX {
// Any target snapshot with time >= src_oldest violates the
// "source strictly newer than target" merge invariant. Short-circuit on the first hit.
if let Some(overlap) = target
.iter_snapshots()?
.filter_map(Result::ok)
- .map(|s| s.backup_time())
- .find(|t| *t >= src_oldest)
+ .find_map(|s| {
+ if s.backup_time() >= src_oldest {
+ Some(s.backup_time_string().to_owned())
+ } else {
+ None
+ }
+ })
{
bail!(
"cannot merge group '{}/{}' from '{}' into '{}': snapshot time overlap \
- (oldest source: {src_oldest}, conflicting target: {overlap})",
+ (oldest source: {src_oldest_str}, conflicting target: {overlap})",
self.group.ty,
self.group.id,
self.ns,
@@ -957,6 +968,12 @@ impl BackupDir {
crate::SnapshotReader::new_do(self.clone())
}
+ /// Returns whether a manifest file exists
+ pub fn has_manifest(&self) -> bool {
+ let manifest_path = self.full_path().join(MANIFEST_BLOB_NAME.as_ref());
+ manifest_path.exists()
+ }
+
/// Load the manifest without a lock. Must not be written back.
pub fn load_manifest(&self) -> Result<(BackupManifest, u64), Error> {
let blob = self.load_blob(MANIFEST_BLOB_NAME.as_ref())?;
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH proxmox-backup 2/4] move group: split overly long error message
2026-04-27 12:02 [PATCH proxmox-backup 0/4] move group/namespace logging improvements Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 1/4] move group: use human-readable snapshot timestamp in check Fabian Grünbichler
@ 2026-04-27 12:02 ` Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 3/4] move namespace: move context log line before check Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 4/4] move namespace: use group(s)/namespace(s) consistently Fabian Grünbichler
3 siblings, 0 replies; 5+ messages in thread
From: Fabian Grünbichler @ 2026-04-27 12:02 UTC (permalink / raw)
To: pbs-devel
this is now logged as
2026-04-27T13:49:49+02:00: oldest source snapshot: 2023-03-15T08:00:13Z
2026-04-27T13:49:49+02:00: conflicting target snapshot: 2026-03-24T10:27:24Z
2026-04-27T13:49:49+02:00: TASK ERROR: cannot merge group 'ct/999' from 'foo' into 'bar': snapshot time overlap
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
pbs-datastore/src/backup_info.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 5f61890ed..8a650b57c 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -8,6 +8,7 @@ use std::time::Duration;
use anyhow::{bail, format_err, Context, Error};
use const_format::concatcp;
+use tracing::info;
use proxmox_s3_client::{S3ObjectKey, S3PathPrefix};
use proxmox_sys::fs::{lock_dir_noblock, lock_dir_noblock_shared, replace_file, CreateOptions};
@@ -317,9 +318,10 @@ impl BackupGroup {
}
})
{
+ info!("oldest source snapshot: {src_oldest_str}");
+ info!("conflicting target snapshot: {overlap}");
bail!(
- "cannot merge group '{}/{}' from '{}' into '{}': snapshot time overlap \
- (oldest source: {src_oldest_str}, conflicting target: {overlap})",
+ "cannot merge group '{}/{}' from '{}' into '{}': snapshot time overlap",
self.group.ty,
self.group.id,
self.ns,
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH proxmox-backup 3/4] move namespace: move context log line before check
2026-04-27 12:02 [PATCH proxmox-backup 0/4] move group/namespace logging improvements Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 1/4] move group: use human-readable snapshot timestamp in check Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 2/4] move group: split overly long error message Fabian Grünbichler
@ 2026-04-27 12:02 ` Fabian Grünbichler
2026-04-27 12:02 ` [PATCH proxmox-backup 4/4] move namespace: use group(s)/namespace(s) consistently Fabian Grünbichler
3 siblings, 0 replies; 5+ messages in thread
From: Fabian Grünbichler @ 2026-04-27 12:02 UTC (permalink / raw)
To: pbs-devel
to make it clear when the context switches to a particular group, since not all
warnings will include its name.
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
pbs-datastore/src/backup_info.rs | 2 +-
pbs-datastore/src/datastore.rs | 16 ++++++++--------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 8a650b57c..819a3b511 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -321,7 +321,7 @@ impl BackupGroup {
info!("oldest source snapshot: {src_oldest_str}");
info!("conflicting target snapshot: {overlap}");
bail!(
- "cannot merge group '{}/{}' from '{}' into '{}': snapshot time overlap",
+ "cannot merge group '{}/{}' from '{}' into '{}': snapshot time mismatch",
self.group.ty,
self.group.id,
self.ns,
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 292c56bff..dd5075675 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -1604,6 +1604,14 @@ impl DataStore {
group.group(),
)));
}
+ log::info!(
+ "{} group '{}/{}' from '{}' to '{target_group_ns}'",
+ if merge { "merging" } else { "moving" },
+ group.group().ty,
+ group.group().id,
+ group.backup_ns(),
+ );
+
if merge {
group
.check_merge_invariants(&target_group)
@@ -1620,14 +1628,6 @@ impl DataStore {
// the merge invariant (source oldest > target newest) valid on retry.
snapshots.sort_by_key(|s| s.backup_time());
- log::info!(
- "{} group '{}/{}' from '{}' to '{target_group_ns}'",
- if merge { "merging" } else { "moving" },
- group.group().ty,
- group.group().id,
- group.backup_ns(),
- );
-
// Each batch is locked, moved, and released before the next to exclude concurrent readers.
// `move_to` writes to the per-datastore move journal before each rename so a concurrent
// GC phase-1 drain can still mark the moved chunks; see `move_journal` for the race.
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH proxmox-backup 4/4] move namespace: use group(s)/namespace(s) consistently
2026-04-27 12:02 [PATCH proxmox-backup 0/4] move group/namespace logging improvements Fabian Grünbichler
` (2 preceding siblings ...)
2026-04-27 12:02 ` [PATCH proxmox-backup 3/4] move namespace: move context log line before check Fabian Grünbichler
@ 2026-04-27 12:02 ` Fabian Grünbichler
3 siblings, 0 replies; 5+ messages in thread
From: Fabian Grünbichler @ 2026-04-27 12:02 UTC (permalink / raw)
To: pbs-devel
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
pbs-datastore/src/datastore.rs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index dd5075675..ed303d551 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -1262,7 +1262,7 @@ impl DataStore {
let backend = self.backend()?;
log::info!(
- "moving namespace '{source_ns}' -> '{target_ns}': {} namespaces",
+ "moving namespace '{source_ns}' -> '{target_ns}': {} namespace(s)",
attempted_ns.len(),
);
@@ -1392,7 +1392,7 @@ impl DataStore {
.any(|failed| failed == ns || ns.contains(failed).is_some())
{
log::warn!(
- "skipping source namespace '{ns}' cleanup: contains groups that failed to move",
+ "skipping source namespace '{ns}' cleanup: contains group(s) that failed to move",
);
continue;
}
@@ -1423,7 +1423,7 @@ impl DataStore {
}
if depth_limited_child {
log::debug!(
- "keeping source namespace '{ns}': contains namespaces excluded by max-depth",
+ "keeping source namespace '{ns}': contains namespace(s) excluded by max-depth",
);
continue;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread