hydrus/hydrus/core/HydrusController.py

855 lines
22 KiB
Python
Raw Normal View History

2015-04-01 20:44:54 +00:00
import collections
import gc
2020-05-20 21:36:02 +00:00
import os
import random
import sys
import threading
import time
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusNATPunch
from hydrus.core import HydrusPaths
from hydrus.core import HydrusPubSub
from hydrus.core import HydrusThreading
2015-04-01 20:44:54 +00:00
2015-09-02 23:16:09 +00:00
class HydrusController( object ):
2015-04-01 20:44:54 +00:00
2019-03-20 21:22:10 +00:00
def __init__( self, db_dir ):
2015-09-02 23:16:09 +00:00
2017-05-10 21:33:58 +00:00
HG.controller = self
2015-09-02 23:16:09 +00:00
2017-03-08 23:23:12 +00:00
self._name = 'hydrus'
self._last_shutdown_was_bad = False
self._i_own_running_file = False
2017-07-12 20:03:45 +00:00
self.db_dir = db_dir
2016-03-09 19:37:14 +00:00
2017-07-12 20:03:45 +00:00
self.db = None
2016-10-19 20:02:56 +00:00
2019-11-14 03:56:30 +00:00
pubsub_valid_callable = self._GetPubsubValidCallable()
self._pubsub = HydrusPubSub.HydrusPubSub( self, pubsub_valid_callable )
2015-09-02 23:16:09 +00:00
self._daemons = []
2019-02-13 22:26:43 +00:00
self._daemon_jobs = {}
2015-09-02 23:16:09 +00:00
self._caches = {}
self._managers = {}
2018-05-23 21:05:06 +00:00
self._fast_job_scheduler = None
self._slow_job_scheduler = None
2018-02-14 21:47:18 +00:00
2019-01-16 22:40:53 +00:00
self._thread_slots = {}
self._thread_slots[ 'misc' ] = ( 0, 10 )
self._thread_slot_lock = threading.Lock()
2016-07-20 19:57:10 +00:00
self._call_to_threads = []
2017-08-09 21:33:51 +00:00
self._long_running_call_to_threads = []
2015-09-02 23:16:09 +00:00
2018-09-19 21:54:51 +00:00
self._thread_pool_busy_status_text = ''
self._thread_pool_busy_status_text_new_check_time = 0
2018-02-14 21:47:18 +00:00
self._call_to_thread_lock = threading.Lock()
2015-09-02 23:16:09 +00:00
self._timestamps = collections.defaultdict( lambda: 0 )
self._timestamps[ 'boot' ] = HydrusData.GetNow()
2018-07-04 20:48:28 +00:00
self._timestamps[ 'last_sleep_check' ] = HydrusData.GetNow()
self._sleep_lock = threading.Lock()
2015-09-02 23:16:09 +00:00
self._just_woke_from_sleep = False
2018-07-04 20:48:28 +00:00
2015-09-02 23:16:09 +00:00
self._system_busy = False
self._doing_fast_exit = False
2015-09-02 23:16:09 +00:00
2016-07-20 19:57:10 +00:00
def _GetCallToThread( self ):
2018-02-14 21:47:18 +00:00
with self._call_to_thread_lock:
2016-07-20 19:57:10 +00:00
2018-02-14 21:47:18 +00:00
for call_to_thread in self._call_to_threads:
2016-07-20 19:57:10 +00:00
2018-02-14 21:47:18 +00:00
if not call_to_thread.CurrentlyWorking():
return call_to_thread
2016-07-20 19:57:10 +00:00
2018-02-14 21:47:18 +00:00
# all the threads in the pool are currently busy
2017-02-08 22:27:00 +00:00
2018-02-14 21:47:18 +00:00
calling_from_the_thread_pool = threading.current_thread() in self._call_to_threads
2017-02-08 22:27:00 +00:00
2018-05-16 20:09:50 +00:00
if calling_from_the_thread_pool or len( self._call_to_threads ) < 200:
2018-02-14 21:47:18 +00:00
call_to_thread = HydrusThreading.THREADCallToThread( self, 'CallToThread' )
self._call_to_threads.append( call_to_thread )
call_to_thread.start()
else:
call_to_thread = random.choice( self._call_to_threads )
2017-02-08 22:27:00 +00:00
2018-02-14 21:47:18 +00:00
return call_to_thread
2016-07-20 19:57:10 +00:00
2017-08-09 21:33:51 +00:00
def _GetCallToThreadLongRunning( self ):
2018-02-14 21:47:18 +00:00
with self._call_to_thread_lock:
2017-08-09 21:33:51 +00:00
2018-02-14 21:47:18 +00:00
for call_to_thread in self._long_running_call_to_threads:
2017-08-09 21:33:51 +00:00
2018-02-14 21:47:18 +00:00
if not call_to_thread.CurrentlyWorking():
return call_to_thread
2017-08-09 21:33:51 +00:00
2018-02-14 21:47:18 +00:00
call_to_thread = HydrusThreading.THREADCallToThread( self, 'CallToThreadLongRunning' )
self._long_running_call_to_threads.append( call_to_thread )
call_to_thread.start()
return call_to_thread
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
def _GetPubsubValidCallable( self ):
return lambda o: True
2018-05-23 21:05:06 +00:00
def _GetAppropriateJobScheduler( self, time_delta ):
2018-05-30 20:13:21 +00:00
if time_delta <= 1.0:
2018-05-23 21:05:06 +00:00
return self._fast_job_scheduler
else:
return self._slow_job_scheduler
2019-02-13 22:26:43 +00:00
def _GetUPnPServices( self ):
return []
2015-09-02 23:16:09 +00:00
def _InitDB( self ):
raise NotImplementedError()
2018-06-06 21:27:02 +00:00
def _InitTempDir( self ):
self.temp_dir = HydrusPaths.GetTempDir()
2018-02-14 21:47:18 +00:00
def _MaintainCallToThreads( self ):
# we don't really want to hang on to threads that are done as event.wait() has a bit of idle cpu
# so, any that are in the pools that aren't doing anything can be killed and sent to garbage
with self._call_to_thread_lock:
def filter_call_to_threads( t ):
if t.CurrentlyWorking():
return True
else:
t.shutdown()
return False
2019-01-09 22:59:03 +00:00
self._call_to_threads = list(filter( filter_call_to_threads, self._call_to_threads ))
2018-02-14 21:47:18 +00:00
2019-01-09 22:59:03 +00:00
self._long_running_call_to_threads = list(filter( filter_call_to_threads, self._long_running_call_to_threads ))
2018-02-14 21:47:18 +00:00
def _PublishShutdownSubtext( self, text ):
pass
2015-04-01 20:44:54 +00:00
def _Read( self, action, *args, **kwargs ):
2019-01-09 22:59:03 +00:00
result = self.db.Read( action, *args, **kwargs )
2015-04-01 20:44:54 +00:00
return result
2017-11-08 22:07:12 +00:00
def _ReportShutdownDaemonsStatus( self ):
pass
2015-09-16 18:11:00 +00:00
def _ShutdownDaemons( self ):
2019-02-13 22:26:43 +00:00
for job in self._daemon_jobs.values():
job.Cancel()
self._daemon_jobs = {}
2015-09-16 18:11:00 +00:00
for daemon in self._daemons:
daemon.shutdown()
2019-10-16 20:47:55 +00:00
started = HydrusData.GetNow()
2015-09-16 18:11:00 +00:00
while True in ( daemon.is_alive() for daemon in self._daemons ):
2017-11-08 22:07:12 +00:00
self._ReportShutdownDaemonsStatus()
2015-09-16 18:11:00 +00:00
time.sleep( 0.1 )
2019-10-16 20:47:55 +00:00
if HydrusData.TimeHasPassed( started + 30 ):
break
2015-09-16 18:11:00 +00:00
self._daemons = []
2019-01-09 22:59:03 +00:00
def _Write( self, action, synchronous, *args, **kwargs ):
2015-04-01 20:44:54 +00:00
2019-01-09 22:59:03 +00:00
result = self.db.Write( action, synchronous, *args, **kwargs )
2015-04-01 20:44:54 +00:00
return result
2015-08-26 21:18:39 +00:00
def pub( self, topic, *args, **kwargs ):
2015-04-01 20:44:54 +00:00
2019-07-31 22:01:02 +00:00
if HG.model_shutdown:
2017-08-09 21:33:51 +00:00
self._pubsub.pubimmediate( topic, *args, **kwargs )
else:
self._pubsub.pub( topic, *args, **kwargs )
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
def pubimmediate( self, topic, *args, **kwargs ):
self._pubsub.pubimmediate( topic, *args, **kwargs )
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
def sub( self, object, method_name, topic ):
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
self._pubsub.sub( object, method_name, topic )
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
2019-01-16 22:40:53 +00:00
def AcquireThreadSlot( self, thread_type ):
with self._thread_slot_lock:
if thread_type not in self._thread_slots:
return True # assume no max if no max set
( current_threads, max_threads ) = self._thread_slots[ thread_type ]
if current_threads < max_threads:
self._thread_slots[ thread_type ] = ( current_threads + 1, max_threads )
return True
else:
return False
2018-05-16 20:09:50 +00:00
def CallLater( self, initial_delay, func, *args, **kwargs ):
2018-02-14 21:47:18 +00:00
2018-05-23 21:05:06 +00:00
job_scheduler = self._GetAppropriateJobScheduler( initial_delay )
2018-02-14 21:47:18 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2020-02-26 22:28:52 +00:00
job = HydrusThreading.SingleJob( self, job_scheduler, initial_delay, call )
2018-02-14 21:47:18 +00:00
2018-05-23 21:05:06 +00:00
job_scheduler.AddJob( job )
2018-02-14 21:47:18 +00:00
return job
2018-05-16 20:09:50 +00:00
def CallRepeating( self, initial_delay, period, func, *args, **kwargs ):
2018-02-21 21:59:37 +00:00
2018-05-23 21:05:06 +00:00
job_scheduler = self._GetAppropriateJobScheduler( period )
2018-02-21 21:59:37 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2018-05-23 21:05:06 +00:00
job = HydrusThreading.RepeatingJob( self, job_scheduler, initial_delay, period, call )
2018-02-21 21:59:37 +00:00
2018-05-23 21:05:06 +00:00
job_scheduler.AddJob( job )
2018-02-21 21:59:37 +00:00
return job
2015-08-26 21:18:39 +00:00
def CallToThread( self, callable, *args, **kwargs ):
2017-06-21 21:15:59 +00:00
if HG.callto_report_mode:
what_to_report = [ callable ]
if len( args ) > 0:
what_to_report.append( args )
if len( kwargs ) > 0:
what_to_report.append( kwargs )
HydrusData.ShowText( tuple( what_to_report ) )
2016-07-20 19:57:10 +00:00
call_to_thread = self._GetCallToThread()
2015-08-26 21:18:39 +00:00
call_to_thread.put( callable, *args, **kwargs )
2017-08-09 21:33:51 +00:00
def CallToThreadLongRunning( self, callable, *args, **kwargs ):
if HG.callto_report_mode:
what_to_report = [ callable ]
if len( args ) > 0:
what_to_report.append( args )
if len( kwargs ) > 0:
what_to_report.append( kwargs )
HydrusData.ShowText( tuple( what_to_report ) )
call_to_thread = self._GetCallToThreadLongRunning()
call_to_thread.put( callable, *args, **kwargs )
def CleanRunningFile( self ):
if self._i_own_running_file:
HydrusData.CleanRunningFile( self.db_dir, self._name )
2015-08-26 21:18:39 +00:00
def ClearCaches( self ):
2019-01-09 22:59:03 +00:00
for cache in list(self._caches.values()): cache.Clear()
2015-08-26 21:18:39 +00:00
2017-04-05 21:16:40 +00:00
def CurrentlyIdle( self ):
return True
2015-04-01 20:44:54 +00:00
2019-04-10 22:50:53 +00:00
def CurrentlyPubSubbing( self ):
return self._pubsub.WorkToDo() or self._pubsub.DoingWork()
2016-08-31 19:55:14 +00:00
def DBCurrentlyDoingJob( self ):
2017-07-12 20:03:45 +00:00
if self.db is None:
2016-08-31 19:55:14 +00:00
return False
else:
2017-07-12 20:03:45 +00:00
return self.db.CurrentlyDoingJob()
2016-08-31 19:55:14 +00:00
2018-02-21 21:59:37 +00:00
def DebugShowScheduledJobs( self ):
2018-05-23 21:05:06 +00:00
summary = self._fast_job_scheduler.GetPrettyJobSummary()
HydrusData.ShowText( 'fast scheduler:' )
HydrusData.ShowText( summary )
summary = self._slow_job_scheduler.GetPrettyJobSummary()
2018-02-21 21:59:37 +00:00
2018-05-23 21:05:06 +00:00
HydrusData.ShowText( 'slow scheduler:' )
2018-02-21 21:59:37 +00:00
HydrusData.ShowText( summary )
def DoingFastExit( self ) -> bool:
return self._doing_fast_exit
2017-08-16 21:58:06 +00:00
def GetBootTime( self ):
return self._timestamps[ 'boot' ]
2017-05-24 20:28:24 +00:00
def GetDBDir( self ):
2016-10-19 20:02:56 +00:00
2017-07-12 20:03:45 +00:00
return self.db_dir
2016-10-19 20:02:56 +00:00
2017-05-24 20:28:24 +00:00
def GetDBStatus( self ):
2016-10-19 20:02:56 +00:00
2017-07-12 20:03:45 +00:00
return self.db.GetStatus()
2017-05-24 20:28:24 +00:00
def GetCache( self, name ):
return self._caches[ name ]
2016-10-19 20:02:56 +00:00
2015-04-01 20:44:54 +00:00
2016-10-19 20:02:56 +00:00
def GetManager( self, name ):
return self._managers[ name ]
2015-04-01 20:44:54 +00:00
2018-09-19 21:54:51 +00:00
def GetThreadPoolBusyStatus( self ):
if HydrusData.TimeHasPassed( self._thread_pool_busy_status_text_new_check_time ):
with self._call_to_thread_lock:
num_threads = sum( ( 1 for t in self._call_to_threads if t.CurrentlyWorking() ) )
if num_threads < 4:
self._thread_pool_busy_status_text = ''
elif num_threads < 10:
self._thread_pool_busy_status_text = 'working'
elif num_threads < 20:
self._thread_pool_busy_status_text = 'busy'
else:
self._thread_pool_busy_status_text = 'very busy!'
self._thread_pool_busy_status_text_new_check_time = HydrusData.GetNow() + 10
return self._thread_pool_busy_status_text
2018-09-12 21:36:26 +00:00
def GetThreadsSnapshot( self ):
threads = []
threads.extend( self._daemons )
threads.extend( self._call_to_threads )
threads.extend( self._long_running_call_to_threads )
threads.append( self._slow_job_scheduler )
threads.append( self._fast_job_scheduler )
return threads
2019-06-19 22:08:48 +00:00
def GoodTimeToStartBackgroundWork( self ):
2015-08-26 21:18:39 +00:00
2016-12-14 21:19:07 +00:00
return self.CurrentlyIdle() and not ( self.JustWokeFromSleep() or self.SystemBusy() )
2019-06-19 22:08:48 +00:00
def GoodTimeToStartForegroundWork( self ):
2016-12-14 21:19:07 +00:00
2018-07-04 20:48:28 +00:00
return not self.JustWokeFromSleep()
2015-08-26 21:18:39 +00:00
2015-04-01 20:44:54 +00:00
def JustWokeFromSleep( self ):
2015-08-26 21:18:39 +00:00
self.SleepCheck()
2015-04-01 20:44:54 +00:00
return self._just_woke_from_sleep
2015-09-02 23:16:09 +00:00
def InitModel( self ):
2015-08-26 21:18:39 +00:00
2018-06-06 21:27:02 +00:00
try:
self._InitTempDir()
except:
HydrusData.Print( 'Failed to initialise temp folder.' )
2018-05-23 21:05:06 +00:00
self._fast_job_scheduler = HydrusThreading.JobScheduler( self )
self._slow_job_scheduler = HydrusThreading.JobScheduler( self )
2018-02-14 21:47:18 +00:00
2018-05-23 21:05:06 +00:00
self._fast_job_scheduler.start()
self._slow_job_scheduler.start()
2018-02-14 21:47:18 +00:00
2017-07-12 20:03:45 +00:00
self.db = self._InitDB()
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
2015-09-02 23:16:09 +00:00
def InitView( self ):
2015-04-01 20:44:54 +00:00
2019-06-19 22:08:48 +00:00
job = self.CallRepeating( 60.0, 300.0, self.MaintainDB, maintenance_mode = HC.MAINTENANCE_IDLE )
2019-02-13 22:26:43 +00:00
2019-05-22 22:35:06 +00:00
job.WakeOnPubSub( 'wake_idle_workers' )
2019-02-13 22:26:43 +00:00
job.ShouldDelayOnWakeup( True )
self._daemon_jobs[ 'maintain_db' ] = job
job = self.CallRepeating( 10.0, 120.0, self.SleepCheck )
self._daemon_jobs[ 'sleep_check' ] = job
job = self.CallRepeating( 10.0, 60.0, self.MaintainMemoryFast )
2015-04-01 20:44:54 +00:00
2019-02-13 22:26:43 +00:00
self._daemon_jobs[ 'maintain_memory_fast' ] = job
job = self.CallRepeating( 10.0, 300.0, self.MaintainMemorySlow )
self._daemon_jobs[ 'maintain_memory_slow' ] = job
upnp_services = self._GetUPnPServices()
self.services_upnp_manager = HydrusNATPunch.ServicesUPnPManager( upnp_services )
job = self.CallRepeating( 10.0, 43200.0, self.services_upnp_manager.RefreshUPnP )
self._daemon_jobs[ 'services_upnp' ] = job
2018-02-21 21:59:37 +00:00
2015-04-01 20:44:54 +00:00
2016-08-31 19:55:14 +00:00
def IsFirstStart( self ):
2017-07-12 20:03:45 +00:00
if self.db is None:
2016-08-31 19:55:14 +00:00
return False
else:
2017-07-12 20:03:45 +00:00
return self.db.IsFirstStart()
2016-08-31 19:55:14 +00:00
def LastShutdownWasBad( self ):
return self._last_shutdown_was_bad
2019-06-19 22:08:48 +00:00
def MaintainDB( self, maintenance_mode = HC.MAINTENANCE_IDLE, stop_time = None ):
2015-04-01 20:44:54 +00:00
2015-09-02 23:16:09 +00:00
pass
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
2018-02-21 21:59:37 +00:00
def MaintainMemoryFast( self ):
2019-06-19 22:08:48 +00:00
sys.stdout.flush()
sys.stderr.flush()
2018-02-21 21:59:37 +00:00
self.pub( 'memory_maintenance_pulse' )
2018-05-23 21:05:06 +00:00
self._fast_job_scheduler.ClearOutDead()
self._slow_job_scheduler.ClearOutDead()
2018-02-28 22:30:36 +00:00
2018-02-21 21:59:37 +00:00
2017-07-05 21:09:28 +00:00
def MaintainMemorySlow( self ):
2015-08-26 21:18:39 +00:00
gc.collect()
2018-01-24 23:09:42 +00:00
HydrusPaths.CleanUpOldTempPaths()
2018-02-14 21:47:18 +00:00
self._MaintainCallToThreads()
2015-08-26 21:18:39 +00:00
2017-03-08 23:23:12 +00:00
def PrintProfile( self, summary, profile_text ):
2018-02-07 23:40:33 +00:00
boot_pretty_timestamp = time.strftime( '%Y-%m-%d %H-%M-%S', time.localtime( self._timestamps[ 'boot' ] ) )
2017-03-08 23:23:12 +00:00
profile_log_filename = self._name + ' profile - ' + boot_pretty_timestamp + '.log'
2017-07-12 20:03:45 +00:00
profile_log_path = os.path.join( self.db_dir, profile_log_filename )
2017-03-08 23:23:12 +00:00
2019-01-23 22:19:16 +00:00
with open( profile_log_path, 'a', encoding = 'utf-8' ) as f:
2017-03-08 23:23:12 +00:00
2018-01-31 22:58:15 +00:00
prefix = time.strftime( '%Y/%m/%d %H:%M:%S: ' )
2017-03-08 23:23:12 +00:00
f.write( prefix + summary )
f.write( os.linesep * 2 )
f.write( profile_text )
2017-03-02 02:14:56 +00:00
def Read( self, action, *args, **kwargs ):
return self._Read( action, *args, **kwargs )
def RecordRunningStart( self ):
self._last_shutdown_was_bad = HydrusData.LastShutdownWasBad( self.db_dir, self._name )
self._i_own_running_file = True
HydrusData.RecordRunningStart( self.db_dir, self._name )
2019-01-16 22:40:53 +00:00
def ReleaseThreadSlot( self, thread_type ):
with self._thread_slot_lock:
if thread_type not in self._thread_slots:
return
( current_threads, max_threads ) = self._thread_slots[ thread_type ]
self._thread_slots[ thread_type ] = ( current_threads - 1, max_threads )
2017-06-21 21:15:59 +00:00
def ReportDataUsed( self, num_bytes ):
pass
def ReportRequestUsed( self ):
2017-03-02 02:14:56 +00:00
pass
2015-04-01 20:44:54 +00:00
2018-07-04 20:48:28 +00:00
def ResetIdleTimer( self ):
self._timestamps[ 'last_user_action' ] = HydrusData.GetNow()
def SetDoingFastExit( self, value: bool ):
self._doing_fast_exit = value
2019-06-19 22:08:48 +00:00
def ShouldStopThisWork( self, maintenance_mode, stop_time = None ):
if maintenance_mode == HC.MAINTENANCE_IDLE:
if not self.CurrentlyIdle():
return True
elif maintenance_mode == HC.MAINTENANCE_SHUTDOWN:
if not HG.do_idle_shutdown_work:
return True
if stop_time is not None:
if HydrusData.TimeHasPassed( stop_time ):
return True
return False
2015-09-02 23:16:09 +00:00
def ShutdownModel( self ):
2015-08-05 18:42:35 +00:00
2017-07-12 20:03:45 +00:00
if self.db is not None:
2016-01-13 22:08:19 +00:00
2019-01-23 22:19:16 +00:00
self.db.Shutdown()
2017-07-27 00:47:13 +00:00
while not self.db.LoopIsFinished():
self._PublishShutdownSubtext( 'waiting for db to finish up\u2026' )
2017-07-27 00:47:13 +00:00
time.sleep( 0.1 )
2016-01-13 22:08:19 +00:00
2015-04-01 20:44:54 +00:00
2018-05-23 21:05:06 +00:00
if self._fast_job_scheduler is not None:
self._fast_job_scheduler.shutdown()
self._fast_job_scheduler = None
if self._slow_job_scheduler is not None:
2018-02-14 21:47:18 +00:00
2018-05-23 21:05:06 +00:00
self._slow_job_scheduler.shutdown()
2018-02-14 21:47:18 +00:00
2018-05-23 21:05:06 +00:00
self._slow_job_scheduler = None
2018-02-14 21:47:18 +00:00
2018-06-06 21:27:02 +00:00
if hasattr( self, 'temp_dir' ):
HydrusPaths.DeletePath( self.temp_dir )
2020-01-02 03:05:35 +00:00
with self._call_to_thread_lock:
for call_to_thread in self._call_to_threads:
call_to_thread.shutdown()
for long_running_call_to_thread in self._long_running_call_to_threads:
long_running_call_to_thread.shutdown()
2019-01-23 22:19:16 +00:00
HG.model_shutdown = True
2020-01-02 03:05:35 +00:00
self._pubsub.Wake()
2015-04-01 20:44:54 +00:00
2015-09-02 23:16:09 +00:00
def ShutdownView( self ):
2017-05-10 21:33:58 +00:00
HG.view_shutdown = True
2015-09-02 23:16:09 +00:00
2015-09-16 18:11:00 +00:00
self._ShutdownDaemons()
2015-09-02 23:16:09 +00:00
2015-09-16 18:11:00 +00:00
def ShutdownFromServer( self ):
raise Exception( 'This hydrus application cannot be shut down from the server!' )
2015-09-02 23:16:09 +00:00
2015-08-26 21:18:39 +00:00
def SleepCheck( self ):
2015-04-01 20:44:54 +00:00
2018-07-04 20:48:28 +00:00
with self._sleep_lock:
2015-08-26 21:18:39 +00:00
2018-07-04 20:48:28 +00:00
if HydrusData.TimeHasPassed( self._timestamps[ 'now_awake' ] ):
2015-08-26 21:18:39 +00:00
2018-07-04 20:48:28 +00:00
last_sleep_check = self._timestamps[ 'last_sleep_check' ]
2015-08-26 21:18:39 +00:00
2018-07-04 20:48:28 +00:00
if HydrusData.TimeHasPassed( last_sleep_check + 600 ): # it has been way too long since this method last fired, so we've prob been asleep
2015-08-26 21:18:39 +00:00
self._just_woke_from_sleep = True
2018-07-04 20:48:28 +00:00
self.ResetIdleTimer() # this will stop the background jobs from kicking in as soon as the grace period is over
self._timestamps[ 'now_awake' ] = HydrusData.GetNow() + 15 # enough time for ethernet to get back online and all that
2015-08-26 21:18:39 +00:00
else:
self._just_woke_from_sleep = False
2018-07-04 20:48:28 +00:00
self._timestamps[ 'last_sleep_check' ] = HydrusData.GetNow()
2015-04-01 20:44:54 +00:00
2018-07-04 20:48:28 +00:00
def SimulateWakeFromSleepEvent( self ):
with self._sleep_lock:
self._timestamps[ 'last_sleep_check' ] = HydrusData.GetNow() - 3600
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
def SystemBusy( self ):
2015-04-01 20:44:54 +00:00
2015-08-26 21:18:39 +00:00
return self._system_busy
2015-04-01 20:44:54 +00:00
2017-10-04 17:51:58 +00:00
def WaitUntilDBEmpty( self ):
while True:
2019-07-31 22:01:02 +00:00
if HG.model_shutdown:
2017-10-04 17:51:58 +00:00
raise HydrusExceptions.ShutdownException( 'Application shutting down!' )
elif self.db.JobsQueueEmpty() and not self.db.CurrentlyDoingJob():
return
else:
time.sleep( 0.00001 )
def WaitUntilModelFree( self ):
self.WaitUntilPubSubsEmpty()
self.WaitUntilDBEmpty()
2015-08-26 21:18:39 +00:00
def WaitUntilPubSubsEmpty( self ):
2015-04-01 20:44:54 +00:00
while True:
2019-07-31 22:01:02 +00:00
if HG.model_shutdown:
2015-12-30 23:44:09 +00:00
raise HydrusExceptions.ShutdownException( 'Application shutting down!' )
2019-04-10 22:50:53 +00:00
elif not self.CurrentlyPubSubbing():
2015-12-30 23:44:09 +00:00
return
else:
time.sleep( 0.00001 )
2015-04-01 20:44:54 +00:00
2019-02-13 22:26:43 +00:00
def WakeDaemon( self, name ):
if name in self._daemon_jobs:
self._daemon_jobs[ name ].Wake()
2015-04-01 20:44:54 +00:00
def Write( self, action, *args, **kwargs ):
2019-01-09 22:59:03 +00:00
return self._Write( action, False, *args, **kwargs )
2016-04-20 20:42:21 +00:00
2015-04-01 20:44:54 +00:00
def WriteSynchronous( self, action, *args, **kwargs ):
2019-01-09 22:59:03 +00:00
return self._Write( action, True, *args, **kwargs )
2015-04-01 20:44:54 +00:00
2016-12-14 21:19:07 +00:00