예제 #1
0
    def _sweeper_loop(self):
        """Regularly check the database for unscored results.

        Try to sweep the database once every SWEEPER_TIMEOUT seconds
        but make sure that no two sweeps run simultaneously. That is,
        start a new sweep SWEEPER_TIMEOUT seconds after the previous
        one started or when the previous one finished, whatever comes
        last.

        The search_jobs_not_done RPC method can interfere with this
        regularity, as it tries to run a sweeper as soon as possible:
        immediately, if no sweeper is running, or as soon as the
        current one terminates.

        Any error during the sweep is sent to the logger and then
        suppressed, because the loop must go on.

        """
        while True:
            self._sweeper_start = monotonic_time()
            self._sweeper_event.clear()

            try:
                self._sweep()
            except Exception:
                logger.error("Unexpected error when searching for unscored "
                             "submissions.", exc_info=True)

            self._sweeper_event.wait(max(self._sweeper_start +
                                         self.SWEEPER_TIMEOUT -
                                         monotonic_time(), 0))
예제 #2
0
    def _sweeper_loop(self):
        """Regularly check for missed operations.

        Run the sweep once every _sweeper_timeout seconds but make
        sure that no two sweeps run simultaneously. That is, start a
        new sweep _sweeper_timeout seconds after the previous one
        started or when the previous one finished, whatever comes
        last.

        The search_operations_not_done RPC method can interfere with
        this regularity, as it tries to run a sweeper as soon as
        possible: immediately, if no sweeper is running, or as soon as
        the current one terminates.

        Any error during the sweep is sent to the logger and then
        suppressed, because the loop must go on.

        """
        while True:
            self._sweeper_start = monotonic_time()
            self._sweeper_event.clear()

            try:
                self._sweep()
            except Exception:
                logger.error(
                    "Unexpected error when searching for missed "
                    "operations.",
                    exc_info=True)

            self._sweeper_event.wait(
                max(
                    self._sweeper_start + self._sweeper_timeout -
                    monotonic_time(), 0))
예제 #3
0
    def _sweeper_loop(self):
        """Regularly check for missed operations.

        Run the sweep once every _sweeper_timeout() seconds but make
        sure that no two sweeps run simultaneously. That is, start a
        new sweep _sweeper_timeout() seconds after the previous one
        started or when the previous one finished, whatever comes
        last.

        The search_operations_not_done RPC method can interfere with
        this regularity, as it tries to run a sweeper as soon as
        possible: immediately, if no sweeper is running, or as soon as
        the current one terminates.

        Any error during the sweep is sent to the logger and then
        suppressed, because the loop must go on.

        """
        # If the timeout is None, it means the subclass does not want
        # a sweeper.
        if self._sweeper_timeout() is None:
            return
        while True:
            self._sweeper_start = monotonic_time()
            self._sweeper_event.clear()

            try:
                self._sweep()
            except Exception:
                logger.error("Unexpected error when searching for missed "
                             "operations.", exc_info=True)

            self._sweeper_event.wait(max(self._sweeper_start +
                                         self._sweeper_timeout() -
                                         monotonic_time(), 0))
예제 #4
0
 def wait_or_kill(self):
     """Wait for the program to terminate, or kill it after 5s."""
     if self.instance.poll() is None:
         # We try one more time to kill gracefully using Ctrl-C.
         logger.info("Interrupting %s and waiting...", self.coord)
         self.instance.send_signal(signal.SIGINT)
         # FIXME on py3 this becomes self.instance.wait(timeout=5)
         t = monotonic_time()
         while monotonic_time() - t < 5:
             if self.instance.poll() is not None:
                 logger.info("Terminated %s.", self.coord)
                 break
             time.sleep(0.1)
         else:
             self.kill()
예제 #5
0
파일: programstarter.py 프로젝트: Nyrio/cms
 def wait_or_kill(self):
     """Wait for the program to terminate, or kill it after 5s."""
     if self.instance.poll() is None:
         # We try one more time to kill gracefully using Ctrl-C.
         logger.info("Interrupting %s and waiting...", self.coord)
         self.instance.send_signal(signal.SIGINT)
         # FIXME on py3 this becomes self.instance.wait(timeout=5)
         t = monotonic_time()
         while monotonic_time() - t < 5:
             if self.instance.poll() is not None:
                 logger.info("Terminated %s.", self.coord)
                 break
             time.sleep(0.1)
         else:
             self.kill()
