Module RelayModel.SortedListNode

Expand source code
import time
import traceback

from RelayModel.Node import Node
from RelayModel.RelayId import RelayId


class SortedListNodeState:
    """Holds all information needed to pass a state of the SortedListNode.

    This class is needed to analyse a system of sorted list nodes. It gets send to the StateMonitor while simulating.

    Attributes:
        node_id (int): Holds the node id of the node.
        left (StateRelay): Holds the relay which defines the connection of the left neighbor.
        right (StateRelay): Holds the relay which defines the connection of the right neighbor.
        relays (list): Holds a list of StateRelays which containing relays that are present in the underlying
            RelayLayer.
        running (bool): Holds the running status of the node.
        leaving (bool): Holds the leaving status of the node.
    """

    def __init__(self, node_id, left, right, relays, running, leaving):
        """When creating the state object all attributes must be set from the parameters.

        Args:
            node_id (int): Defines the node_id attribute.
            left (StateRelay): Defines the left neighbor connection.
            right (StateRelay): Defines the right neighbor connection.
            relays (list): Defines the list of StateRelays.
            running (bool): Defines the running state of the node.
            leaving (bool): Defines the leaving state of the node.
        """
        self.node_id = node_id
        self.left = left
        self.right = right
        self.relays = relays
        self.running = running
        self.leaving = leaving

    def __str__(self):
        left = self.left.sink_rid if self.left is not None else 'None'
        right = self.right.sink_rid if self.right is not None else 'None'
        return "State: node_id={}, left={} " \
               "right={} relays={}" \
               "running={} leaving={}".format(self.node_id, left, right, self.relays, self.running, self.leaving)


class StateRelay:
    """Holds every information needed to analyse Relays.

    This class is used to send Relay information to the StateMonitor. It should only be used in a State object.

    Attributes:
        relay_id (RelayId): Holds the RelayId of the Relay which information should be stored.
        alive (bool): Holds the alive state of the Relay.
        sink_rid (RelayLayerId): Holds the rid of the sink relay of the relay connection.
        direct (bool): Holds the direct information of the Relay.
    """
    def __init__(self, relay):
        """When creating a StateRelay object only a Relay object is needed.

        From this Relay object all necessary information are extracted and stored into this class.

        Args:
            relay (Relay): The Relay object this StateRelay should represent.
        """
        self.relay_id = relay.relay_id
        self.alive = relay.alive
        self.sink_rid = relay.sink_rid
        self.direct = relay.is_direct()


