Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions CompactGUI.Watcher/BackgroundCompactor.vb
Original file line numberDiff line numberDiff line change
Expand Up@@ -64,24 +64,33 @@ Public Class BackgroundCompactor
End Function


Public Async Function StartCompactingAsync(folders As IEnumerable(Of WatchedFolder)) As Task(Of Boolean)
Public Async Function StartCompactingAsync(folders As IEnumerable(Of WatchedFolder), Optional startCancellationToken As CancellationToken = Nothing) As Task(Of Boolean)
If IsCompactorActive Then Return False
If startCancellationToken.IsCancellationRequested Then Return False

cancellationTokenSource?.Dispose()
Dim runCancellation = New CancellationTokenSource()
cancellationTokenSource = runCancellation

WatcherLog.BackgroundCompactingStarted(_logger)
IsCompactorActive = True
isCompacting = True
isCompactingPaused = False

Dim currentProcess As Process = Process.GetCurrentProcess()
Dim originalPriority As ProcessPriorityClass = ProcessPriorityClass.Normal
Dim priorityChanged As Boolean = False

Try
WatcherLog.BackgroundCompactingStarted(_logger)
IsCompactorActive = True

'Publish the initial pause state before marking the run active. If system activity
'resumes before this point, the start token catches it below; if it resumes after
'this point, PauseCompacting can safely record the pause for the new compactor.
isCompactingPaused = False
isCompacting = True

If startCancellationToken.IsCancellationRequested Then Return False

originalPriority = currentProcess.PriorityClass
currentProcess.PriorityClass = ProcessPriorityClass.Idle
priorityChanged = True

For Each folder In folders.ToList
If runCancellation.IsCancellationRequested Then Return False
Expand DownExpand Up@@ -187,13 +196,14 @@ Public Class BackgroundCompactor
End If
runCancellation.Dispose()

Try
currentProcess.PriorityClass = originalPriority
Catch ex As Exception
_logger.LogDebug(ex, "Unable to restore CompactGUI process priority.")
Finally
currentProcess.Dispose()
End Try
If priorityChanged Then
Try
currentProcess.PriorityClass = originalPriority
Catch ex As Exception
_logger.LogDebug(ex, "Unable to restore CompactGUI process priority.")
End Try
End If
currentProcess.Dispose()
End Try
End Function

Expand DownExpand Up@@ -359,4 +369,4 @@ Public Class BackgroundCompactor
isCompactingPaused = False ' Reset pause state on cancellation
End Sub

End Class
End Class
31 changes: 27 additions & 4 deletions CompactGUI.Watcher/Watcher.vb
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,7 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi
Private ReadOnly _parseWatchersSemaphore As New SemaphoreSlim(1, 1)
Private ReadOnly _runWatcherSemaphore As New SemaphoreSlim(1, 1)
Private _runCancellationTokenSource As CancellationTokenSource
Private _runIsIdleTriggered As Boolean
Private ReadOnly _runCancellationLock As New Object

Private ReadOnly _logger As ILogger(Of Watcher)
Expand DownExpand Up@@ -107,6 +108,7 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi

SyncLock _runCancellationLock
_runCancellationTokenSource = ownedCancellation
_runIsIdleTriggered = Not runAll
End SyncLock
IsRunning = True

Expand All@@ -128,7 +130,7 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi
Return False
End If
If _parseWatchersSemaphore.CurrentCount <> 0 AndAlso (IsBackgroundCompactingEnabled OrElse runAll) Then
Await BackgroundCompact(runAll) 'The background compactor manages its own cancellation token.
Await BackgroundCompact(runAll, If(runAll, CancellationToken.None, runToken)) 'The background compactor manages its own cancellation token once started.
End If
If runToken.IsCancellationRequested Then
_logger.LogInformation("Watcher run cancelled by user.")
Expand All@@ -146,6 +148,7 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi
SyncLock _runCancellationLock
If Object.ReferenceEquals(_runCancellationTokenSource, ownedCancellation) Then
_runCancellationTokenSource = Nothing
_runIsIdleTriggered = False
End If
End SyncLock

Expand DownExpand Up@@ -173,6 +176,20 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi
BGCompactor.CancelCompacting()
End Sub

Private Sub CancelIdleTriggeredRun()
Dim cancellation As CancellationTokenSource = Nothing

SyncLock _runCancellationLock
If _runIsIdleTriggered Then cancellation = _runCancellationTokenSource
End SyncLock

Try
cancellation?.Cancel()
Catch ex As ObjectDisposedException
'The idle-triggered run completed between retrieving and cancelling its token source.
End Try
End Sub



Private Sub OnSystemNotIdle(sender As Object, e As EventArgs)
Expand All@@ -183,6 +200,10 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi
Dim bgMode = _settingsService.AppSettings.BackgroundModeSelection
If bgMode <> BackgroundMode.IdleOnly Then Return

'If activity resumes while an idle-triggered analysis is still preparing a background
'run, cancel that pending transition. An already-running compactor is still paused below
'so the existing idle resume behaviour remains intact.
CancelIdleTriggeredRun()
BGCompactor.PauseCompacting()
End Sub

Expand DownExpand Up@@ -449,13 +470,14 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi

End Function

Public Async Function BackgroundCompact(Optional runAll As Boolean = False) As Task
Public Async Function BackgroundCompact(Optional runAll As Boolean = False, Optional startCancellationToken As CancellationToken = Nothing) As Task

Dim acquired = Await _parseWatchersSemaphore.WaitAsync(0)
If Not acquired Then Return

Try

If startCancellationToken.IsCancellationRequested Then Return
If BGCompactor.IsCompactorActive Then Return

RefreshWatchedFolderAvailability()
Expand All@@ -473,7 +495,8 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi

If foldersToCompress.Any = 0 Then Return

Await BGCompactor.StartCompactingAsync(foldersToCompress)
If startCancellationToken.IsCancellationRequested Then Return
Await BGCompactor.StartCompactingAsync(foldersToCompress, startCancellationToken)

OnPropertyChanged(NameOf(TotalSaved))
Finally
Expand DownExpand Up@@ -547,4 +570,4 @@ Partial Public Class Watcher : Inherits ObservableRecipient : Implements IRecipi



End Class
End Class
Loading