Files
mongo/buildscripts/resmokelib/utils/timer.py
Max Hirschhorn 424314f65e SERVER-1424 Rewrite smoke.py.
Split out the passthrough tests into separate suites. The MongoDB
deployment is started up by resmoke.py so that we can record the
success/failure of each individual test in MCI.

Added support for parallel execution of tests by dispatching to
multiple MongoDB deployments.

Added support for grouping different kinds of tests (e.g. C++ unit
tests, dbtests, and jstests) so that they can be run together. This
allows for customizability in specifying what tests to execute when
changes are made to a particular part of the code.
2015-05-08 14:49:42 -04:00

120 lines
3.5 KiB
Python

"""
Alternative to the threading.Timer class.
Enables a timer to be restarted without needing to construct a new thread
each time. This is necessary to execute periodic actions, e.g. flushing
log messages to buildlogger, while avoiding errors related to "can't start
new thread" that would otherwise occur on Windows.
"""
from __future__ import absolute_import
import threading
class AlarmClock(threading.Thread):
"""
Calls a function after a specified number of seconds.
"""
def __init__(self, interval, func, args=None, kwargs=None):
"""
Initializes the timer with a function to periodically execute.
"""
threading.Thread.__init__(self)
# A non-dismissed timer should not prevent the program from exiting
self.daemon = True
self.interval = interval
self.func = func
self.args = args if args is not None else []
self.kwargs = kwargs if kwargs is not None else {}
self.lock = threading.Lock()
self.cond = threading.Condition(self.lock)
self.snoozed = False # canceled for one execution
self.dismissed = False # canceled for all time
self.restarted = False
def dismiss(self):
"""
Disables the timer.
"""
with self.lock:
self.dismissed = True
self.cond.notify_all()
self.join() # Tidy up the started thread.
cancel = dismiss # Expose API compatible with that of threading.Timer.
def snooze(self):
"""
Skips the next execution of 'func' if it has not already started.
"""
with self.lock:
if self.dismissed:
raise ValueError("Timer cannot be snoozed if it has been dismissed")
self.snoozed = True
self.restarted = False
self.cond.notify_all()
def reset(self):
"""
Restarts the timer, causing it to wait 'interval' seconds before calling
'func' again.
"""
with self.lock:
if self.dismissed:
raise ValueError("Timer cannot be reset if it has been dismissed")
if not self.snoozed:
raise ValueError("Timer cannot be reset if it has not been snoozed")
self.restarted = True
self.cond.notify_all()
def run(self):
"""
Repeatedly calls 'func' with a delay of 'interval' seconds between executions.
If the timer is snoozed before 'func' is called, then it waits to be reset.
After is has been reset, the timer will again wait 'interval' seconds and
then try to call 'func'.
If the timer is dismissed, then no subsequent executions of 'func' are made.
"""
with self.lock:
while not self.dismissed:
# Wait for the specified amount of time.
self.cond.wait(self.interval)
if self.dismissed:
return
# If the timer was snoozed, then it should wait to be reset.
if self.snoozed:
while not self.restarted:
self.cond.wait()
if self.dismissed:
return
self.restarted = False
self.snoozed = False
continue
# Execute the function.
self.func(*self.args, **self.kwargs)
# Ignore snoozes that took place while the function was being executed.
self.snoozed = False