Skip to content

fix(app): keep the exit save overlay stable while disks save in parallel - #252

Merged
coldhighsun merged 1 commit into
mainfrom
fix/exit-save-progress-flicker
Oct 13, 2026
Merged

coldhighsun merged 1 commit into
mainfrom
fix/exit-save-progress-flicker

Conversation

@coldhighsun

Copy link
Copy Markdown
Owner

Summary

When several RAM disks are saved in parallel on exit, each progress report overwrote the overlay with its own disk's name and byte counts, so the status text and progress bar flickered between disks. Reports could also be delivered out of order, nudging the bar backwards.

The overlay now shows an aggregate instead of whichever disk reported last.

Changes

  • ExitSaveProgressTracker (new, thread-safe): folds the per-disk reports into one monotonic, size-weighted state with a fixed byte total known before the first report. The bar and the byte count share a 99% ceiling until the save is completed, so an untracked disk that is still saving cannot be hidden behind a full bar.
  • Overlay texts: "Saving N disk images (k/N done)" for several disks, the disk's own name for one, "Finishing up..." once every disk is done, and "M of N disk images could not be saved" when the save ended with failures. Strings are added in both languages.
  • Refresh path: the save threads only update the tracker. The screen is refreshed through the new CoalescingSignal at Background priority, so a burst of reports cannot flood the dispatcher or delay input.
  • Failures: SaveFailed marks a disk as failed only once its own final save has begun, so an earlier periodic auto-save failure does not mark a disk whose final save then succeeds. A failed disk is never shown as finished.
  • MountManager.Dispose(Action<RamDisk, double>): the callback now reports only the disk and its own fraction. The overall fraction, the used-byte count and DisposeProgressAggregator (with its tests) are removed, since the app aggregates by size itself.
  • RamDisk.WillSaveOnDispose (backed by RamDiskSaveDecisions): tells the app which disks will really be written, so clean disks are not counted as "disk images".
  • Shutdown robustness: collecting the sizes and finishing the display are isolated teardown steps, so a failure there cannot skip the exit save.
  • CLAUDE.md documents the exit-save progress pipeline and its ordering rules.

Notes

  • MountManager.Dispose(Action<RamDisk, double, double, ulong>) is replaced by a two-argument overload. The app is the only caller.
  • The wiring in App.ShutdownAsync (CollectExitSaveSizes, the SaveFailed hookup, BeginExitSave before Dispose) is not unit-tested because it needs a real RamDisk (WinFsp driver) or the WPF App.
  • SettingsStoreTests.Update_ConcurrentUpdatesOfDifferentFields_KeepsEveryChange failed intermittently on some runs. It is unrelated to this change and passes on rerun.

Test plan

  • dotnet build ManagedDrive.slnx (no warnings)
  • dotnet test tests/ManagedDrive.Tests (1859 tests; new tests for the tracker, CoalescingSignal, the view model texts and the localization keys)
  • Manual: mount 3 disks with data, exit, and check the text is stable and the bar and bytes only increase
  • Manual: exit with unchanged disks and check the overlay keeps "Saving disk images, please wait..."

When several disks were saved in parallel on exit, every progress report
overwrote the overlay with its own disk's name and byte counts, so the text and
bar flickered between disks.

The overlay now shows an aggregate. ExitSaveProgressTracker folds the per-disk
reports into one thread-safe, size-weighted, monotonic state: a fixed byte total
known up front, "Saving N disk images (k/N done)" for several disks, the disk's
own name for one, and distinct texts for finishing and for failed saves. The
save threads only update the tracker; the screen is refreshed through a
coalescing signal at background priority so it cannot flood the dispatcher.

MountManager.Dispose now reports just (disk, fraction), without the overall
fraction, the byte count or the aggregator, and RamDisk.WillSaveOnDispose tells
the app which disks will really be written.
@codecov

codecov Bot commented Oct 13, 2026

Copy link
Copy Markdown

@coldhighsun
coldhighsun merged commit b0548d6 into main Oct 13, 2026
6 checks passed
@coldhighsun
coldhighsun deleted the fix/exit-save-progress-flicker branch October 13, 2026 15:08
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.

1 participant