Recreate not removing excluded files when using lvm snapshots #1053
Labels
No labels
blocked
breaking
bug
data loss
design finalized
good first issue
new feature area
question / support
security
waiting for response
No milestone
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
borgmatic-collective/borgmatic#1053
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What I'm trying to do and why
I tried the new recreate command after adding a few additional exclude_patterns to my config. I expected the excluded files to be gone after recreeate, but they stayed available. The main motivation was freeing up space used by big temporary files I didn't exclude during the first few backups.
Steps to reproduce
exclude_patterns, e.g.- /home/foo/bar*/tmp/*.zstborgmatic -c foo.yaml -v 2 list --find "/home/foo/bar*/tmp/*.zst"borgmatic -c foo -v 2 recreate(observe that borgmatic is actually looking into each old archive)borgmatic -c foo.yaml -v 2 prune compact(I'm actually not sure if this is needed. Is it? I guess it's not needed for listing, but it might be needed to actually free up the space. Would be great if this was documented.info. But it is needed to actually free up the space. Running compact loggedRemote: compaction freed about 28.37 GB repository space.after applying the workaround mentioned below.)Actual behavior
list --find still finds the excluded files in the older archives
Expected behavior
list --find finds nothing
Other notes / implementation ideas
low prio issue I run into while testing: existing temporary target
While trying this and that, I interrupted borgmatic using ctrl-c. Later, a
recreatewas failing due toArchive foo-2025-03-22T03:30:03.675584.recreate already exists. Maybe it could delete that or just chose another name (at least when not using--target)low prio question
While waiting to recreate a dozen archives, I wondered why I cannot run read-only operations like info, list without acquiring an exclusive lock.
observation and possible reason for this issue
list --findlists the files like this:tmp/borgmatic-b7547a4w/borgmatic/lvm_snapshots/3751af5bd81011e6d21d/home/foo/bar-baz/tmp/baz_latest.tar.zstI guess
recreateneeds to respect the lvm-specific prefix. This may also be relevant for the other snapshotting mechanisms like zfs, btffs.verification and workaround
To verify this theory, I changed the exclude from
- /home/foo/bar*/tmp/*.zstto- '**/home/foo/bar*/tmp/*.zst'and re-ranrecreate. This actually removed the files from the old archives. After that,compactfreed up the space.borgmatic version
2.0.0.dev0 (HEAD is
d5d04b89dc)borgmatic installation method
pipx install --editable .
Borg version
borg 1.4.0 (with borg 1.2.8 on the server; the server is a Hetzner storage box)
Python version
Python 3.13.2
Database version (if applicable)
No response
Operating system and version
No response
Recreate not pruning/compacting files when using lvm snapshotsto Recreate not removing excluded files when using lvm snapshotsWow, thanks for taking this unreleased feature for a spin! That's brave of you. I think your theory is correct that the exclude patterns aren't matching because of how the LVM snapshot paths are stored.
The good news is that the "fix" for LVM paths being stored that way is to upgrade your server to Borg 1.4.x+. With that version of Borg, borgmatic stores LVM snapshot paths without the
tmp/borgmatic-b7547a4w/borgmatic/lvm_snapshots/3751af5bd81011e6d21dpath prefix, so the archive file path looks just like any other file—which your exclude patterns will match. With older versions of Borg (like 1.2.8), the path stripping feature isn't available and so borgmatic falls back to storing the "full" snapshot path. (This is mentioned briefly in the docs.)The bad news is that this doesn't help you with any of your already-snapshotted file paths. But the
**/exclude path work-around you discovered should address the problem. And because this is a problem solved "properly" by newer versions of Borg, I'm not really wild about modifyingrecreateor exclude patterns in general to compensate for it.Other questions you had:
--helpat your suggestion.--bypass-lock, which sadly is still not implemented in borgmatic (#427), but Borg supports it natively. I will say that I don't think this is an issue with Borg 2.Thank you for this instant and elaborate response including answers to all questions.
It's nice to see your docs fix is not only used when calling with
--helpon the the command line but also on the website. That's DRY 😎I like your priority: if it's fixed in borg 1.4, don't waste time on it. I guess I'll stick with the server-side borg version provided by Hetzner for now, but it's nice to know I could configure
remote_pathif I wanted to.I'm afraid automatically just prefixing
**/*(like with list --find) might even be dangerous if the exclude pattern is not very specific, so it's better up to the user to use this workaround manually, if desired.I appreciate your understanding here! I'm actually going to reopen this ticket though so I remember to look into the "archive already exists" issue.
The solution I ended on for this one was to just display a nicer error message:
There are also a few other variants of this error message now for related Borg recreate errors.
I went this way because I didn't feel great about auto-deleting an archive that a user wasn't explicitly requesting to be deleted, even if it's "just" a temporary archive. And it's not always a temporary archive;
borgmatic recreate --target foocan result in a Borg "archive already exists" error even thoughfoois not a temporary recreate archive.Anyway, this is implemented in main and will be part of the next release.
Released in borgmatic 2.0.2!
I want to amend that Hetzner Storage Boxes actually allow choosing between Borg 1.1, 1.2 and 1.4, so we can actually use borg 1.4 by configuring
remote_path: borg-1.4. The versions supported by Hetzner, the remote path argument and the current default version are documented here.Awesome, glad to hear you can change that on the server side!