refactor!: audit the codebase, fix backup safety bugs, and speed up backups - #24
Merged
Merged
Conversation
…ackups An audit of every file found data-safety bugs, slow paths, and a lot of code that defended against problems a single-player backup tool does not have. - Fix cleanup, delete, cancel, settings, runtime, and Git bugs that could lose a copy, hide a copy, skip the game's final save, or report a false success. End-to-end tests with real Git and real ZIP files reproduce each one. - Make a Git backup start a few git processes instead of one for each file, write each ZIP archive one time, copy the world with parallel workers, and batch deletes and the start-up catalog rebuild. - Remove duplicate helpers, dead code, test-only hooks in production classes, and tests that pinned old implementation details. Move the runtime logic into src/main, where it has tests. BREAKING CHANGE: WorldArchive no longer reads settings files from 0.1.0 or the shared Git repository of 0.1.0. Import that repository one time with Import > Repository.
|
Comments Outside DiffThese findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.
|
A failed ZIP delete counted as done when Files.exists returned false, which it also does when the drive is away. A failed unmark also skipped the catalog write that lists the kept copies again. Keep every copy whose delete fails, and write the catalog even when the deleted-backup list cannot be changed.
….3.9 The old 0.4.0 moved to Minecraft 26.3 and fixed bugs. This release rewrites most of the engine and breaks old data, so it takes the 0.4.0 number. Date the 0.4.0 changelog section, rename the old section to 0.3.9, and make the comments that describe the old release say 0.3.9.
ishaanko
added a commit
that referenced
this pull request
Sep 29, 2026
…ackups (#24) * refactor!: audit the codebase, fix backup safety bugs, and speed up backups An audit of every file found data-safety bugs, slow paths, and a lot of code that defended against problems a single-player backup tool does not have. - Fix cleanup, delete, cancel, settings, runtime, and Git bugs that could lose a copy, hide a copy, skip the game's final save, or report a false success. End-to-end tests with real Git and real ZIP files reproduce each one. - Make a Git backup start a few git processes instead of one for each file, write each ZIP archive one time, copy the world with parallel workers, and batch deletes and the start-up catalog rebuild. - Remove duplicate helpers, dead code, test-only hooks in production classes, and tests that pinned old implementation details. Move the runtime logic into src/main, where it has tests. BREAKING CHANGE: WorldArchive no longer reads settings files from 0.1.0 or the shared Git repository of 0.1.0. Import that repository one time with Import > Repository. * fix(cleanup): keep a ZIP copy listed when its delete fails A failed ZIP delete counted as done when Files.exists returned false, which it also does when the drive is away. A failed unmark also skipped the catalog write that lists the kept copies again. Keep every copy whose delete fails, and write the catalog even when the deleted-backup list cannot be changed. * chore(release): make this release 0.4.0 and rename the old 0.4.0 to 0.3.9 The old 0.4.0 moved to Minecraft 26.3 and fixed bugs. This release rewrites most of the engine and breaks old data, so it takes the 0.4.0 number. Date the 0.4.0 changelog section, rename the old section to 0.3.9, and make the comments that describe the old release say 0.3.9.
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
An audit of every file found three kinds of problems:
What this PR does
Safety fixes
Each fix has a test that failed before the fix. The end-to-end tests use real Git, real ZIP files, and real folders. The
0.4.0section ofCHANGELOG.mdhas the full list. The most important:git lfs installno longer runs on every backup. It could write hooks into the user's global Git hooks folder.Speed
Measured before and after on one machine:
A backup of an open world still reads every file two times, because the game can write while the copy runs.
Less code
src/mainandsrc/clientwent from 39,805 lines to 30,214 lines.supportpackage: one path validator, one inventory type, one manifest codec, one safe-text helper, and one file lock.src/main, where tests cover it. The Fabric side is a thin adapter.Tests
e2epackage runs the real engine through the productionServiceGraph.Breaking change
WorldArchive no longer reads settings files from 0.1.0 or the shared Git repository of 0.1.0.
CHANGELOG.mdgives the steps to import that repository one time with Import > Repository.Version
This PR is release 0.4.0. The release that had the number 0.4.0 (the move to Minecraft 26.3) is now 0.3.9 in
CHANGELOG.mdand in the code comments.mod_versionstays0.4.0. The oldv0.4.0tag and GitHub release are nowv0.3.9, sov0.4.0is free. After this PR merges, tag the merge commitv0.4.0.Needs a check in the game
No test can run Minecraft. These 20 checks need
./gradlew runClient.In-game checks
Start the game with
./gradlew runClient. Use a test worldwith a few chunks explored. For the Git checks, install Git and Git LFS, and
make a bare repository with
git init --bare <folder>/remote.git. Use itsabsolute path as the world's Git remote on the Worlds settings tab.
Backups while you play
Exit backup and its toast.
Expected: the toast shows "Creating backup... Keep Minecraft open until it
finishes.", then "Backup finished. You can safely quit Minecraft." in green.
After Cancel, the toast shows "Cancelling backup...", then "Backup cancelled.
Your world was saved."
Manual backup of the open world keeps /save-off.
/save-off.Expected: the backup succeeds. The log shows no autosave lines for the
6 minutes, because autosave stays off as you set it.
Schedule, pause, and a world that is off.
the interval to 1 minute. Save.
for 2 minutes.
Expected: step 2 makes a backup each minute. Step 3 makes no backup and
no chat line. Step 4 makes no backup and no chat line.
Linked saves folder and linked world folder.
.minecraft/savesto another place and link itback:
ln -son Linux or macOS,mklink /Jon Windows.Backups.
of the whole saves folder.
Expected: the Backups button works, the icon opens the backup browser,
and the exit backup is made, in both cases.
Quit during an exit backup.
Expected: "Saving world" stays for at most about 35 seconds. At the next
start, the title screen shows one toast: "Minecraft closed before the
world-exit backup finished, so that backup was not made." The toast does
not come back after a second restart.
A folder change while a backup runs, and the Create tooltip.
Save.
tab, save, and hover over Create in the backup browser.
Expected: the save is refused with "Backup folders cannot change while a
backup, restore, delete or import is running. Try again when it has
finished." The Create tooltip says "Backups are off for this world.
Turn them on in Settings, on the Worlds tab."
Backup browser
Filter, rows, and reload.
text and wait 2 seconds.
edge of the screen.
open while a scheduled backup runs.
Expected: the cursor and the focus stay in the filter. A row reads
"date · label · trigger". The tooltip stays inside the screen. The action
buttons have a 4-pixel gap. The list reloads by itself when the scheduled
backup finishes.
Paging labels.
Expected: the page buttons read Previous and Next, not "<" and
">", and they do not overlap other buttons.
Delete
Delete prompts and results.
scale 3.
Expected: the one-backup prompt says "Delete this backup from every
destination? You cannot undo this." and "Its copy on your Git remote is
deleted too." The 3-backup prompt names each backup by date and label and
says "1 of them have a label. A label does not protect a backup from
Delete." The 7-backup prompt ends with "...and 2 more". The buttons stay
on the screen. The results say "Deleted 1 backup", "Deleted 3 backups",
and "Deleted 7 backups" in green.
A remote that refuses the delete.
git --git-dir=<folder>/remote.git config receive.denyDeletes true.Expected: the result says "No backups were deleted" in red. A line names
the backup by date and label and gives the remote's reason. The backup
stays in the list with its Git copy.
Sync, Verify, Restore, and Cancel
Cancel buttons.
ssh://git@10.255.255.1/remote.git. Select a backup and click Sync,then Cancel.
Expected: Sync shows "Cancelling sync...", then "Sync cancelled". Verify
shows "Cancelling verification...", then "Verification cancelled". Create
shows "Cancelling backup...", then "Backup cancelled". Restore shows
"Cancelling restore...", then "Restore cancelled", and no new world folder
is in
saves. Delete shows "Please wait…" and has no Cancel.Restore prompts and names.
and click Restore.
con,a|b,x., and the folder name ofthe original world.
Expected: the prompt has the line "This leaves the world you are
playing." and a line about the Minecraft version of the backup. The name
box refuses all four names.
Restore from Edit World.
Backups.
Expected: the new world and the original world are both in the list.
Storage and cleanup
Storage limits and cleanup rows.
save. Hover over Review Cleanup.
1,5as the limit and save again.confirmation rows.
of them.
Expected: Review Cleanup is off, and its tooltip says "Save the
policy first; cleanup uses the saved limit". The limit
1,5reads back as1.5. Preview and confirmation rows show the same "date · label · action ·
N changed" text. Toggling one protected Git row toggles the whole group.
Import
Import screens.
https://user:pass@example.com/r.gitinto Repository address, and click Find Backups from Repository.
the list.
Expected: step 1 shows the reason, for example that the address must not
contain a password. Step 2 shows "No folder was selected". In step 3 the
status with conflicts is yellow, and it is green only for a clean import.
Settings
Unreadable settings file.
config/worldarchive.jsonwith the textnot json.Expected: step 2 shows "WorldArchive settings could not be read (...), so
backups are paused. Open Settings to fix or reset them." Step 3 shows
"Settings could not be read: ..." and only Reset settings and
Cancel. After the reset, the screen says "Settings were reset. The old
file was kept as worldarchive.json.unreadable-..." and that file is in
config. In step 4 the world list loads, and backups work again.Save failure and world problems.
configfolder read-only. Change a setting and clickSave.
ZIP folder to a folder inside another world, and save.
saves. Start the game and openthe Worlds tab.
Expected: step 1 shows "Settings could not be saved: ..." with the
reason. Step 2 marks the world red and shows its problem. Step 3 shows
" is a copy of , so it now has its own backup history".
Folder picker, footer, and text.
an xdg-desktop-portal service.
1280x720 window. Open the settings screen.
Expected: the system folder dialog opens. Without a portal, the screen
says "The native folder picker failed; type an absolute path instead".
The footer shows Git, Git LFS, and folder state, and no "Remote" item.
The help text says "Paste the address of this world's Git repository.
Each new backup uploads to it. If an upload fails, choose Sync on that
backup to try again." No text overlaps with Force Unicode Font.
World list integration
Backups buttons and Open Folder.
Make Backup and Backups on the Edit World screen again.
click Open Folder. Then make a Git backup.
Expected: there is always one Backups button, never two. The Edit
World buttons still work after you come back. Open Folder opens the
nearest existing folder and makes no empty
<world id>.gitfolder. TheGit backup succeeds.
Screens changed in the final stage.
and pick a folder of ZIP archives.
Restore.
Expected: step 1 opens the settings screen and returns to World
Backups. Step 2 opens the folder dialog and then the import preview.
Step 3 shows the version notice for the backup's version and the running
version. Step 4 shows the same result headlines as before, for example
"Backup completed", "Backup synchronized", and "Backup verified", with
one line for each copy.