hydrus/hydrus/client/ClientDBMaintenanceManager.py

228 lines
6.9 KiB
Python
Raw Normal View History

2023-08-09 21:12:17 +00:00
import os
import threading
import time
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusThreading
from hydrus.core import HydrusTime
2024-02-14 21:20:24 +00:00
from hydrus.client import ClientGlobals as CG
from hydrus.client.interfaces import ClientControllerInterface
2023-08-09 21:12:17 +00:00
class DatabaseMaintenanceManager( object ):
2024-02-14 21:20:24 +00:00
def __init__( self, controller: ClientControllerInterface.ClientControllerInterface ):
2023-08-09 21:12:17 +00:00
self._controller = controller
self._lock = threading.Lock()
self._serious_error_encountered = False
self._wake_event = threading.Event()
self._shutdown = False
self._is_working_hard = False
self._controller.sub( self, 'Shutdown', 'shutdown' )
self._controller.sub( self, 'Wake', 'checkbox_manager_inverted' )
self._controller.sub( self, 'Wake', 'notify_deferred_delete_database_maintenance_new_work' )
def _AbleToDoBackgroundMaintenance( self ):
if self._is_working_hard:
return True
2024-02-14 21:20:24 +00:00
if CG.client_controller.CurrentlyIdle():
2023-08-09 21:12:17 +00:00
if not self._controller.new_options.GetBoolean( 'database_deferred_delete_maintenance_during_idle' ):
return False
if not self._controller.GoodTimeToStartBackgroundWork():
return False
else:
if not self._controller.new_options.GetBoolean( 'database_deferred_delete_maintenance_during_active' ):
return False
return True
2023-10-25 21:23:53 +00:00
def _GetWaitPeriod( self, work_period: float, time_it_took: float, still_work_to_do: bool ):
2023-08-09 21:12:17 +00:00
if not still_work_to_do:
return 600
if self._is_working_hard:
2024-02-14 21:20:24 +00:00
rest_ratio = CG.client_controller.new_options.GetInteger( 'deferred_table_delete_rest_percentage_work_hard' ) / 100
2023-08-09 21:12:17 +00:00
2024-02-14 21:20:24 +00:00
elif CG.client_controller.CurrentlyIdle():
2023-08-09 21:12:17 +00:00
2024-02-14 21:20:24 +00:00
rest_ratio = CG.client_controller.new_options.GetInteger( 'deferred_table_delete_rest_percentage_idle' ) / 100
2023-08-09 21:12:17 +00:00
else:
2024-02-14 21:20:24 +00:00
rest_ratio = CG.client_controller.new_options.GetInteger( 'deferred_table_delete_rest_percentage_normal' ) / 100
2023-08-09 21:12:17 +00:00
2023-10-25 21:23:53 +00:00
reasonable_work_time = min( 5 * work_period, time_it_took )
return reasonable_work_time * rest_ratio
2023-08-09 21:12:17 +00:00
def _GetWorkPeriod( self ):
if self._is_working_hard:
2024-02-14 21:20:24 +00:00
return CG.client_controller.new_options.GetInteger( 'deferred_table_delete_work_time_ms_work_hard' ) / 1000
2023-08-09 21:12:17 +00:00
2024-02-14 21:20:24 +00:00
elif CG.client_controller.CurrentlyIdle():
2023-08-09 21:12:17 +00:00
2024-02-14 21:20:24 +00:00
return CG.client_controller.new_options.GetInteger( 'deferred_table_delete_work_time_ms_idle' ) / 1000
2023-08-09 21:12:17 +00:00
else:
2024-02-14 21:20:24 +00:00
return CG.client_controller.new_options.GetInteger( 'deferred_table_delete_work_time_ms_normal' ) / 1000
2023-08-09 21:12:17 +00:00
def MainLoopBackgroundWork( self ):
def check_shutdown():
if HydrusThreading.IsThreadShuttingDown() or self._shutdown or self._serious_error_encountered:
raise HydrusExceptions.ShutdownException()
try:
time_to_start = HydrusTime.GetNow() + 15
while not HydrusTime.TimeHasPassed( time_to_start ):
check_shutdown()
time.sleep( 1 )
while True:
still_work_to_do = False
check_shutdown()
self._controller.WaitUntilViewFree()
with self._lock:
able_to_work = self._AbleToDoBackgroundMaintenance()
work_period = self._GetWorkPeriod()
2023-10-25 21:23:53 +00:00
time_it_took = 1.0
2023-08-09 21:12:17 +00:00
if able_to_work:
time_to_stop = HydrusTime.GetNowFloat() + work_period
2023-10-25 21:23:53 +00:00
start_time = HydrusTime.GetNowFloat()
2023-08-09 21:12:17 +00:00
try:
2024-02-14 21:20:24 +00:00
still_work_to_do = CG.client_controller.WriteSynchronous( 'do_deferred_table_delete_work', time_to_stop )
2023-08-09 21:12:17 +00:00
except Exception as e:
self._serious_error_encountered = True
HydrusData.PrintException( e )
message = 'There was an unexpected problem during deferred table delete database maintenance work! This maintenance system will not run again this boot. A full traceback of this error should be written to the log.'
message += os.linesep * 2
message += str( e )
HydrusData.ShowText( message )
finally:
self._controller.pub( 'notify_deferred_delete_database_maintenance_work_complete' )
2023-10-25 21:23:53 +00:00
time_it_took = HydrusTime.GetNowFloat() - start_time
2023-08-09 21:12:17 +00:00
with self._lock:
2023-10-25 21:23:53 +00:00
wait_period = self._GetWaitPeriod( work_period, time_it_took, still_work_to_do )
2023-08-09 21:12:17 +00:00
self._wake_event.wait( wait_period )
self._wake_event.clear()
except HydrusExceptions.ShutdownException:
pass
def FlipWorkingHard( self ):
with self._lock:
self._is_working_hard = not self._is_working_hard
self._controller.pub( 'notify_deferred_delete_database_maintenance_state_change' )
self.Wake()
def IsWorkingHard( self ) -> bool:
with self._lock:
return self._is_working_hard
def Shutdown( self ):
with self._lock:
self._shutdown = True
self.Wake()
def Start( self ):
self._controller.CallToThreadLongRunning( self.MainLoopBackgroundWork )
def Wake( self ):
self._wake_event.set()