class SortedListNode(Node):
    """The implementation of a sorted list node.

    This class is an implementation of a sorted list protokoll. It is adjusted to work with the relay modell.

    Attributes:
        node_id (int): Holds the node id of the node to form a list topology.
        left (RelayId): Holds the RelayId of the left neighbor Relay connection.
        right (RelayId): Holds the RelayId of the right neighbor Relay connection.
    """
    def __init__(self, node_id, ip: str, port: int, analyse_mode=False):
        """When creating a SortedListNode object every parameter from the Node class is needed.

        Args:
            node_id (int): Defines the node id of this specific node.
            ip (str): Defines the ip address the node should be reachable on.
            port (int): Defines the port the node should be reachable on.
            analyse_mode (bool, optional): Whether the node should be executed in analyse mode or not.
        """
        super(SortedListNode, self).__init__(node_id, ip, port, analyse_mode)

        self.node_id = node_id
        self.__left = None
        self.__right = None

    def __set_left(self, relay):
        if relay is None:
            self.logger.debug("REMOVE LEFT SET TO NONE")
            self.__left = None
        elif isinstance(relay, RelayId):
            # print("Setting left relay", relay.relay_id)
            self.__left = relay
            self.relay_layer.validate_relay(relay)

    def __get_left(self):
        """Handles the left neighbor attribute.

        When setting the left neighbor it only accepts None or a RelayId as a value. When setting the neighbor the Relay
        gets validated after setting.
        """
        return self.__left

    def __set_right(self, relay):
        if relay is None:
            self.logger.debug("REMOVE RIGHT SET TO NONE")
            self.__right = None
        elif isinstance(relay, RelayId):
            # print("Setting right relay", relay.relay_id)
            self.__right = relay
            self.relay_layer.validate_relay(relay)

    def __get_right(self):
        """Handles the right neighbor attribute.

        When setting the right neighbor it only accepts None or a RelayId as a value. When setting the neighbor the
        Relay gets validated after setting.
        """
        return self.__right

    left = property(__get_left, __set_left)
    right = property(__get_right, __set_right)

    def original_timeout(self):
        """Overrides the method from the node class to implement a BuildList protocol.

        The method corrects left and right neighbors and introduces itself to them.
        For further information see the thesis of this module.
        """
        # print(self.node_id, list(
        #     map(lambda x: str(x.relay_id) + "->" + str(x.out_relay.out_id) if x is not None else "",
        #         self.get_relays_from_original_variables())))
        self.logger.debug("{} \t ".format(self.node_id) +
              "left: {}\t".format(str(self.left) + "->" + str(self.relay_layer.get_sink_node_id(self.left)) if self.left is not None else "None")+
              "right: {}".format(str(self.right) + "->" + str(self.relay_layer.get_sink_node_id(self.right))if self.right is not None else "None"))
        self.logger.debug(f"Original Timeout: left: {self.left} \n right: {self.right}")

        if self.left is not None and isinstance(self.left, RelayId) and self.relay_layer.check_relay_exists(self.left):
            if self.relay_layer.get_sink_node_id(self.left) < self.node_id:
                self.logger.debug("Send via left ot")
                self.call_method(self.left, 'linearize', [self.in_ref])
            else:
                # print("Timeout left else")
                # print("Send via in_ref ot")
                # self.call_method(self.in_ref, 'linearize', [self.left])
                self.logger.debug("Remove left and linearize {}".format(self.left))
                left = self.left
                self.left = None
                self.linearize(left)

        if self.right is not None and isinstance(self.right, RelayId) and self.relay_layer.check_relay_exists(self.right):
            if self.relay_layer.get_sink_node_id(self.right) > self.node_id:
                self.logger.debug("Send via right ot")
                self.call_method(self.right, 'linearize', [self.in_ref])
            else:
                # print("Timeout right else")
                self.logger.debug("Remove right and linearize {}".format(self.right))
                # self.call_method(self.in_ref, 'linearize', [self.right])
                right = self.right
                self.right = None
                self.linearize(right)

    def reversal_of_relay(self, relay_id: RelayId):
        """Overrides the method from the node class.

        The reversal of a relay is given by sending a linearize action to the given relay with the in_ref as parameter.

        Args:
            relay_id (RelayId): Defines the Relay connection that should be reversed.
        """
        # print(f"reversal on {relay.out_relay}")
        self.logger.debug("Reversal sent over relay {} and in ref {}".format(relay_id, self.in_ref))
        self.call_method(relay_id, 'linearize', [self.in_ref])

    def check_in_original_variables(self, relay_id: RelayId):
        """Overrides the method from the node class.

        It checks if the given RelayId is present in the left or right neighbor variable.

        Args:
            relay_id (RelayId): Defines the RelayId that should be checked.

        Returns:
            bool: True if the given RelayId is in one of the variables, False otherwise.

        """
        if self.__left == relay_id:
            return True
        elif self.__right == relay_id:
            return True
        else:
            return False

    def remove_from_original_variables(self, relay_id: RelayId):
        """Overrides the method from the node class.

        It removes the given RelayId from the left or right neighbor if they are set to this RelayId.

        Args:
            relay_id (RelayId): The RelayId that should be deleted from the variables.
        """
        if self.left == relay_id:
            self.left = None
        elif self.right == relay_id:
            self.right = None

    def get_relays_from_original_variables(self):
        """Overrides the method from the node class.

        It forms a list with the left and right neighbor and returns it.

        Returns:
            list: A list containing the left and right neighbor RelayIds. Or an empty list if none is set at the moment.
        """
        return_list = []
        if self.__left is not None:
            return_list.append(self.__left)

        if self.__right is not None:
            return_list.append(self.__right)
        return return_list

    def send_analyse_state(self):
        """Overrides method from the node class.

        Creates a SortedListNodeState with all information needed and sends it to the StateMonitor.

        Returns:
            bool: Returns the system state. True if system is valid, False otherwise.
        """
        if self.left is not None and self.relay_layer.check_relay_exists(self.left):
            left = StateRelay(self.relay_layer.get_relay_by_relay_id(self.left))
        else:
            left = None

        if self.right is not None and self.relay_layer.check_relay_exists(self.right):
            right = StateRelay(self.relay_layer.get_relay_by_relay_id(self.right))
        else:
            right = None

        validated_relays = self.relay_layer.get_validated_relays()

        state_relays = []

        for relay_id in validated_relays:
            relay = self.relay_layer.get_relay_by_relay_id(relay_id)
            if relay is not None:
                state_relays.append(StateRelay(relay))

        node_state = SortedListNodeState(self.node_id, left, right, state_relays,
                                         self.running, self.leaving)

        return self.send_state_to_monitor(node_state)

    def linearize(self, v: RelayId):
        """Impelements the linearize method from the BuildList protocol.

        For further information see the thesis of this module.

        Args:
            v (RelayId): The connection that should be linearized.
        """
        self.logger.debug(f"Linearize relay: {v}\n left: {self.left}\n right: {self.right}")
        if v is None:
            self.logger.warning("V is NONE")
            return

        v_node_id = self.relay_layer.get_sink_node_id(v)
        if v_node_id is None:
            return
        v_level = self.relay_layer.get_level(v)
        if self.left is not None and self.relay_layer.check_relay_exists(self.left):
            left_node_id = self.relay_layer.get_sink_node_id(self.left)
            if v_node_id < left_node_id:
                self.call_method(self.left, 'linearize', [v])
                self.relay_layer.validate_relay(v)
            if left_node_id < v_node_id < self.node_id:
                self.logger.debug("Send left via v")
                self.call_method(v, 'linearize', [self.left])
                self.left = v
                self.logger.debug("Self left after sending v {}".format(self.left))
            elif left_node_id == v_node_id and self.left != v:
                self.logger.debug(f"Merge left: {self.left}\n v: {v}")
                merged = self.relay_layer.merge([self.left, v])

                if merged is not None:
                    self.logger.debug(f"Merged: {merged.relay_id} from {self.left} and {v}")
                    self.left = merged

                else:
                    # self.logger.warning(f"Merged failed in node for {self.left} \nand {v}!!")
                    left_level = self.relay_layer.get_level(self.left)
                    if left_level is None or v_level < left_level:
                        left = self.left
                        self.left = v
                        self.relay_layer.delete(left)
                    else:
                        self.relay_layer.delete(v)
        else:
            if v_node_id < self.node_id:
                self.logger.debug("Set left to v")
                self.left = v
                self.logger.debug("After set {}".format(self.left))

        if self.right is not None and self.relay_layer.check_relay_exists(self.right):
            right_node_id = self.relay_layer.get_sink_node_id(self.right)
            if self.node_id < v_node_id < right_node_id:
                self.logger.debug("Send right via v")
                self.call_method(v, 'linearize', [self.right])
                self.right = v
                self.logger.debug("right after send {}".format(self.right))
            elif right_node_id == v_node_id and self.right != v:
                self.logger.debug(f"Merge right: {self.right}\n v: {v}")
                merged = self.relay_layer.merge([self.right, v])
                if merged is not None:
                    self.logger.debug(f"Merged: {merged} from {self.right} and {v}")
                    self.right = merged
                else:
                    right_level = self.relay_layer.get_level(self.right)
                    if right_level is None or v_level < right_level:
                        right = self.right
                        self.right = v
                        self.relay_layer.delete(right)
                    else:
                        self.relay_layer.delete(v)

            if right_node_id < v_node_id:
                self.call_method(self.right, 'linearize', [v])
                self.relay_layer.validate_relay(v)
        else:
            if self.node_id < v_node_id:
                self.right = v

