Fixes and improvements from running 2.4.1 on 4 PCs with large saves — how would you like them?
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 8/100
Direzione di ricerca
This is a coordination thread for a large body of work in progress, not a task to start from. It names many open PRs (#49, #51, #52, #56, #68, #69, #70, #72), and the maintainer is waiting on design choices, including #71's push loop. Newcomers should not pick it up; instead look for a separate issue with one named failing test, such as TestSoak_ManyAlternatingRoundsNeverConflict.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Status (updated 2026-10-26)
Everything goes into dev-public. Each PR's description has the details; this is the map.
How these were found. Every fix here started from a real failure, mostly a red CI run, and was reproduced before it was fixed: each comes with a test that fails without it. #61–#65 came out of a long run of the e2e tests on Windows runners with the race detector, about 155,000 test runs over 11 rounds. For example, "daemon never became ready" appeared 10 times in about 28,000 runs before #61 and not once in about 52,000 after. With all fixes together, one round ran about 33,000 tests without a failure. Where a cause is inferred rather than reproduced, the PR says so.
Merged — thank you: #22, #23, #24, #25, #28, #49, #50, #52, #53, #54, #55, #56, #57, #58, #61, #62, #63, #64, #65, #68, #69, #70, #72, #73, #74, #78, #80, #84, #90, #98, #99, #100, #106, #107, #113, #115 and #116.
Open, in the order I'd suggest:
| PR | Why |
|---|---|
| #114 | A save folder that can't be written is said once, with what to do, and retried after 30 minutes. Updated as you asked: a file the game holds open isn't mistaken for it. |
| #118 | Device settings found by what the files hold, as suggestions that keep syncing until confirmed. Updated as you asked (IF NOT EXISTS), and the snapshot history is now compared by the database. Migration 0042. |
| #117 | A game being played is held back from syncing until its session ends. Updated as you asked: one idle rule (no processor time for five minutes), and a session gone all but idle for an hour without a save ends. |
| #125 | A snapshot taken in the millisecond a session began is named for it (TestSessionNamesTheSnapshotAlreadyTaken failed 11 in 40 on Windows). |
| #126 | "Track game" lists the games running now first. |
| #51 | A false conflict when a device edits again before the other has recorded what it took. |
| #26 | Sync speed: batched small files, an "unchanged" manifest shortcut, presence probed on its own. |
| #27 | Closest devices first, by measured link speed. Migration 0039 (now IF NOT EXISTS). Needs #26. |
Drafts that build on the above:
| PR | Why | Needs |
|---|---|---|
| #127 | A game tracked without an App ID is offered its game database link, set only when confirmed. | #118 |
| #128 | Sessions for protected games and games installed anywhere; a safety net for games whose program isn't seen. | #117, #118 |
CI: red runs (as of 2026-10-17), and why
| Run | Where | Failing test | Cause |
|---|---|---|---|
| #375, #379, #384 | dev-public |
TestReportedWAN_AlternatingEditsMustNotConflict |
#71's push loop; fixed by #78 (merged). |
| #385 | #77 | TestJourney_DeviceSpecificConfigNeverTravels (step 2) |
Found at last, from the logs #57 prints: B's "sync-complete" report to A timed out (it has a 2 s limit and isn't retried), so A's base stayed a round behind and B's next save read as "both sides modified". Same failure as #314, #328, #334, #361. Fixed by #80 (merged). |
| #381 | dev-public |
TestCrossingSyncs_AFirstPullIsNotTakenForADifferentSave |
The same reports timing out, in both directions, over a minute: the receiving daemon seems to hold them while it applies a sync. Addressed by #80 (merged). |
| #394 | #80 | TestBranchFollow_FetchesTheOtherDevicesSaveNotDeletesIt |
A's once-a-minute sync switched it back to the old branch before B could follow: #85. |
| #386 | #52 | TestDeletion_SurvivesALostReportWhenServed |
Not reproduced: 0 failures in 648 runs with the race detector, under load, on current dev-public. Probably the same timing, fixed by #80. |
Waiting on you
- Reviews, in the order above.
- Your view on the question in the latest comment: whether to remove automatic snapshots that are only steps on the way to a newer one.
Waiting on me
- Nothing open.
Postponed, as you asked: save versions: design issue #29 and drafts #30, #31 and #36. Draft #34 is closed (replaced by #117 and #128). Draft #32 closes once #114 is in, since its other parts are in dev-public (#116 and the launcher files). The gap tests in an earlier comment suggest versions are no longer needed for safety; I'll go by what you decide.
Test build: https://github.com/ChakraFusion/OpenSave/releases/tag/v2.4.1-fixes.9 (unofficial pre-release on my fork).
Background: the original post (2026-10-04)
Hi! I've been running OpenSave across four Windows PCs (LAN plus VPN), with some large saves. The largest is Project Zomboid at ~240k files. Along the way I found several bugs, a few of which delete or lose save data, and fixed them in my fork:
https://github.com/ChakraFusion/OpenSave/tree/fixes-2.4.1
- The fork passes your full CI (Linux and Windows, race detector, e2e).
- It has been tested by hand on all four PCs, including emptied folders, interrupted restores, offline changes and real conflicts.
- A test build for all platforms (unofficial pre-release on my fork): https://github.com/ChakraFusion/OpenSave/releases/tag/v2.4.1-fixes.9
I've split it into focused PRs, as the README asks. Every branch passes CI on its own. The ones marked standalone apply to v2.4.1 directly. The rest are stacked: each builds on the one before, and I'll rebase them as earlier ones land. The larger features are linked to issues so we can discuss the approach first, but the code is ready, so you can read it alongside.
Bug fixes
- "Keep mine" can delete files on the device whose version was kept: a 300-file save becomes 100 files on v2.4.1. Adds a guard against syncs that delete most of a save. (standalone)
- Changes OpenSave writes itself are taken for the game saving: snapshot floods during a sync, and syncs echoing back. A save the game writes right after a pull now still counts as the game's. (standalone)
- A save folder on a different drive letter on another PC (
D:vsE:) is found, and a drive this PC doesn't have no longer raises a warning. (standalone)
Performance
4. Manifests and snapshots on large saves: rescanning 240k files 13–19 s → 1.3 s; a follow-up snapshot 80 s → 9 s. (standalone)
5. Batched small-file pulls, an "unchanged" manifest shortcut and gzip: 5,000 files 42 s → 12 s. Presence is probed every 10 s. (stacked on 1)
6. Network-aware sync: link speeds are measured, the closest devices are synced first, and VPN block fetches no longer fail on a fixed 30 s limit. (stacked on 5)
7. Smaller memory footprint (GOGC 50, 1 GiB soft limit). (standalone, optional)
Larger features (stacked, in this order)
8. Save versions: syncs decide by version vectors instead of guessing from files. This is the foundation for most of what follows. → design issue #29
9. Snapshot integrity: never incomplete; identified by content, so every PC agrees and keeps each snapshot once; snapshots fully contained in newer ones are removed.
10. Launcher files (Steam's remotecache.vdf) aren't saves; an unwritable folder is reported once and retried after 30 min; the snapshot after a pull is faster.
11. Device settings: per-PC graphics/config files are kept out of sync, from Ludusavi's config entries and content detection, with per-file control.
12. Play sessions: sync is held while a game is played anywhere; games are detected wherever installed, protected games included; an activity safety net covers unrecognised games.
13. "Track game" from the game database; one folder, one game, with an offer to link entries; folders holding only Steam's files are ignored.
14. Putting back an emptied save takes the other device's save and version; emptying isn't a version until confirmed.
15. Database: WAL, batched deletion-record clears (put-back went from ~1 hour in SQLite to seconds), and free space handed back.
16. Restore writes as many files at once as the drive does best (HDD, SATA or NVMe), with progress and time left.
Coordination
- Migrations: mine continue after
0037_game_root_mapped, numbered 0038–0043 in stack order. I'll renumber them if anything lands in between. - i18n: I'll follow #18 / #20. New UI text can go through the i18n setup once the components I touch are extracted, or I can do that extraction myself.
- Flaky tests on your CI: two of your own tests failed intermittently for me on plain v2.4.1,
TestJourney_DeviceSpecificConfigNeverTravels(CI) andTestSettings_AutoDeleteOldSnapshots_SweepsWhenSwitchedOn(locally under load). Happy to look into them if useful. - Extra save locations:
TestMultiRootScenario_ALateReportDoesNotHideADivergence("already in sync") failed twice on Windows runners for me. Without a merge base, an extra location falls back to comparing modification times against the peer-wide last-sync time, which any late report moves. I think save versions for extra locations would be the real fix, and I'm happy to do that as a follow-up once versions land.
Does this order and size work for you? Is there anything you'd rather not have, or would like done differently?
Where everything is
- Bug fixes: #22 (Keep mine), #23 (own writes), #24 (other drive letter)
- Performance: #25 (large saves), #26 (sync speed, on #22), #27 (network-aware, on #26), #28 (memory, optional)
- Save versions: design issue #29, draft PR #30
- Stacked on #30, in order: #31 snapshot integrity → #32 launcher files / unwritable folders → #33 device settings → #34 play sessions → #35 Track game → #36 put-back → #37 database → #38 parallel restore
- Lingua principale
- Go
- Stelle
- 225
- Fork
- 9
- Merge medio
- 1g 21h
- PR unite (30g)
- 72
Preparare l'ambiente
- Include un Dockerfile o un file Docker Compose
- Nessun modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Liquid-co/OpenSave
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Lack of support for CEMUAperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Liquid-co/OpenSave
Issue simili
-
[Bug] Custom tool truncation leaves unused stream copies openForse già presa @OUAO-FRANK l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
[v3] KeyBindingManager calls (Add/Remove) are not converted into a case-insensitive accelerator.KeyApertaBug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
crmne/hyprmoncfg#114 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
runtime: usleep sleeps nanoseconds instead of microseconds on linux/mips and linux/mips64Forse già presa @BRobertson7 l’ha presa oggi. Apertacompiler/runtime
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
golang/go#82913 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100