예제 #6
0
파일: flushingdict.py 프로젝트: Nyrio/cms
    def __init__(self, size, flush_latency_seconds, callback):
        # Elements contained in the dict that force a flush.
        self.size = size

        # How much time we wait for other key-values before flushing.
        self.flush_latency_seconds = flush_latency_seconds

        # Function to flush the data to.
        self.callback = callback

        # This contains all the key-values received and not yet
        # flushed.
        self.d = dict()

        # This contains all the key-values that are currently being flushed
        self.fd = dict()

        # The greenlet that checks if the dict should be flushed or not
        # TODO: do something if the FlushingDict is deleted
        self.flush_greenlet = gevent.spawn(self._check_flush)

        # This lock ensures that if a key-value arrives while flush is
        # executing, it is not inserted in the dict until flush
        # terminates.
        self.d_lock = RLock()

        # Time when an item was last inserted in the dict
        self.last_insert = monotonic_time()
예제 #7
0
    def __init__(self, size, flush_latency_seconds, callback):
        # Elements contained in the dict that force a flush.
        self.size = size

        # How much time we wait for other key-values before flushing.
        self.flush_latency_seconds = flush_latency_seconds

        # Function to flush the data to.
        self.callback = callback

        # This contains all the key-values received and not yet
        # flushed.
        self.d = dict()

        # This contains all the key-values that are currently being flushed
        self.fd = dict()

        # The greenlet that checks if the dict should be flushed or not
        # TODO: do something if the FlushingDict is deleted
        self.flush_greenlet = gevent.spawn(self._check_flush)

        # This lock ensures that if a key-value arrives while flush is
        # executing, it is not inserted in the dict until flush
        # terminates.
        self.d_lock = RLock()

        # Time when an item was last inserted in the dict
        self.last_insert = monotonic_time()
예제 #8
0
파일: flushingdict.py 프로젝트: Nyrio/cms
 def _check_flush(self):
     while True:
         while True:
             with self.d_lock:
                 since_last_insert = monotonic_time() - self.last_insert
                 if len(self.d) != 0 and (
                         len(self.d) >= self.size or
                         since_last_insert > self.flush_latency_seconds):
                     break
             gevent.sleep(0.05)
         self.flush()
예제 #9
0
 def _check_flush(self):
     while True:
         while True:
             with self.d_lock:
                 since_last_insert = monotonic_time() - self.last_insert
                 if len(self.d) != 0 and (
                         len(self.d) >= self.size
                         or since_last_insert > self.flush_latency_seconds):
                     break
             gevent.sleep(0.05)
         self.flush()
예제 #10
0
파일: service.py 프로젝트: Karl-Krauth/cms
def repeater(func, period):
    """Repeatedly call the given function.

    Continuosly calls the given function, over and over. For a call to
    be issued the previous one needs to have returned, and at least the
    given number of seconds needs to have passed. Raised exceptions are
    caught, logged and then suppressed.

    func (function): the function to call.
    period (float): the desired interval between successive calls.

    """
    while True:
        call = monotonic_time()

        try:
            func()
        except Exception:
            logger.error("Unexpected error.", exc_info=True)

        gevent.sleep(max(call + period - monotonic_time(), 0))
예제 #11
0
def repeater(func, period):
    """Repeatedly call the given function.

    Continuosly calls the given function, over and over. For a call to
    be issued the previous one needs to have returned, and at least the
    given number of seconds needs to have passed. Raised exceptions are
    caught, logged and then suppressed.

    func (function): the function to call.
    period (float): the desired interval between successive calls.

    """
    while True:
        call = monotonic_time()

        try:
            func()
        except Exception:
            logger.error("Unexpected error.", exc_info=True)

        gevent.sleep(max(call + period - monotonic_time(), 0))
예제 #12
0
파일: Sandbox.py 프로젝트: akmohtashami/cms
    def get_execution_wall_clock_time(self):
        """Return the total time from the start of the sandbox to the
        conclusion of the task.

        return (float): total time the sandbox was alive.

        """
        if self.exec_time:
            return self.exec_time
        if self.popen_time:
            self.exec_time = monotonic_time() - self.popen_time
            return self.exec_time
        return None