Classes

class SortedListNode (node_id, ip: str, port: int, analyse_mode=False)

The implementation of a sorted list node.

This class is an implementation of a sorted list protokoll. It is adjusted to work with the relay modell.

Attributes

node_id : int
Holds the node id of the node to form a list topology.
left : RelayId
Holds the RelayId of the left neighbor Relay connection.
right : RelayId
Holds the RelayId of the right neighbor Relay connection.

When creating a SortedListNode object every parameter from the Node class is needed.

Args

node_id : int
Defines the node id of this specific node.
ip : str
Defines the ip address the node should be reachable on.
port : int
Defines the port the node should be reachable on.
analyse_mode : bool, optional
Whether the node should be executed in analyse mode or not.
Expand source code
class SortedListNode(Node):
    """The implementation of a sorted list node.

    This class is an implementation of a sorted list protokoll. It is adjusted to work with the relay modell.

    Attributes:
        node_id (int): Holds the node id of the node to form a list topology.
        left (RelayId): Holds the RelayId of the left neighbor Relay connection.
        right (RelayId): Holds the RelayId of the right neighbor Relay connection.
    """
    def __init__(self, node_id, ip: str, port: int, analyse_mode=False):
        """When creating a SortedListNode object every parameter from the Node class is needed.

        Args:
            node_id (int): Defines the node id of this specific node.
            ip (str): Defines the ip address the node should be reachable on.
            port (int): Defines the port the node should be reachable on.
            analyse_mode (bool, optional): Whether the node should be executed in analyse mode or not.
        """
        super(SortedListNode, self).__init__(node_id, ip, port, analyse_mode)

        self.node_id = node_id
        self.__left = None
        self.__right = None

    def __set_left(self, relay):
        if relay is None:
            self.logger.debug("REMOVE LEFT SET TO NONE")
            self.__left = None
        elif isinstance(relay, RelayId):
            # print("Setting left relay", relay.relay_id)
            self.__left = relay
            self.relay_layer.validate_relay(relay)

    def __get_left(self):
        """Handles the left neighbor attribute.

        When setting the left neighbor it only accepts None or a RelayId as a value. When setting the neighbor the Relay
        gets validated after setting.
        """
        return self.__left

    def __set_right(self, relay):
        if relay is None:
            self.logger.debug("REMOVE RIGHT SET TO NONE")
            self.__right = None
        elif isinstance(relay, RelayId):
            # print("Setting right relay", relay.relay_id)
            self.__right = relay
            self.relay_layer.validate_relay(relay)

    def __get_right(self):
        """Handles the right neighbor attribute.

        When setting the right neighbor it only accepts None or a RelayId as a value. When setting the neighbor the
        Relay gets validated after setting.
        """
        return self.__right

    left = property(__get_left, __set_left)
    right = property(__get_right, __set_right)

    def original_timeout(self):
        """Overrides the method from the node class to implement a BuildList protocol.

        The method corrects left and right neighbors and introduces itself to them.
        For further information see the thesis of this module.
        """
        # print(self.node_id, list(
        #     map(lambda x: str(x.relay_id) + "->" + str(x.out_relay.out_id) if x is not None else "",
        #         self.get_relays_from_original_variables())))
        self.logger.debug("{} \t ".format(self.node_id) +
              "left: {}\t".format(str(self.left) + "->" + str(self.relay_layer.get_sink_node_id(self.left)) if self.left is not None else "None")+
              "right: {}".format(str(self.right) + "->" + str(self.relay_layer.get_sink_node_id(self.right))if self.right is not None else "None"))
        self.logger.debug(f"Original Timeout: left: {self.left} \n right: {self.right}")

        if self.left is not None and isinstance(self.left, RelayId) and self.relay_layer.check_relay_exists(self.left):
            if self.relay_layer.get_sink_node_id(self.left) < self.node_id:
                self.logger.debug("Send via left ot")
                self.call_method(self.left, 'linearize', [self.in_ref])
            else:
                # print("Timeout left else")
                # print("Send via in_ref ot")
                # self.call_method(self.in_ref, 'linearize', [self.left])
                self.logger.debug("Remove left and linearize {}".format(self.left))
                left = self.left
                self.left = None
                self.linearize(left)

        if self.right is not None and isinstance(self.right, RelayId) and self.relay_layer.check_relay_exists(self.right):
            if self.relay_layer.get_sink_node_id(self.right) > self.node_id:
                self.logger.debug("Send via right ot")
                self.call_method(self.right, 'linearize', [self.in_ref])
            else:
                # print("Timeout right else")
                self.logger.debug("Remove right and linearize {}".format(self.right))
                # self.call_method(self.in_ref, 'linearize', [self.right])
                right = self.right
                self.right = None
                self.linearize(right)

    def reversal_of_relay(self, relay_id: RelayId):
        """Overrides the method from the node class.

        The reversal of a relay is given by sending a linearize action to the given relay with the in_ref as parameter.

        Args:
            relay_id (RelayId): Defines the Relay connection that should be reversed.
        """
        # print(f"reversal on {relay.out_relay}")
        self.logger.debug("Reversal sent over relay {} and in ref {}".format(relay_id, self.in_ref))
        self.call_method(relay_id, 'linearize', [self.in_ref])

    def check_in_original_variables(self, relay_id: RelayId):
        """Overrides the method from the node class.

        It checks if the given RelayId is present in the left or right neighbor variable.

        Args:
            relay_id (RelayId): Defines the RelayId that should be checked.

        Returns:
            bool: True if the given RelayId is in one of the variables, False otherwise.

        """
        if self.__left == relay_id:
            return True
        elif self.__right == relay_id:
            return True
        else:
            return False

    def remove_from_original_variables(self, relay_id: RelayId):
        """Overrides the method from the node class.

        It removes the given RelayId from the left or right neighbor if they are set to this RelayId.

        Args:
            relay_id (RelayId): The RelayId that should be deleted from the variables.
        """
        if self.left == relay_id:
            self.left = None
        elif self.right == relay_id:
            self.right = None

    def get_relays_from_original_variables(self):
        """Overrides the method from the node class.

        It forms a list with the left and right neighbor and returns it.

        Returns:
            list: A list containing the left and right neighbor RelayIds. Or an empty list if none is set at the moment.
        """
        return_list = []
        if self.__left is not None:
            return_list.append(self.__left)

        if self.__right is not None:
            return_list.append(self.__right)
        return return_list

    def send_analyse_state(self):
        """Overrides method from the node class.

        Creates a SortedListNodeState with all information needed and sends it to the StateMonitor.

        Returns:
            bool: Returns the system state. True if system is valid, False otherwise.
        """
        if self.left is not None and self.relay_layer.check_relay_exists(self.left):
            left = StateRelay(self.relay_layer.get_relay_by_relay_id(self.left))
        else:
            left = None

        if self.right is not None and self.relay_layer.check_relay_exists(self.right):
            right = StateRelay(self.relay_layer.get_relay_by_relay_id(self.right))
        else:
            right = None

        validated_relays = self.relay_layer.get_validated_relays()

        state_relays = []

        for relay_id in validated_relays:
            relay = self.relay_layer.get_relay_by_relay_id(relay_id)
            if relay is not None:
                state_relays.append(StateRelay(relay))

        node_state = SortedListNodeState(self.node_id, left, right, state_relays,
                                         self.running, self.leaving)

        return self.send_state_to_monitor(node_state)

    def linearize(self, v: RelayId):
        """Impelements the linearize method from the BuildList protocol.

        For further information see the thesis of this module.

        Args:
            v (RelayId): The connection that should be linearized.
        """
        self.logger.debug(f"Linearize relay: {v}\n left: {self.left}\n right: {self.right}")
        if v is None:
            self.logger.warning("V is NONE")
            return

        v_node_id = self.relay_layer.get_sink_node_id(v)
        if v_node_id is None:
            return
        v_level = self.relay_layer.get_level(v)
        if self.left is not None and self.relay_layer.check_relay_exists(self.left):
            left_node_id = self.relay_layer.get_sink_node_id(self.left)
            if v_node_id < left_node_id:
                self.call_method(self.left, 'linearize', [v])
                self.relay_layer.validate_relay(v)
            if left_node_id < v_node_id < self.node_id:
                self.logger.debug("Send left via v")
                self.call_method(v, 'linearize', [self.left])
                self.left = v
                self.logger.debug("Self left after sending v {}".format(self.left))
            elif left_node_id == v_node_id and self.left != v:
                self.logger.debug(f"Merge left: {self.left}\n v: {v}")
                merged = self.relay_layer.merge([self.left, v])

                if merged is not None:
                    self.logger.debug(f"Merged: {merged.relay_id} from {self.left} and {v}")
                    self.left = merged

                else:
                    # self.logger.warning(f"Merged failed in node for {self.left} \nand {v}!!")
                    left_level = self.relay_layer.get_level(self.left)
                    if left_level is None or v_level < left_level:
                        left = self.left
                        self.left = v
                        self.relay_layer.delete(left)
                    else:
                        self.relay_layer.delete(v)
        else:
            if v_node_id < self.node_id:
                self.logger.debug("Set left to v")
                self.left = v
                self.logger.debug("After set {}".format(self.left))

        if self.right is not None and self.relay_layer.check_relay_exists(self.right):
            right_node_id = self.relay_layer.get_sink_node_id(self.right)
            if self.node_id < v_node_id < right_node_id:
                self.logger.debug("Send right via v")
                self.call_method(v, 'linearize', [self.right])
                self.right = v
                self.logger.debug("right after send {}".format(self.right))
            elif right_node_id == v_node_id and self.right != v:
                self.logger.debug(f"Merge right: {self.right}\n v: {v}")
                merged = self.relay_layer.merge([self.right, v])
                if merged is not None:
                    self.logger.debug(f"Merged: {merged} from {self.right} and {v}")
                    self.right = merged
                else:
                    right_level = self.relay_layer.get_level(self.right)
                    if right_level is None or v_level < right_level:
                        right = self.right
                        self.right = v
                        self.relay_layer.delete(right)
                    else:
                        self.relay_layer.delete(v)

            if right_node_id < v_node_id:
                self.call_method(self.right, 'linearize', [v])
                self.relay_layer.validate_relay(v)
        else:
            if self.node_id < v_node_id:
                self.right = v

