Repository navigation
fix(backup): remove scratch that a stopped backup left behind - #1671
Merged
Merged
Conversation
On 13 October 2026 systemd stopped Core on the home box mid-backup. Its raw copy stayed in /dev/shm (1.37 GB), so on 16 October the next copy went to the SD card and ran past the two-hour limit. A backup now holds a shared flock on each folder where it keeps scratch. At start Core takes that lock exclusively without waiting. When it gets it, no backup is running there, so it removes ftw-backup-<n>.raw and its journal from /dev/shm, and stage folders, verification folders and unfinished archives from the backups folder. It logs each path and size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On 13 October 2026 systemd stopped Core on the home box while a full backup was copying. The process exited before its deferred cleanup ran. It left
/dev/shm/ftw-backup-4218622654.raw(1.37 GB) and its-journal, and nothing removes them before a reboot. On 16 OctoberbackupScratchFilefound too little free space in/dev/shm, so the raw copy went to the SD card. The backup slowed to about 2,000 rows/s and hit the two-hourliveBackupTimeout. #1670 explains that failure and logs it; this change removes the cause.Change
At start, after it resolves the backups folder and before it can accept a backup, Core removes scratch that stopped backups left:
/dev/shm:ftw-backup-<digits>.rawandftw-backup-<digits>.raw-journal, regular files only;.ftw-backup-stage-<digits>/and.ftw-backup-verify-<digits>/folders, and unfinished.ftw-full-backup-*.ftwbak.tmparchives.A run stopped while packing or verifying leaves the last two on the data disk, often larger than the raw copy, so they are included. Nothing else matches: not published
.ftwbakarchives, their.verified.json,.ftw-pre-restore-*safety copies, symlinks, or names with other suffixes. Core logs each removed path with its size in bytes.How Core tells a stopped backup from a running one
A backup holds a shared
flockon each folder where it keeps scratch: the folder of the raw copy (/dev/shm, or the stage folder when it falls back), the output folder for the whole ofbackup.Create, and the folder a verification works in. The kernel drops aflockwhen the process exits, also on SIGKILL. At start Core asks for the same lock exclusively and does not wait. If it gets it, no backup is running in that folder, so every matching entry is a leftover. If not, a running backup may own them, and Core keeps all of them and says so in the log.That protects an
ftw-backup createrun or a second Core on the same host. The lock is on the folder itself, so no lock file is left anywhere. It is never on a SQLite file:flockand SQLite'sfcntllocks are independent on local Linux file systems, but NFS emulates one with the other.Where Core cannot take the exclusive lock, it keeps everything; Windows, which has no
flock, never removes anything. A backup that cannot take its shared lock still runs.Overlap with #1670
#1670 edits
backupScratchFileand addsbackupShmDir. This change stays out of both. Its only line instore.gois two lines below #1670's hunk, with unchanged lines between them.RemoveStaleBackupScratchInShmnames/dev/shmitself. Whichever PR lands second should point it atbackupShmDir; that is a one-line follow-up.#1615 also edits
archive.go, inInspect; the hunks do not touch.Tests
TestKilledBackupScratchIsRemovedAndLiveScratchKeptstarts a helper process that holds a folder and writesftw-backup-2.raw. While it runs, the cleanup keeps its file and journal. After SIGKILL, the cleanup removes both, reports 4,608 bytes and logs the path withbytes=4096. Five decoys with similar names survive.TestRawCopyFolderIsHeldWhileCopyingfinds the backup's own raw copy (beside the destination, or in/dev/shmthrough/proc/self/fd) at each progress report and checks that its folder is locked.TestRunningBackupKeepsItsScratchruns the cleanup at every progress step of a realCreateand then of a verification. It removes nothing, and both finish.TestStaleScratchIsRemovedAndArchivesKeptremoves a stage folder, a verification folder and an archive temp (6,000 bytes) and keeps archives, their verification records, a restore safety copy and unrelated files./dev/shm, where the raw copy goes to tmpfs, and with 64 MB, where it falls back to the stage folder. With the raw-copy hold removed, the Linux run fails withnothing holds /dev/shm while /dev/shm/ftw-backup-3714948555.raw is written.make verifypasses on macOS arm64.GOOS=windowsbuilds and vetsstateandbackup.No command ran on the home box. Its leftover goes away when it first starts a Core with this change.
🤖 Generated with Claude Code