예제 #13
0
파일: Sandbox.py 프로젝트: ioi-2017/cms
    def get_execution_wall_clock_time(self):
        """Return the total time from the start of the sandbox to the
        conclusion of the task.

        return (float): total time the sandbox was alive.

        """
        if self.exec_time:
            return self.exec_time
        if self.popen_time:
            self.exec_time = monotonic_time() - self.popen_time
            return self.exec_time
        return None
예제 #14
0
    def stop(self):
        """Quit gracefully. Or not: if the quit RPC does not work, kill."""
        if self.service_name != "RankingWebServer":
            # Try to terminate gracefully (RWS does not have a way to do it).
            logger.info("Asking %s/%s to terminate...", self.service_name,
                        self.shard)
            rs = RemoteService(self.cms_config, self.service_name, self.shard)
            rs.call("quit", {"reason": "from test harness"})

        # If it didn't understand, use bad manners.
        self._check()
        if self.healthy:
            logger.info("Interrupting %s/%s.", self.service_name, self.shard)
            self.instance.send_signal(signal.SIGINT)
            # FIXME on py3 this becomes self.instance.wait(timeout=5)
            t = monotonic_time()
            while monotonic_time() - t < 5:
                if self.instance.poll() is not None:
                    break
                time.sleep(0.1)
            else:
                logger.info("Killing %s/%s.", self.service_name, self.shard)
                self.instance.kill()
예제 #15
0
    def stop(self):
        """Quit gracefully. Or not: if the quit RPC does not work, kill."""
        if self.service_name != "RankingWebServer":
            # Try to terminate gracefully (RWS does not have a way to do it).
            logger.info("Asking %s/%s to terminate...",
                        self.service_name, self.shard)
            rs = RemoteService(self.cms_config, self.service_name, self.shard)
            rs.call("quit", {"reason": "from test harness"})

        # If it didn't understand, use bad manners.
        self._check()
        if self.healthy:
            logger.info("Interrupting %s/%s.", self.service_name, self.shard)
            self.instance.send_signal(signal.SIGINT)
            # FIXME on py3 this becomes self.instance.wait(timeout=5)
            t = monotonic_time()
            while monotonic_time() - t < 5:
                if self.instance.poll() is not None:
                    break
                time.sleep(0.1)
            else:
                logger.info("Killing %s/%s.", self.service_name, self.shard)
                self.instance.kill()
예제 #16
0
    def add_timeout(self, func, plus, seconds, immediately=False):
        """Registers a function to be called every x seconds.

        func (function): the function to call.
        plus (object): additional data to pass to the function.
        seconds (float): the function will be called every seconds
                         seconds.
        immediately (bool): if True, func will be called also at the
                            beginning.

        """
        next_timeout = monotonic_time()
        if not immediately:
            next_timeout += seconds
        heapq.heappush(self._timeouts, (next_timeout, seconds, func, plus))

        # Wake up the run() cycle
        self.event.set()
예제 #17
0
    def _trigger(self, maximum=2.0):
        """Call the timeouts that have expired and find interval to
        next timeout (capped to maximum second).

        maximum (float): seconds to cap to the value.
        return (float): seconds to next timeout.

        """
        current = monotonic_time()

        # Try to connect to disconnected services.
        self._reconnect()

        # Check if some scheduled function needs to be called.
        while self._timeouts != []:
            timeout_data = self._timeouts[0]
            next_timeout, _, _, _ = timeout_data
            if current > next_timeout:
                heapq.heappop(self._timeouts)

                # The helper function checks the return value and, if
                # needed, enqueues the next timeout call
                def helper(timeout_data):
                    next_timeout, seconds, func, plus = timeout_data
                    if plus is None:
                        ret = func()
                    else:
                        ret = func(plus)
                    if ret:
                        heapq.heappush(self._timeouts,
                                       (next_timeout + seconds,
                                        seconds, func, plus))

                gevent.spawn(helper, timeout_data)
            else:
                break

        # Compute time to next timeout call
        next_timeout = maximum
        if self._timeouts != []:
            next_timeout = min(next_timeout, self._timeouts[0][0] - current)
        return max(0.0, next_timeout)