Ancestors

Instance variables

var left

Handles the left neighbor attribute.

When setting the left neighbor it only accepts None or a RelayId as a value. When setting the neighbor the Relay gets validated after setting.

Expand source code
def __get_left(self):
    """Handles the left neighbor attribute.

    When setting the left neighbor it only accepts None or a RelayId as a value. When setting the neighbor the Relay
    gets validated after setting.
    """
    return self.__left
var right

Handles the right neighbor attribute.

When setting the right neighbor it only accepts None or a RelayId as a value. When setting the neighbor the Relay gets validated after setting.

Expand source code
def __get_right(self):
    """Handles the right neighbor attribute.

    When setting the right neighbor it only accepts None or a RelayId as a value. When setting the neighbor the
    Relay gets validated after setting.
    """
    return self.__right

Methods

def check_in_original_variables(self, relay_id: RelayId)

Overrides the method from the node class.

It checks if the given RelayId is present in the left or right neighbor variable.

Args

relay_id : RelayId
Defines the RelayId that should be checked.

Returns

bool
True if the given RelayId is in one of the variables, False otherwise.
Expand source code
def check_in_original_variables(self, relay_id: RelayId):
    """Overrides the method from the node class.

    It checks if the given RelayId is present in the left or right neighbor variable.

    Args:
        relay_id (RelayId): Defines the RelayId that should be checked.

    Returns:
        bool: True if the given RelayId is in one of the variables, False otherwise.

    """
    if self.__left == relay_id:
        return True
    elif self.__right == relay_id:
        return True
    else:
        return False
