Skip to content

Fix tracking selected full backup state#1246

Closed
iliaross wants to merge 7 commits into
masterfrom
fix/selected-full-snapshot-promotion
Closed

Fix tracking selected full backup state#1246
iliaross wants to merge 7 commits into
masterfrom
fix/selected-full-snapshot-promotion

Conversation

@iliaross

@iliaross iliaross commented Jul 2, 2026

Copy link
Copy Markdown
Member

Hello Jamie!

This PR improves snapshot handling for selected full backup chains as discussed in #1238 (comment).

Now selected full-backup state is retained only for domains whose full backup reaches at least one durable destination. Successful selected full snapshots are promoted, while snapshots from failed selected full backups are removed so future differentials do not silently depend on an unusable full backup.

This PR improves snapshot handling for selected full backup chains.

Selected full-backup state is now retained only for domains whose full backup reaches at least one durable destination. Successful selected full snapshots are promoted, while snapshots from failed selected full backups are removed so future differentials do not silently depend on an unusable full backup.
@iliaross

iliaross commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Jamie, I've fixed the merge conflict. Please take a look.

@iliaross

iliaross commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

I believe it needs more fixes... I will update this with progress.

ⓘ Promote selected full backup snapshot state only for referenced full-backup chains, and remove the stale per-domain promotion path from `feature-dir.pl`.
@iliaross

iliaross commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

Jamie, this is ready for review now.

@iliaross

iliaross commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Jamie, is this good to merge or not?

@jcameron

Copy link
Copy Markdown
Collaborator

So can you explain the failure mode that this PR fixes? Because in a regular backup to a local destination, the incremental file is updated in feature-dir.pl after the archive is created..

@iliaross

Copy link
Copy Markdown
Member Author

So can you explain the failure mode that this PR fixes? Because in a regular backup to a local destination, the incremental file is updated in feature-dir.pl after the archive is created..

Yeah, for local backups.

Yet this issue only affects a full backup selected as a differential base. If final packaging or upload fails after tar updates its state, that state points to a backup that doesn’t exist.

This PR keeps the state if at least one destination succeeds or otherwise, it removes it, with existing incremental behavior is unchanged.

@jcameron

Copy link
Copy Markdown
Collaborator

Ok so the potential problem is that if an incremental backup fails to be uploaded to it's destination, we shouldn't update the state file?

Or is it that if a full backup fails to upload we shouldn't clear the state file?

I'm not quite sure of the full sequence of events this is fixing..

ⓘ Stage and lock selected-full snapshot state, publish it only after each domain archive reaches a durable destination, and discard unusable state on failure.
@iliaross

Copy link
Copy Markdown
Member Author

The issue is with a full backup that is selected as the base for future differentials, not with a failed differential upload.

The failure sequence is:

  1. tar --listed-incremental updates the selected full’s snapshot state while creating the home archive.
  2. The backup can still fail later, during packaging, metadata writing, or upload.
  3. If we keep that new state, the next differential can be created against a full backup that never reached any durable destination.
  4. That leaves an unrestorable chain.

So yes, the important case is "if a selected full backup fails to upload, we should not keep and publish the new state”. And, I added a few more fixes on the latest commit because the earlier version still could published state too early.

The current version of this PR should make selected-full state fail closed.

Comment thread backups-lib.pl
# Serialize access to every snapshot this backup can read or replace. These
# locks are acquired before domain locks and held until state is finalized, so
# overlapping full and differential runs cannot publish, restore or remove each
# other's snapshot generation.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there already protection against multiple backups running at the same time for the same domain though, via locking? That should protect against this kind of failure.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sufficient protection. The existing domain lock is released, while upload and snapshot publication happen much later.

So destination locking only protects jobs using the same destination URL. Two backups for the same domain but different destinations can potentially overlap, like:

  • Full backup creates its staged snapshot
  • It releases the domain lock and starts uploading
  • A differential backup acquires the domain lock and accesses snapshot state
  • The full backup later publishes or discards that state

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet, these a3a206f locking will be better to avoid lock_file timeouts.

Comment thread backups-lib.pl
}
}
@incremental_lockfiles = sort @incremental_lockfiles;
foreach my $lockfile (@incremental_lockfiles) {

@jcameron jcameron Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't get_incremental_file already create the directory for the file it returns?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It only returns a pathname.

Comment thread backups-lib.pl
# Invalidate every selected snapshot before the first domain is archived. If
# this process is terminated part-way through a multi-domain backup, no domain
# that was not reached can retain state for an older full backup generation.
if ($selected_full) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can exclude this, that feels like an over-complication for a very rare situation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather simplify this if necessary, but not remove this crash protection completely. That prevents an interrupted run from leaving old state for a domain whose archive may already have been replaced, without invalidating every domain at the start, right?

Comment thread backups-lib.pl Outdated
iliaross added 2 commits July 12, 2026 03:32
ⓘ Serialize full and differential snapshot access with blocking `flock` handles held through final publication or discard. This avoids `lock_file` timeouts and automatically releases locks when a backup exits.
ⓘ Remove redundant ownership and mode verification after snapshot creation and rename, while failing publication if setting the required ownership or permissions fails.

#1246 (comment)
@jcameron

Copy link
Copy Markdown
Collaborator

So I had a look again at the current logic that is supposed to handle the case of a failed full backup, and realized that it doesn't treat failed uploads properly in the case of a full backup, as you correctly pointed out. But the fix to me seems as simple as : ef6b148

If this doesn't work, I would be really interested to see a sequence of Virtualmin CLI commands that demonstrate the problem. I was able to trigger it via a SSH full backup for a single to a working destination, then another SSH backup to a different destination with permissions that prevented an upload.

@iliaross

Copy link
Copy Markdown
Member Author

I think you're right. My PR though also handled crashes and partial multi-destination success, but that extra complexity likely isn't justified. I will rather close this for now.

And, for your latest change you could use !$ok instead of tracking new $remotefailed, right?

@iliaross iliaross closed this Jul 14, 2026
@iliaross
iliaross deleted the fix/selected-full-snapshot-promotion branch July 14, 2026 00:43
@jcameron

Copy link
Copy Markdown
Collaborator

I think you're right. My PR though also handled crashes and partial multi-destination success, but that extra complexity likely isn't justified. I will rather close this for now.

Thanks! But does my fix really address all the issues you found originally though? I am surprised that it's so much simpler.

And, for your latest change you could use !$ok instead of tracking new $remotefailed, right?

I considered that, but since $ok is used as an indicator that the archiving process failed in which case @errdoms should already be populated, I felt it was more readable to use $remotefailed.

@iliaross

Copy link
Copy Markdown
Member Author

But does my fix really address all the issues you found originally though?

No, not really. Yet, I thought you wanted to keep it more simple... and this is why I closed it.

I considered that, but since $ok is used as an indicator that the archiving process failed in which case @errdoms should already be populated, I felt it was more readable to use $remotefailed.

Got it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants