From 6330a1b05fd9c6de283d01cfa3e669b40c790e4d Mon Sep 17 00:00:00 2001 From: laurentiu021 Date: Wed, 17 Jun 2026 19:44:33 +0300 Subject: [PATCH] fix: clear persisted performance snapshot on Restore All and serialize baseline capture --- CHANGELOG.md | 6 ++++++ .../SysManager/Services/PerformanceService.cs | 16 ++++++++++++++ SysManager/SysManager/SysManager.csproj | 6 +++--- .../ViewModels/PerformanceViewModel.cs | 21 +++++++++++++++---- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2a1dd6..a55adbb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.20.41] - 2026-06-17 + +### Fixed +- **"Restore All" in Performance Mode now fully clears the saved baseline.** After restoring everything to the original state, the on-disk snapshot was left behind, so the next change reloaded the now-reverted values as its baseline — a later "Restore All" could then re-apply stale settings. The saved snapshot is now deleted when you restore all. +- **Applying several performance tweaks at once can no longer race the baseline capture.** The independent Apply buttons (power plan, visual effects, Game Mode, Xbox Game Bar, GPU, processor state) each captured the "before" snapshot without coordination, so two run together could both think no baseline existed. Baseline capture is now serialized so the original state is recorded exactly once. + ## [1.20.40] - 2026-06-17 ### Fixed diff --git a/SysManager/SysManager/Services/PerformanceService.cs b/SysManager/SysManager/Services/PerformanceService.cs index 22e428ce..48057694 100644 --- a/SysManager/SysManager/Services/PerformanceService.cs +++ b/SysManager/SysManager/Services/PerformanceService.cs @@ -121,6 +121,22 @@ public static void SaveSnapshot(OriginalSnapshot snapshot) catch (UnauthorizedAccessException ex) { Log.Warning(ex, "Failed to save performance snapshot"); } } + /// + /// Delete the persisted snapshot from disk. Called after "Restore All" so the next + /// Apply captures a fresh baseline instead of reloading the now-reverted pre-restore + /// state via . + /// + public static void DeleteSnapshot() + { + try + { + if (File.Exists(SnapshotPath)) File.Delete(SnapshotPath); + Log.Information("Performance snapshot deleted from {Path}", SnapshotPath); + } + catch (IOException ex) { Log.Warning(ex, "Failed to delete performance snapshot"); } + catch (UnauthorizedAccessException ex) { Log.Warning(ex, "Failed to delete performance snapshot"); } + } + /// Load a previously saved snapshot from disk. Returns null if none exists. public static OriginalSnapshot? LoadSnapshot() { diff --git a/SysManager/SysManager/SysManager.csproj b/SysManager/SysManager/SysManager.csproj index ed6cb9b7..91cba233 100644 --- a/SysManager/SysManager/SysManager.csproj +++ b/SysManager/SysManager/SysManager.csproj @@ -10,9 +10,9 @@ SysManager true NU1603;NU1701 - 1.20.40 - 1.20.40.0 - 1.20.40.0 + 1.20.41 + 1.20.41.0 + 1.20.41.0 SysManager SysManager — Windows system monitoring toolkit by laurentiu021. Network, updates, health, logs, safe deep cleanup. https://github.com/laurentiu021/SystemManager diff --git a/SysManager/SysManager/ViewModels/PerformanceViewModel.cs b/SysManager/SysManager/ViewModels/PerformanceViewModel.cs index 907b5342..fbeedf91 100644 --- a/SysManager/SysManager/ViewModels/PerformanceViewModel.cs +++ b/SysManager/SysManager/ViewModels/PerformanceViewModel.cs @@ -27,6 +27,9 @@ public sealed partial class PerformanceViewModel : ViewModelBase { private readonly PerformanceService _service; private PerformanceService.OriginalSnapshot? _snapshot; + // Serializes the load-modify of _snapshot so two Apply commands running at once + // can't both observe a null snapshot and race the capture/save. + private readonly SemaphoreSlim _snapshotGate = new(1, 1); [ObservableProperty] private bool _isElevated; [ObservableProperty] private PerformanceProfile _profile = new(); @@ -71,10 +74,15 @@ private async Task InitAsync() /// Ensure snapshot exists before any change. private async Task EnsureSnapshotAsync() { - _snapshot ??= PerformanceService.LoadSnapshot() - ?? await _service.TakeSnapshotAsync(); - PerformanceService.SaveSnapshot(_snapshot); - HasSnapshot = true; + await _snapshotGate.WaitAsync().ConfigureAwait(false); + try + { + _snapshot ??= PerformanceService.LoadSnapshot() + ?? await _service.TakeSnapshotAsync(); + PerformanceService.SaveSnapshot(_snapshot); + HasSnapshot = true; + } + finally { _snapshotGate.Release(); } } private void UpdateSummary() @@ -508,6 +516,10 @@ private async Task RestoreAllAsync() Log.Information("Performance settings restored to original snapshot"); _snapshot = null; HasSnapshot = false; + // Delete the persisted snapshot too — otherwise the next Apply reloads the + // now-reverted pre-restore baseline via LoadSnapshot and a later Restore All + // would re-apply stale values. + PerformanceService.DeleteSnapshot(); await RefreshAsync(); } catch (InvalidOperationException ex) { StatusMessage = $"Restore all settings failed: {ex.Message}"; } @@ -561,6 +573,7 @@ protected override void Dispose(bool disposing) if (disposing) { _snapshot = null; + _snapshotGate.Dispose(); } base.Dispose(disposing); }