Skip to content

Timer

gradysim.simulator.handler.timer.TimerHandler

Bases: INodeHandler

Adds timers to the simulation. This allows nodes to set timers which is a very important feature when implementing distributed algorithms. Nodes can schedule timers through their providers.

Source code in gradysim/simulator/handler/timer.py
class TimerHandler(INodeHandler):
    """
    Adds timers to the simulation. This allows nodes to set timers
    which is a very important feature when implementing distributed
    algorithms. Nodes can schedule timers through their providers.
    """
    _event_loop: EventLoop

    _timer_id: int
    _pending_timers: Dict[int, Dict[str, Set[int]]]
    """Timers pending for each node. A dict of nodes where the value is a dict of messages and their identifiers."""

    def __init__(self):
        """
        Constructs a TimerHandler, no configuration is necessary.
        """
        self._registed_nodes: Set[Node] = set()
        self._timer_id = 0
        self._pending_timers = defaultdict(lambda : defaultdict(set))

    def get_current_time(self):
        return self._event_loop.current_time

    @staticmethod
    def get_label() -> str:
        return "timer"

    def inject(self, event_loop: EventLoop) -> None:
        self._event_loop = event_loop

    def register_node(self, node: Node) -> None:
        self._registed_nodes.add(node)

    def fire_timer(self, message: str, node: Node, identifier: int):
        """
        Fires a timer. Should be called by the event loop.
        """
        if identifier not in self._pending_timers[node.id][message]:
            return

        node.protocol_encapsulator.handle_timer(message)
        self._pending_timers[node.id][message].remove(identifier)

    def set_timer(self, message: str, timestamp: float, node: Node):
        """
        Sets a timer. Should be called by the nodes' providers. Node needs to be
        registered and timer needs to be set in the future.
        """
        if node not in self._registed_nodes:
            raise TimerException(f"Could not set timer: Node {node.id} not registered")

        if timestamp < self._event_loop.current_time:
            raise TimerException("Could not set timer: Timer cannot be set in the past")

        identifier = self._timer_id
        self._event_loop.schedule_event(timestamp,
                                        lambda: self.fire_timer(message, node, identifier),
                                        label_node(node) + " handle_timer")
        self._pending_timers[node.id][message].add(identifier)
        self._timer_id += 1

    def cancel_timer(self, message: str, node: Node):
        """
        Cancels a timer. Should be called by the nodes' providers. Node needs to be
        registered.
        """
        if node not in self._registed_nodes:
            raise TimerException(f"Could not cancel timer: Node {node.id} not registered")

        self._pending_timers[node.id][message].clear()

__init__()

Constructs a TimerHandler, no configuration is necessary.

Source code in gradysim/simulator/handler/timer.py
def __init__(self):
    """
    Constructs a TimerHandler, no configuration is necessary.
    """
    self._registed_nodes: Set[Node] = set()
    self._timer_id = 0
    self._pending_timers = defaultdict(lambda : defaultdict(set))

cancel_timer(message, node)

Cancels a timer. Should be called by the nodes' providers. Node needs to be registered.

Source code in gradysim/simulator/handler/timer.py
def cancel_timer(self, message: str, node: Node):
    """
    Cancels a timer. Should be called by the nodes' providers. Node needs to be
    registered.
    """
    if node not in self._registed_nodes:
        raise TimerException(f"Could not cancel timer: Node {node.id} not registered")

    self._pending_timers[node.id][message].clear()

fire_timer(message, node, identifier)

Fires a timer. Should be called by the event loop.

Source code in gradysim/simulator/handler/timer.py
def fire_timer(self, message: str, node: Node, identifier: int):
    """
    Fires a timer. Should be called by the event loop.
    """
    if identifier not in self._pending_timers[node.id][message]:
        return

    node.protocol_encapsulator.handle_timer(message)
    self._pending_timers[node.id][message].remove(identifier)

set_timer(message, timestamp, node)

Sets a timer. Should be called by the nodes' providers. Node needs to be registered and timer needs to be set in the future.

Source code in gradysim/simulator/handler/timer.py
def set_timer(self, message: str, timestamp: float, node: Node):
    """
    Sets a timer. Should be called by the nodes' providers. Node needs to be
    registered and timer needs to be set in the future.
    """
    if node not in self._registed_nodes:
        raise TimerException(f"Could not set timer: Node {node.id} not registered")

    if timestamp < self._event_loop.current_time:
        raise TimerException("Could not set timer: Timer cannot be set in the past")

    identifier = self._timer_id
    self._event_loop.schedule_event(timestamp,
                                    lambda: self.fire_timer(message, node, identifier),
                                    label_node(node) + " handle_timer")
    self._pending_timers[node.id][message].add(identifier)
    self._timer_id += 1