def get_relays_from_original_variables(self)

Overrides the method from the node class.

It forms a list with the left and right neighbor and returns it.

Returns

list
A list containing the left and right neighbor RelayIds. Or an empty list if none is set at the moment.
Expand source code
def get_relays_from_original_variables(self):
    """Overrides the method from the node class.

    It forms a list with the left and right neighbor and returns it.

    Returns:
        list: A list containing the left and right neighbor RelayIds. Or an empty list if none is set at the moment.
    """
    return_list = []
    if self.__left is not None:
        return_list.append(self.__left)

    if self.__right is not None:
        return_list.append(self.__right)
    return return_list
def linearize(self, v: RelayId)

Impelements the linearize method from the BuildList protocol.

For further information see the thesis of this module.

Args

v : RelayId
The connection that should be linearized.
Expand source code
def linearize(self, v: RelayId):
    """Impelements the linearize method from the BuildList protocol.

    For further information see the thesis of this module.

    Args:
        v (RelayId): The connection that should be linearized.
    """
    self.logger.debug(f"Linearize relay: {v}\n left: {self.left}\n right: {self.right}")
    if v is None:
        self.logger.warning("V is NONE")
        return

    v_node_id = self.relay_layer.get_sink_node_id(v)
    if v_node_id is None:
        return
    v_level = self.relay_layer.get_level(v)
    if self.left is not None and self.relay_layer.check_relay_exists(self.left):
        left_node_id = self.relay_layer.get_sink_node_id(self.left)
        if v_node_id < left_node_id:
            self.call_method(self.left, 'linearize', [v])
            self.relay_layer.validate_relay(v)
        if left_node_id < v_node_id < self.node_id:
            self.logger.debug("Send left via v")
            self.call_method(v, 'linearize', [self.left])
            self.left = v
            self.logger.debug("Self left after sending v {}".format(self.left))
        elif left_node_id == v_node_id and self.left != v:
            self.logger.debug(f"Merge left: {self.left}\n v: {v}")
            merged = self.relay_layer.merge([self.left, v])

            if merged is not None:
                self.logger.debug(f"Merged: {merged.relay_id} from {self.left} and {v}")
                self.left = merged

            else:
                # self.logger.warning(f"Merged failed in node for {self.left} \nand {v}!!")
                left_level = self.relay_layer.get_level(self.left)
                if left_level is None or v_level < left_level:
                    left = self.left
                    self.left = v
                    self.relay_layer.delete(left)
                else:
                    self.relay_layer.delete(v)
    else:
        if v_node_id < self.node_id:
            self.logger.debug("Set left to v")
            self.left = v
            self.logger.debug("After set {}".format(self.left))

    if self.right is not None and self.relay_layer.check_relay_exists(self.right):
        right_node_id = self.relay_layer.get_sink_node_id(self.right)
        if self.node_id < v_node_id < right_node_id:
            self.logger.debug("Send right via v")
            self.call_method(v, 'linearize', [self.right])
            self.right = v
            self.logger.debug("right after send {}".format(self.right))
        elif right_node_id == v_node_id and self.right != v:
            self.logger.debug(f"Merge right: {self.right}\n v: {v}")
            merged = self.relay_layer.merge([self.right, v])
            if merged is not None:
                self.logger.debug(f"Merged: {merged} from {self.right} and {v}")
                self.right = merged
            else:
                right_level = self.relay_layer.get_level(self.right)
                if right_level is None or v_level < right_level:
                    right = self.right
                    self.right = v
                    self.relay_layer.delete(right)
                else:
                    self.relay_layer.delete(v)

        if right_node_id < v_node_id:
            self.call_method(self.right, 'linearize', [v])
            self.relay_layer.validate_relay(v)
    else:
        if self.node_id < v_node_id:
            self.right = v