예제 #18
0
파일: Sandbox.py 프로젝트: ioi-2017/cms
    def execute_without_std(self, command, wait=False):
        """Execute the given command in the sandbox using
        subprocess.Popen and discarding standard input, output and
        error. More specifically, the standard input gets closed just
        after the execution has started; standard output and error are
        read until the end, in a way that prevents the execution from
        being blocked because of insufficient buffering.

        command ([string]): executable filename and arguments of the
            command.

        return (bool): True if the sandbox didn't report errors
            (caused by the sandbox itself), False otherwise

        """
        def preexec_fn(self):
            """Set limits for the child process.

            """
            if self.chdir:
                os.chdir(self.chdir)

            # TODO - We're not checking that setrlimit() returns
            # successfully (they may try to set to higher limits than
            # allowed to); anyway, this is just for testing
            # environment, not for real contests, so who cares.
            if self.timeout:
                rlimit_cpu = self.timeout
                if self.extra_timeout:
                    rlimit_cpu += self.extra_timeout
                rlimit_cpu = int(rlimit_cpu) + 1
                resource.setrlimit(resource.RLIMIT_CPU,
                                   (rlimit_cpu, rlimit_cpu))

            if self.address_space:
                rlimit_data = int(self.address_space * 1024)
                resource.setrlimit(resource.RLIMIT_DATA,
                                   (rlimit_data, rlimit_data))

            if self.stack_space:
                rlimit_stack = int(self.stack_space * 1024)
                resource.setrlimit(resource.RLIMIT_STACK,
                                   (rlimit_stack, rlimit_stack))

            # TODO - Doesn't work as expected
            #resource.setrlimit(resource.RLIMIT_NPROC, (1, 1))

        # Setup std*** redirection
        if self.stdin_file:
            stdin_fd = os.open(os.path.join(self.path, self.stdin_file),
                               os.O_RDONLY)
        else:
            stdin_fd = subprocess.PIPE
        if self.stdout_file:
            stdout_fd = os.open(os.path.join(self.path, self.stdout_file),
                                os.O_WRONLY | os.O_TRUNC | os.O_CREAT,
                                stat.S_IRUSR | stat.S_IRGRP |
                                stat.S_IROTH | stat.S_IWUSR)
        else:
            stdout_fd = subprocess.PIPE
        if self.stderr_file:
            stderr_fd = os.open(os.path.join(self.path, self.stderr_file),
                                os.O_WRONLY | os.O_TRUNC | os.O_CREAT,
                                stat.S_IRUSR | stat.S_IRGRP |
                                stat.S_IROTH | stat.S_IWUSR)
        else:
            stderr_fd = subprocess.PIPE

        # Note down execution time
        self.popen_time = monotonic_time()

        # Actually call the Popen
        self.popen = self._popen(command,
                                 stdin=stdin_fd,
                                 stdout=stdout_fd,
                                 stderr=stderr_fd,
                                 preexec_fn=partial(preexec_fn, self),
                                 close_fds=True)

        # Close file descriptors passed to the child
        if self.stdin_file:
            os.close(stdin_fd)
        if self.stdout_file:
            os.close(stdout_fd)
        if self.stderr_file:
            os.close(stderr_fd)

        if self.wallclock_timeout:
            # Kill the process after the wall clock time passed
            def timed_killer(timeout, popen):
                gevent.sleep(timeout)
                # TODO - Here we risk to kill some other process that gets
                # the same PID in the meantime; I don't know how to
                # properly solve this problem
                try:
                    popen.kill()
                except OSError:
                    # The process had died by itself
                    pass

            # Setup the killer
            full_wallclock_timeout = self.wallclock_timeout
            if self.extra_timeout:
                full_wallclock_timeout += self.extra_timeout
            gevent.spawn(timed_killer, full_wallclock_timeout, self.popen)

        # If the caller wants us to wait for completion, we also avoid
        # std*** to interfere with command. Otherwise we let the
        # caller handle these issues.
        if wait:
            return self.translate_box_exitcode(
                wait_without_std([self.popen])[0])
        else:
            return self.popen
예제 #19
0
 def add(self, key, value):
     logger.debug("Adding item %s", key)
     with self.d_lock:
         self.d[key] = value
         self.last_insert = monotonic_time()