def original_timeout(self)

Overrides the method from the node class to implement a BuildList protocol.

The method corrects left and right neighbors and introduces itself to them. For further information see the thesis of this module.

Expand source code
def original_timeout(self):
    """Overrides the method from the node class to implement a BuildList protocol.

    The method corrects left and right neighbors and introduces itself to them.
    For further information see the thesis of this module.
    """
    # print(self.node_id, list(
    #     map(lambda x: str(x.relay_id) + "->" + str(x.out_relay.out_id) if x is not None else "",
    #         self.get_relays_from_original_variables())))
    self.logger.debug("{} \t ".format(self.node_id) +
          "left: {}\t".format(str(self.left) + "->" + str(self.relay_layer.get_sink_node_id(self.left)) if self.left is not None else "None")+
          "right: {}".format(str(self.right) + "->" + str(self.relay_layer.get_sink_node_id(self.right))if self.right is not None else "None"))
    self.logger.debug(f"Original Timeout: left: {self.left} \n right: {self.right}")

    if self.left is not None and isinstance(self.left, RelayId) and self.relay_layer.check_relay_exists(self.left):
        if self.relay_layer.get_sink_node_id(self.left) < self.node_id:
            self.logger.debug("Send via left ot")
            self.call_method(self.left, 'linearize', [self.in_ref])
        else:
            # print("Timeout left else")
            # print("Send via in_ref ot")
            # self.call_method(self.in_ref, 'linearize', [self.left])
            self.logger.debug("Remove left and linearize {}".format(self.left))
            left = self.left
            self.left = None
            self.linearize(left)

    if self.right is not None and isinstance(self.right, RelayId) and self.relay_layer.check_relay_exists(self.right):
        if self.relay_layer.get_sink_node_id(self.right) > self.node_id:
            self.logger.debug("Send via right ot")
            self.call_method(self.right, 'linearize', [self.in_ref])
        else:
            # print("Timeout right else")
            self.logger.debug("Remove right and linearize {}".format(self.right))
            # self.call_method(self.in_ref, 'linearize', [self.right])
            right = self.right
            self.right = None
            self.linearize(right)