예제 #20
0
파일: flushingdict.py 프로젝트: Nyrio/cms
 def add(self, key, value):
     logger.debug("Adding item %s", key)
     with self.d_lock:
         self.d[key] = value
         self.last_insert = monotonic_time()
예제 #21
0
파일: Sandbox.py 프로젝트: akmohtashami/cms
    def execute_without_std(self, command, wait=False):
        """Execute the given command in the sandbox using
        subprocess.Popen and discarding standard input, output and
        error. More specifically, the standard input gets closed just
        after the execution has started; standard output and error are
        read until the end, in a way that prevents the execution from
        being blocked because of insufficient buffering.

        command ([string]): executable filename and arguments of the
            command.

        return (bool): True if the sandbox didn't report errors
            (caused by the sandbox itself), False otherwise

        """
        def preexec_fn(self):
            """Set limits for the child process.

            """
            if self.chdir:
                os.chdir(self.chdir)

            # TODO - We're not checking that setrlimit() returns
            # successfully (they may try to set to higher limits than
            # allowed to); anyway, this is just for testing
            # environment, not for real contests, so who cares.
            if self.timeout:
                rlimit_cpu = self.timeout
                if self.extra_timeout:
                    rlimit_cpu += self.extra_timeout
                rlimit_cpu = int(rlimit_cpu) + 1
                resource.setrlimit(resource.RLIMIT_CPU,
                                   (rlimit_cpu, rlimit_cpu))

            if self.address_space:
                rlimit_data = int(self.address_space * 1024)
                resource.setrlimit(resource.RLIMIT_DATA,
                                   (rlimit_data, rlimit_data))

            if self.stack_space:
                rlimit_stack = int(self.stack_space * 1024)
                resource.setrlimit(resource.RLIMIT_STACK,
                                   (rlimit_stack, rlimit_stack))

            # TODO - Doesn't work as expected
            #resource.setrlimit(resource.RLIMIT_NPROC, (1, 1))

        # Setup std*** redirection
        if self.stdin_file:
            stdin_fd = os.open(os.path.join(self.path, self.stdin_file),
                               os.O_RDONLY)
        else:
            stdin_fd = subprocess.PIPE
        if self.stdout_file:
            stdout_fd = os.open(os.path.join(self.path, self.stdout_file),
                                os.O_WRONLY | os.O_TRUNC | os.O_CREAT,
                                stat.S_IRUSR | stat.S_IRGRP |
                                stat.S_IROTH | stat.S_IWUSR)
        else:
            stdout_fd = subprocess.PIPE
        if self.stderr_file:
            stderr_fd = os.open(os.path.join(self.path, self.stderr_file),
                                os.O_WRONLY | os.O_TRUNC | os.O_CREAT,
                                stat.S_IRUSR | stat.S_IRGRP |
                                stat.S_IROTH | stat.S_IWUSR)
        else:
            stderr_fd = subprocess.PIPE

        # Note down execution time
        self.popen_time = monotonic_time()

        # Actually call the Popen
        self.popen = self._popen(command,
                                 stdin=stdin_fd,
                                 stdout=stdout_fd,
                                 stderr=stderr_fd,
                                 preexec_fn=partial(preexec_fn, self),
                                 close_fds=True)

        # Close file descriptors passed to the child
        if self.stdin_file:
            os.close(stdin_fd)
        if self.stdout_file:
            os.close(stdout_fd)
        if self.stderr_file:
            os.close(stderr_fd)

        if self.wallclock_timeout:
            # Kill the process after the wall clock time passed
            def timed_killer(timeout, popen):
                gevent.sleep(timeout)
                # TODO - Here we risk to kill some other process that gets
                # the same PID in the meantime; I don't know how to
                # properly solve this problem
                try:
                    popen.kill()
                except OSError:
                    # The process had died by itself
                    pass

            # Setup the killer
            full_wallclock_timeout = self.wallclock_timeout
            if self.extra_timeout:
                full_wallclock_timeout += self.extra_timeout
            gevent.spawn(timed_killer, full_wallclock_timeout, self.popen)

        # If the caller wants us to wait for completion, we also avoid
        # std*** to interfere with command. Otherwise we let the
        # caller handle these issues.
        if wait:
            return self.translate_box_exitcode(
                wait_without_std([self.popen])[0])
        else:
            return self.popen