def remove_from_original_variables(self, relay_id: RelayId)

Overrides the method from the node class.

It removes the given RelayId from the left or right neighbor if they are set to this RelayId.

Args

relay_id : RelayId
The RelayId that should be deleted from the variables.
Expand source code
def remove_from_original_variables(self, relay_id: RelayId):
    """Overrides the method from the node class.

    It removes the given RelayId from the left or right neighbor if they are set to this RelayId.

    Args:
        relay_id (RelayId): The RelayId that should be deleted from the variables.
    """
    if self.left == relay_id:
        self.left = None
    elif self.right == relay_id:
        self.right = None
def reversal_of_relay(self, relay_id: RelayId)

Overrides the method from the node class.

The reversal of a relay is given by sending a linearize action to the given relay with the in_ref as parameter.

Args

relay_id : RelayId
Defines the Relay connection that should be reversed.
Expand source code
def reversal_of_relay(self, relay_id: RelayId):
    """Overrides the method from the node class.

    The reversal of a relay is given by sending a linearize action to the given relay with the in_ref as parameter.

    Args:
        relay_id (RelayId): Defines the Relay connection that should be reversed.
    """
    # print(f"reversal on {relay.out_relay}")
    self.logger.debug("Reversal sent over relay {} and in ref {}".format(relay_id, self.in_ref))
    self.call_method(relay_id, 'linearize', [self.in_ref])
def send_analyse_state(self)

Overrides method from the node class.

Creates a SortedListNodeState with all information needed and sends it to the StateMonitor.

Returns

bool
Returns the system state. True if system is valid, False otherwise.
Expand source code
def send_analyse_state(self):
    """Overrides method from the node class.

    Creates a SortedListNodeState with all information needed and sends it to the StateMonitor.

    Returns:
        bool: Returns the system state. True if system is valid, False otherwise.
    """
    if self.left is not None and self.relay_layer.check_relay_exists(self.left):
        left = StateRelay(self.relay_layer.get_relay_by_relay_id(self.left))
    else:
        left = None

    if self.right is not None and self.relay_layer.check_relay_exists(self.right):
        right = StateRelay(self.relay_layer.get_relay_by_relay_id(self.right))
    else:
        right = None

    validated_relays = self.relay_layer.get_validated_relays()

    state_relays = []

    for relay_id in validated_relays:
        relay = self.relay_layer.get_relay_by_relay_id(relay_id)
        if relay is not None:
            state_relays.append(StateRelay(relay))

    node_state = SortedListNodeState(self.node_id, left, right, state_relays,
                                     self.running, self.leaving)

    return self.send_state_to_monitor(node_state)

Inherited members

class SortedListNodeState (node_id, left, right, relays, running, leaving)

Holds all information needed to pass a state of the SortedListNode.

This class is needed to analyse a system of sorted list nodes. It gets send to the StateMonitor while simulating.

Attributes

node_id : int
Holds the node id of the node.
left : StateRelay
Holds the relay which defines the connection of the left neighbor.
right : StateRelay
Holds the relay which defines the connection of the right neighbor.
relays : list
Holds a list of StateRelays which containing relays that are present in the underlying RelayLayer.
running : bool
Holds the running status of the node.
leaving : bool
Holds the leaving status of the node.

When creating the state object all attributes must be set from the parameters.

Args

node_id : int
Defines the node_id attribute.
left : StateRelay
Defines the left neighbor connection.
right : StateRelay
Defines the right neighbor connection.
relays : list
Defines the list of StateRelays.
running : bool
Defines the running state of the node.
leaving : bool
Defines the leaving state of the node.
Expand source code
class SortedListNodeState:
    """Holds all information needed to pass a state of the SortedListNode.

    This class is needed to analyse a system of sorted list nodes. It gets send to the StateMonitor while simulating.

    Attributes:
        node_id (int): Holds the node id of the node.
        left (StateRelay): Holds the relay which defines the connection of the left neighbor.
        right (StateRelay): Holds the relay which defines the connection of the right neighbor.
        relays (list): Holds a list of StateRelays which containing relays that are present in the underlying
            RelayLayer.
        running (bool): Holds the running status of the node.
        leaving (bool): Holds the leaving status of the node.
    """

    def __init__(self, node_id, left, right, relays, running, leaving):
        """When creating the state object all attributes must be set from the parameters.

        Args:
            node_id (int): Defines the node_id attribute.
            left (StateRelay): Defines the left neighbor connection.
            right (StateRelay): Defines the right neighbor connection.
            relays (list): Defines the list of StateRelays.
            running (bool): Defines the running state of the node.
            leaving (bool): Defines the leaving state of the node.
        """
        self.node_id = node_id
        self.left = left
        self.right = right
        self.relays = relays
        self.running = running
        self.leaving = leaving

    def __str__(self):
        left = self.left.sink_rid if self.left is not None else 'None'
        right = self.right.sink_rid if self.right is not None else 'None'
        return "State: node_id={}, left={} " \
               "right={} relays={}" \
               "running={} leaving={}".format(self.node_id, left, right, self.relays, self.running, self.leaving)
class StateRelay (relay)

Holds every information needed to analyse Relays.

This class is used to send Relay information to the StateMonitor. It should only be used in a State object.

Attributes

relay_id : RelayId
Holds the RelayId of the Relay which information should be stored.
alive : bool
Holds the alive state of the Relay.
sink_rid : RelayLayerId
Holds the rid of the sink relay of the relay connection.
direct : bool
Holds the direct information of the Relay.

When creating a StateRelay object only a Relay object is needed.

From this Relay object all necessary information are extracted and stored into this class.

Args

relay : Relay
The Relay object this StateRelay should represent.
Expand source code
class StateRelay:
    """Holds every information needed to analyse Relays.

    This class is used to send Relay information to the StateMonitor. It should only be used in a State object.

    Attributes:
        relay_id (RelayId): Holds the RelayId of the Relay which information should be stored.
        alive (bool): Holds the alive state of the Relay.
        sink_rid (RelayLayerId): Holds the rid of the sink relay of the relay connection.
        direct (bool): Holds the direct information of the Relay.
    """
    def __init__(self, relay):
        """When creating a StateRelay object only a Relay object is needed.

        From this Relay object all necessary information are extracted and stored into this class.

        Args:
            relay (Relay): The Relay object this StateRelay should represent.
        """
        self.relay_id = relay.relay_id
        self.alive = relay.alive
        self.sink_rid = relay.sink_rid
        self.direct = relay.is_direct()