From 329d042591decc9453b6fed8eebddb08818982ea Mon Sep 17 00:00:00 2001 From: berkeracir Date: Sun, 23 May 2021 15:27:27 +0300 Subject: [PATCH 1/5] finalize Ricart-Agrawala Algorithm --- MutualExclusion/RicartAgrawala.py | 2 +- tests/MutualExclusion/testRicartAgrawala.py | 111 +++++++++++++++----- 2 files changed, 84 insertions(+), 29 deletions(-) diff --git a/MutualExclusion/RicartAgrawala.py b/MutualExclusion/RicartAgrawala.py index 1ddc2ab..c67d331 100644 --- a/MutualExclusion/RicartAgrawala.py +++ b/MutualExclusion/RicartAgrawala.py @@ -48,7 +48,7 @@ class RicartAgrawalaMessagePayload(GenericMessagePayload): class RicartAgrawalaNode(ComponentModel): - privilegeSleepAmount = 0.1 + privilegeSleepAmount = 1 def __init__(self, componentName, componentID): super().__init__(componentName, componentID) diff --git a/tests/MutualExclusion/testRicartAgrawala.py b/tests/MutualExclusion/testRicartAgrawala.py index dc78674..0e7663f 100644 --- a/tests/MutualExclusion/testRicartAgrawala.py +++ b/tests/MutualExclusion/testRicartAgrawala.py @@ -1,4 +1,5 @@ -import math +import os +import shutil import random from enum import Enum @@ -7,12 +8,17 @@ import networkx as nx import threading from time import sleep from itertools import combinations, groupby -from math import cos, sin, atan2, radians +from math import cos, sin, atan2 from MutualExclusion.RicartAgrawala import RicartAgrawalaNode from Ahc import Topology from Channels import P2PFIFOPerfectChannel + +SAVED_FILE_INDEX = 0 +SAVING_ENABLED = True +SAVE_PATH = os.path.join(os.path.dirname(__file__), "ricartAgrawalaOut") + FPS = 24.0 EDGE_COLOR = '#7F7F7F' @@ -22,8 +28,9 @@ WAITING_NODE_COLOR = '#FFFF00' NODE_COLOR = '#00FF00' drawnGraphNodeColors = [] -drawnGraphNodeClockValues = [] +drawnGraphNodeLabels = [] +labelDistance = 0 class COMMAND(Enum): DRAW = "draw" @@ -36,6 +43,7 @@ class COMMAND(Enum): class ARGUMENT(Enum): ALL = "-all" TIME = "-time" + DISTANCE = "-distance" REQUEST = "-request" REPLY = "-reply" PRIVILEGE = "-privilege" @@ -43,6 +51,7 @@ class ARGUMENT(Enum): MEAN = "-mean" TOTAL = "-total" + def processUserCommand(userInput: str): try: splitInput = userInput.split() @@ -77,10 +86,12 @@ def helpCommand(cmd=COMMAND.HELP): f"\t\"{COMMAND.DRAW.value}\"") elif cmd is COMMAND.SET: print(f"Set:\n" - f"\t\"{COMMAND.SET.value} {ARGUMENT.TIME.value} t\"") + f"\t\"{COMMAND.SET.value} {ARGUMENT.TIME.value} t\"\n" + f"\t\"{COMMAND.SET.value} {ARGUMENT.DISTANCE.value} d\"") elif cmd is COMMAND.GET: print(f"Get:\n" f"\t\"{COMMAND.GET.value} {ARGUMENT.TIME.value}\"\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.DISTANCE.value}\"\n" f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value}\"\n" f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value} nodeId\"\n" f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value} [{ARGUMENT.REQUEST.value}/{ARGUMENT.REPLY.value}/{ARGUMENT.PRIVILEGE.value}/{ARGUMENT.FORWARDED.value}]\"\n" @@ -128,11 +139,14 @@ def drawCommand(args): helpCommand(COMMAND.DRAW) def setCommand(args): - if len(args) == 2: - setTime = ARGUMENT.TIME.value in args + global labelDistance + setTime = ARGUMENT.TIME.value in args + setDistance = ARGUMENT.DISTANCE.value in args + + if setTime and not setDistance: + args.remove(ARGUMENT.TIME.value) - if setTime: - args.remove(ARGUMENT.TIME.value) + if len(args) == 1: try: t = float(args[0]) if t > 0: @@ -141,6 +155,19 @@ def setCommand(args): print(f"Sleep time cannot be set to {t}, choose a value above 0!") except ValueError: print(f"\'{args[0]}\' is not float.") + else: + helpCommand(COMMAND.SET) + elif setDistance and not setTime: + args.remove(ARGUMENT.DISTANCE.value) + + if len(args) == 1: + try: + labelDistance = float(args[0]) + drawGraph(True) + except ValueError: + print(f"\'{args[0]}\' is not float.") + else: + helpCommand(COMMAND.SET) else: helpCommand(COMMAND.SET) @@ -161,7 +188,10 @@ def getNodeInformation(node: RicartAgrawalaNode, request=True, reply=True, privi return f"{node.componentinstancenumber} => " + " | ".join(information) def getCommand(args): + global labelDistance + isTime = ARGUMENT.TIME.value in args + isDistance = ARGUMENT.DISTANCE.value in args isAll = ARGUMENT.ALL.value in args isMean = ARGUMENT.MEAN.value in args @@ -175,6 +205,8 @@ def getCommand(args): if isTime: args.remove(ARGUMENT.TIME.value) + if isDistance: + args.remove(ARGUMENT.DISTANCE.value) if isAll: args.remove(ARGUMENT.ALL.value) if isMean: @@ -190,12 +222,17 @@ def getCommand(args): if isForwarded: args.remove(ARGUMENT.FORWARDED.value) - if isTime and not isAll and not (isMean or isTotal): + if (isTime or isDistance) and not isAll and not (isMean or isTotal): if len(args) == 0 and not areAnyOtherArgumentsSet: - print(f"Sleep amount in critical section is {RicartAgrawalaNode.privilegeSleepAmount} seconds.") + if isTime and not isDistance: + print(f"Sleep amount in critical section is {RicartAgrawalaNode.privilegeSleepAmount} seconds.") + elif isDistance and not isTime: + print(f"Label drawing distance from the node is {labelDistance}.") + else: + helpCommand(COMMAND.GET) else: helpCommand(COMMAND.GET) - elif isAll and not isTime and not (isMean or isTotal): + elif isAll and not (isTime or isDistance) and not (isMean or isTotal): if not areAnyOtherArgumentsSet: isRequest = isReply = isPrivilege = isForwarded = True @@ -205,7 +242,7 @@ def getCommand(args): print(getNodeInformation(node, isRequest, isReply, isPrivilege, isForwarded)) else: helpCommand(COMMAND.GET) - elif (isMean or isTotal) and not isTime and not isAll: + elif (isMean or isTotal) and not (isTime or isDistance) and not isAll: if not areAnyOtherArgumentsSet: isRequest = isReply = isPrivilege = isForwarded = True @@ -236,7 +273,7 @@ def getCommand(args): else: helpCommand(COMMAND.GET) else: - if areAnyOtherArgumentsSet and not isTime and not isAll and not isMean: + if areAnyOtherArgumentsSet and not (isTime or isDistance) and not isAll and not isMean: if len(args) == 1: try: nodeID = int(args[0]) @@ -252,17 +289,18 @@ def getCommand(args): helpCommand(COMMAND.GET) def drawGraph(overwrite=False): - global drawnGraphNodeColors, drawnGraphNodeClockValues + global drawnGraphNodeColors, drawnGraphNodeLabels, labelDistance, SAVED_FILE_INDEX, SAVING_ENABLED G = Topology().G - pos = nx.circular_layout(G, center=(0, 0)) + mstG = nx.minimum_spanning_tree(Topology().G) + pos = nx.drawing.nx_pydot.graphviz_layout(mstG, prog="neato", root=mstG.nodes[0]) # neato twopi sfdp nodeColors = [] - clockValues = [] + nodeLabels = [] for nodeID in Topology().nodes: node = Topology().nodes[nodeID] - G.nodes[nodeID]['clock'] = node.clock - clockValues.append(node.clock) + G.nodes[nodeID]['label'] = node.clock + nodeLabels.append(node.clock) if node.isPrivileged: nodeColors.append(PRIVILEGED_NODE_COLOR) @@ -271,23 +309,33 @@ def drawGraph(overwrite=False): else: nodeColors.append(NODE_COLOR) - if overwrite or nodeColors != drawnGraphNodeColors or clockValues != drawnGraphNodeClockValues: + if overwrite or nodeColors != drawnGraphNodeColors or nodeLabels != drawnGraphNodeLabels: drawnGraphNodeColors = list(nodeColors) - drawnGraphNodeClockValues = list(clockValues) + drawnGraphNodeLabels = list(nodeLabels) - clockLabelsPos = {} + labels = nx.get_node_attributes(G, 'label') + labelPos = {} + centerX, centerY = pos[0] + sumX, sumY = 0, 0 for key in pos: + if key == 0: + pass x, y = pos[key] - r = math.sqrt(x**2 + y**2) - theta = atan2(y, x) + radians(75) - d = 0.1 - clockLabelsPos[key] = (x + d * cos(theta), y + d * sin(theta)) + sumX, sumY = sumX + x, sumY + y + theta = atan2(centerY - y, centerX - x) + labelPos[key] = (x + labelDistance * cos(theta), y + labelDistance * sin(theta)) + meanX, meanY = sumX / len(pos), sumY / len(pos) + theta = atan2(meanY - centerY, meanX - centerX) + labelPos[0] = (centerX + labelDistance * cos(theta), centerY + labelDistance * sin(theta)) - nodeClockLabels = nx.get_node_attributes(G, 'clock') nx.draw(G, pos, node_color=nodeColors, edge_color=EDGE_COLOR, with_labels=True, font_weight='bold') - nx.draw_networkx_labels(G, clockLabelsPos, nodeClockLabels) + nx.draw_networkx_labels(G, labelPos, labels) plt.draw() + if SAVING_ENABLED: + path = os.path.join(SAVE_PATH, f"ra_{SAVED_FILE_INDEX}.png") + plt.savefig(path, format="PNG") + SAVED_FILE_INDEX += 1 plt.show() def graphDrawingDaemon(): @@ -321,12 +369,19 @@ def completeBinomialGraph(n, p, seed=None): return G def main(): - G = completeBinomialGraph(20, 0.00000001, seed=5) + global labelDistance + + G = completeBinomialGraph(5, 0.2, seed=15) + labelDistance = len(G.nodes) topology = Topology() topology.construct_from_graph(G, RicartAgrawalaNode, P2PFIFOPerfectChannel) topology.start() + if os.path.exists(SAVE_PATH): + shutil.rmtree(SAVE_PATH) + os.makedirs(SAVE_PATH) + graphDaemon = threading.Thread(target=graphDrawingDaemon, daemon=True) graphDaemon.start() -- GitLab From d83c318dca75b1ab0ea6a8dd0e1e933f870603a0 Mon Sep 17 00:00:00 2001 From: berkeracir Date: Sun, 23 May 2021 15:28:19 +0300 Subject: [PATCH 2/5] finalize Raymond's Algorithm --- MutualExclusion/Raymond.py | 186 ++++++++++++ tests/MutualExclusion/testRaymond.py | 422 +++++++++++++++++++++++++++ 2 files changed, 608 insertions(+) create mode 100644 MutualExclusion/Raymond.py create mode 100644 tests/MutualExclusion/testRaymond.py diff --git a/MutualExclusion/Raymond.py b/MutualExclusion/Raymond.py new file mode 100644 index 0000000..0a9fe63 --- /dev/null +++ b/MutualExclusion/Raymond.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +""" + Implementation of the Raymond's Algorithm for mutual exclusion. +""" + +__author__ = "Berker Acır" +__contact__ = "berkeracir159@gmail.com" +__copyright__ = "Copyright 2021, WINSLAB" +__credits__ = ["Berker Acır"] +__date__ = "2021/05/18" +__deprecated__ = False +__email__ = "berkeracir159@gmail.com" +__license__ = "GPLv3" +__maintainer__ = "developer" +__status__ = "Production" +__version__ = "0.0.1" + +import random +from enum import Enum +from time import sleep +import networkx as nx + +from Ahc import ComponentModel, Event, EventTypes, GenericMessage, GenericMessagePayload, GenericMessageHeader, inf, \ + Topology + + +class RaymondEventTypes(Enum): + TOKEN = "TOKEN" + REQUEST = "REQUEST" + PRIVILEGE = "PRIVILEGE" + + +class RaymondMessageTypes(Enum): + TOKEN = "TOKEN" + REQUEST = "REQUEST" + + +class RaymondMessageHeader(GenericMessageHeader): + + def __init__(self, messageType, messageFrom, messageTo, nextHop=float('inf'), interfaceID=float('inf'), + sequenceID=-1): + super().__init__(messageType, messageFrom, messageTo, nextHop, interfaceID, sequenceID) + + +class RaymondMessagePayload(GenericMessagePayload): + + def __init__(self, nodeID): + self.nodeID = nodeID + + +class RaymondNode(ComponentModel): + privilegeSleepAmount = 1 + + def __init__(self, componentName, componentID): + super().__init__(componentName, componentID) + + self.eventhandlers[RaymondEventTypes.TOKEN] = self.token_received + self.eventhandlers[RaymondEventTypes.REQUEST] = self.request_received + self.eventhandlers[RaymondEventTypes.PRIVILEGE] = self.on_privilege + + self.neighborNodeIDs = set() + self.parentNodeID = None + self.queue = list() + + self.isRoot = False + self.havePendingRequest = False + self.isPrivileged = False + + self.privilegeCount = 0 + self.sentRequestCount = 0 + self.sentTokenCount = 0 + self.receivedRequestCount = 0 + self.receivedTokenCount = 0 + self.forwardedMessageCount = 0 + + def on_init(self, eventobj: Event): + mstG = nx.minimum_spanning_tree(Topology().G) + self.neighborNodeIDs = set(mstG.neighbors(self.componentinstancenumber)) + if self.componentinstancenumber == 0: + self.isRoot = True + else: + self.parentNodeID = nx.shortest_path(mstG, self.componentinstancenumber, 0)[1] + + def on_message_from_bottom(self, eventobj: Event): + message = eventobj.eventcontent + header = message.header + messageType = header.messagetype + messageTo = header.messageto + + if messageTo == self.componentinstancenumber: + if messageType == RaymondMessageTypes.REQUEST: + eventobj.event = RaymondEventTypes.REQUEST + self.send_self(eventobj) + elif messageType == RaymondMessageTypes.TOKEN: + eventobj.event = RaymondEventTypes.TOKEN + self.send_self(eventobj) + + def put(self, nodeID=None): + if nodeID is None: + nodeID = self.componentinstancenumber + + if not self.queue: + headChanged = True + else: + headChanged = False + self.queue.append(nodeID) + if nodeID == self.componentinstancenumber: + self.havePendingRequest = True + + if headChanged: + if self.isRoot: + if nodeID == self.componentinstancenumber: + self.send_self(Event(self, RaymondEventTypes.PRIVILEGE, None)) + else: + self.send_token(nodeID) + else: + self.send_request() + + def pop(self): + nodeID = self.queue.pop(0) + if nodeID == self.componentinstancenumber and nodeID not in self.queue: + self.havePendingRequest = False + + if self.queue: + head = self.queue[0] + if self.isRoot: + if head == self.componentinstancenumber: + self.send_self(Event(self, RaymondEventTypes.PRIVILEGE, None)) + else: + self.send_token(head) + else: + self.send_request() + + def on_privilege(self, eventobj: Event): + self.isPrivileged = True + + self.privilegeCount += 1 + sleep(self.privilegeSleepAmount) + + self.isPrivileged = False + self.pop() + + def token_received(self, eventobj: Event): + print(f"{self.componentinstancenumber} - token received from {self.parentNodeID}") + self.receivedTokenCount += 1 + self.isRoot = True + self.parentNodeID = None + + head = self.queue[0] + if head == self.componentinstancenumber: + self.send_self(Event(self, RaymondEventTypes.PRIVILEGE, None)) + else: + self.send_token(head) + + def request_received(self, eventobj: Event): + print(f"{self.componentinstancenumber} - request received from {eventobj.eventcontent.payload.nodeID}") + self.receivedRequestCount += 1 + receivedRequestNodeID = eventobj.eventcontent.payload.nodeID + self.put(receivedRequestNodeID) + + def send_token(self, nodeID): + print(f"{self.componentinstancenumber} - send token to {nodeID}") + self.sentTokenCount += 1 + self.isRoot = False + self.parentNodeID = nodeID + + nextHop = self.parentNodeID + interfaceID = f"{self.componentinstancenumber}-{nextHop}" + header = RaymondMessageHeader(RaymondMessageTypes.TOKEN, self.componentinstancenumber, self.parentNodeID, + nextHop, interfaceID) + payload = RaymondMessagePayload(self.componentinstancenumber) + message = GenericMessage(header, payload) + self.send_down(Event(self, EventTypes.MFRT, message)) + + self.pop() + + def send_request(self): + print(f"{self.componentinstancenumber} - send request to {self.parentNodeID}") + self.sentRequestCount += 1 + nextHop = self.parentNodeID + interfaceID = f"{self.componentinstancenumber}-{nextHop}" + header = RaymondMessageHeader(RaymondMessageTypes.REQUEST, self.componentinstancenumber, self.parentNodeID, + nextHop, interfaceID) + payload = RaymondMessagePayload(self.componentinstancenumber) + message = GenericMessage(header, payload) + self.send_down(Event(self, EventTypes.MFRT, message)) diff --git a/tests/MutualExclusion/testRaymond.py b/tests/MutualExclusion/testRaymond.py new file mode 100644 index 0000000..1886b70 --- /dev/null +++ b/tests/MutualExclusion/testRaymond.py @@ -0,0 +1,422 @@ +import os +import shutil +import random +from enum import Enum + +import matplotlib.pyplot as plt +import networkx as nx +import threading +from time import sleep +from itertools import combinations, groupby +from math import cos, atan2 + +from MutualExclusion.Raymond import RaymondNode +from Ahc import Topology +from Channels import P2PFIFOPerfectChannel + + +SAVED_FILE_INDEX = 0 +SAVING_ENABLED = True +SAVE_PATH = os.path.join(os.path.dirname(__file__), "raymondOut") + +FPS = 24.0 + +EDGE_COLOR = '#BABABA' +MST_EDGE_COLOR = '#7F7F7F' +ROOT_NODE_EDGE_COLOR = '#000000' + +PRIVILEGED_NODE_COLOR = '#FF0000' +WAITING_NODE_COLOR = '#FFFF00' +NODE_COLOR = '#00FF00' + +drawnGraphNodeColors = [] +drawnGraphNodeLabels = [] +drawnGraphNodeLineWidths = [] +drawnGraphNodeEdgeColors = [] + +labelDistance = 0 + +class COMMAND(Enum): + DRAW = "draw" + REQUEST = "request" + HELP = "help" + SET = "set" + GET = "get" + + +class ARGUMENT(Enum): + ALL = "-all" + TIME = "-time" + DISTANCE = "-distance" + REQUEST = "-request" + TOKEN = "-token" + PRIVILEGE = "-privilege" + FORWARDED = "-forwarded" + MEAN = "-mean" + TOTAL = "-total" + + +def processUserCommand(userInput: str): + try: + splitInput = userInput.split() + cmd = splitInput[0] + args = [] + if len(splitInput) > 1: + args = splitInput[1:] + + if cmd == COMMAND.REQUEST.value: + requestCommand(args) + elif cmd == COMMAND.DRAW.value: + drawCommand(args) + elif cmd == COMMAND.SET.value: + setCommand(args) + elif cmd == COMMAND.GET.value: + getCommand(args) + elif cmd == COMMAND.HELP.value: + helpCommand() + else: + print(f"Unknown input: \'{userInput}\'") + except IndexError: + pass + +def helpCommand(cmd=COMMAND.HELP): + if cmd is COMMAND.REQUEST: + print(f"Request:\n" + f"\t\"{COMMAND.REQUEST.value} nodeId\"\n" + f"\t\"{COMMAND.REQUEST.value} nodeId1 nodeId2...\"\n" + f"\t\"{COMMAND.REQUEST.value} {ARGUMENT.ALL.value}\"") + elif cmd is COMMAND.DRAW: + print(f"Draw:\n" + f"\t\"{COMMAND.DRAW.value}\"") + elif cmd is COMMAND.SET: + print(f"Set:\n" + f"\t\"{COMMAND.SET.value} {ARGUMENT.TIME.value} t\"\n" + f"\t\"{COMMAND.SET.value} {ARGUMENT.DISTANCE.value} d\"") + elif cmd is COMMAND.GET: + print(f"Get:\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.TIME.value}\"\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.DISTANCE.value}\"\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value}\"\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value} nodeId\"\n" + f"\t\"{COMMAND.GET.value} {ARGUMENT.ALL.value} [{ARGUMENT.REQUEST.value}/{ARGUMENT.TOKEN.value}/{ARGUMENT.PRIVILEGE.value}/{ARGUMENT.FORWARDED.value}]\"\n" + f"\t\"{COMMAND.GET.value} [{ARGUMENT.REQUEST.value}/{ARGUMENT.TOKEN.value}/{ARGUMENT.PRIVILEGE.value}/{ARGUMENT.FORWARDED.value}] nodeId\"\n" + f"\t\"{COMMAND.GET.value} [{ARGUMENT.MEAN.value}/{ARGUMENT.TOTAL.value}]\"\n" + f"\t\"{COMMAND.GET.value} [{ARGUMENT.MEAN.value}/{ARGUMENT.TOTAL.value}] [{ARGUMENT.REQUEST.value}/{ARGUMENT.TOKEN.value}/{ARGUMENT.PRIVILEGE.value}/{ARGUMENT.FORWARDED.value}]\"") + else: + helpCommand(COMMAND.REQUEST) + helpCommand(COMMAND.DRAW) + helpCommand(COMMAND.SET) + helpCommand(COMMAND.GET) + +def requestCommand(args): + allNodes = ARGUMENT.ALL.value in args + if allNodes: + args.remove(ARGUMENT.ALL.value) + + if len(args) == 0: + for nodeID in Topology().nodes: + Topology().nodes[nodeID].put() + else: + helpCommand(COMMAND.REQUEST) + else: + nodes = list() + for arg in args: + try: + nodeID = int(arg) + node = Topology().nodes[nodeID] + nodes.append(node) + except KeyError: + print(f"Node {nodeID} does not exist in the topology.") + except ValueError: + print(f"\'{arg}\' is not integer.") + + if nodes: + for node in nodes: + node.put() + else: + helpCommand(COMMAND.REQUEST) + +def drawCommand(args): + if len(args) == 0: + drawGraph(True) + else: + helpCommand(COMMAND.DRAW) + +def setCommand(args): + global labelDistance + + setTime = ARGUMENT.TIME.value in args + setDistance = ARGUMENT.DISTANCE.value in args + + if setTime and not setDistance: + args.remove(ARGUMENT.TIME.value) + + if len(args) == 1: + try: + t = float(args[0]) + if t > 0: + RaymondNode.privilegeSleepAmount = t + else: + print(f"Sleep time cannot be set to {t}, choose a value above 0!") + except ValueError: + print(f"\'{args[0]}\' is not float.") + else: + helpCommand(COMMAND.SET) + elif setDistance and not setTime: + args.remove(ARGUMENT.DISTANCE.value) + + if len(args) == 1: + try: + labelDistance = float(args[0]) + drawGraph(True) + except ValueError: + print(f"\'{args[0]}\' is not float.") + else: + helpCommand(COMMAND.SET) + else: + helpCommand(COMMAND.SET) + +def getNodeInformation(node: RaymondNode, request=True, token=True, privilege=True, forwarded=True): + information = [] + + if request: + information.append(f"ReceivedRequests: {node.receivedRequestCount}") + information.append(f"SentRequests: {node.sentRequestCount}") + if token: + information.append(f"ReceivedTokens: {node.receivedTokenCount}") + information.append(f"SentTokens: {node.sentTokenCount}") + if privilege: + information.append(f"Privileged: {node.privilegeCount}") + if forwarded: + information.append(f"ForwardedMessages: {node.forwardedMessageCount}") + + return f"{node.componentinstancenumber} => " + " | ".join(information) + +def getCommand(args): + global labelDistance + + isTime = ARGUMENT.TIME.value in args + isDistance = ARGUMENT.DISTANCE.value in args + + isAll = ARGUMENT.ALL.value in args + isMean = ARGUMENT.MEAN.value in args + isTotal = ARGUMENT.TOTAL.value in args + + isRequest = ARGUMENT.REQUEST.value in args + isToken = ARGUMENT.TOKEN.value in args + isPrivilege = ARGUMENT.PRIVILEGE.value in args + isForwarded = ARGUMENT.FORWARDED.value in args + areAnyOtherArgumentsSet = isRequest or isToken or isPrivilege or isForwarded + + if isTime: + args.remove(ARGUMENT.TIME.value) + if isDistance: + args.remove(ARGUMENT.DISTANCE.value) + if isAll: + args.remove(ARGUMENT.ALL.value) + if isMean: + args.remove(ARGUMENT.MEAN.value) + if isTotal: + args.remove(ARGUMENT.TOTAL.value) + if isRequest: + args.remove(ARGUMENT.REQUEST.value) + if isToken: + args.remove(ARGUMENT.TOKEN.value) + if isPrivilege: + args.remove(ARGUMENT.PRIVILEGE.value) + if isForwarded: + args.remove(ARGUMENT.FORWARDED.value) + + if (isTime or isDistance) and not isAll and not (isMean or isTotal): + if len(args) == 0 and not areAnyOtherArgumentsSet: + if isTime and not isDistance: + print(f"Sleep amount in critical section is {RaymondNode.privilegeSleepAmount} seconds.") + elif isDistance and not isTime: + print(f"Label drawing distance from the node is {labelDistance}.") + else: + helpCommand(COMMAND.GET) + else: + helpCommand(COMMAND.GET) + elif isAll and not (isTime or isDistance) and not (isMean or isTotal): + if not areAnyOtherArgumentsSet: + isRequest = isToken = isPrivilege = isForwarded = True + + if len(args) == 0: + for nodeID in Topology().nodes: + node = Topology().nodes[nodeID] + print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded)) + else: + helpCommand(COMMAND.GET) + elif (isMean or isTotal) and not (isTime or isDistance) and not isAll: + if not areAnyOtherArgumentsSet: + isRequest = isToken = isPrivilege = isForwarded = True + + if len(args) == 0: + N = len(Topology().nodes) + node = RaymondNode("node", -1) + + for nodeID in Topology().nodes: + node.privilegeCount += Topology().nodes[nodeID].privilegeCount + node.sentRequestCount += Topology().nodes[nodeID].sentRequestCount + node.sentTokenCount += Topology().nodes[nodeID].sentTokenCount + node.receivedRequestCount += Topology().nodes[nodeID].receivedRequestCount + node.receivedTokenCount += Topology().nodes[nodeID].receivedTokenCount + node.forwardedMessageCount += Topology().nodes[nodeID].forwardedMessageCount + + if isTotal: + node.componentinstancenumber = f"Total of {N} Nodes" + print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded)) + if isMean: + node.componentinstancenumber = f"Mean of {N} Nodes" + node.privilegeCount /= N + node.sentRequestCount /= N + node.sentTokenCount /= N + node.receivedRequestCount /= N + node.receivedTokenCount /= N + node.forwardedMessageCount /= N + print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded)) + else: + helpCommand(COMMAND.GET) + else: + if areAnyOtherArgumentsSet and not (isTime or isDistance) and not isAll and not isMean: + if len(args) == 1: + try: + nodeID = int(args[0]) + node = Topology().nodes[nodeID] + print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded)) + except KeyError: + print(f"Node {nodeID} does not exist in the topology.") + except ValueError: + print(f"\'{args[0]}\' is not integer.") + else: + helpCommand(COMMAND.GET) + else: + helpCommand(COMMAND.GET) + +def drawGraph(overwrite=False): + global drawnGraphNodeColors, drawnGraphNodeLabels, drawnGraphNodeLineWidths, drawnGraphNodeEdgeColors, \ + labelDistance, SAVED_FILE_INDEX, SAVING_ENABLED + + G = Topology().G + mstG = nx.minimum_spanning_tree(Topology().G) + pos = nx.drawing.nx_pydot.graphviz_layout(mstG, prog="neato", root=mstG.nodes[0]) # neato twopi sfdp + + nodeColors = [] + nodeLabels = [] + nodeLineWidths = [] + nodeEdgeColors = [] + for nodeID in Topology().nodes: + node = Topology().nodes[nodeID] + label = f"[{','.join([str(i) for i in node.queue])}]" + mstG.nodes[nodeID]['label'] = label + nodeLabels.append(label) + + if node.isPrivileged: + nodeColor = PRIVILEGED_NODE_COLOR + elif node.havePendingRequest: + nodeColor = WAITING_NODE_COLOR + else: + nodeColor = NODE_COLOR + nodeColors.append(nodeColor) + + if node.isRoot: + nodeLineWidths.append(2) + nodeEdgeColors.append(ROOT_NODE_EDGE_COLOR) + else: + nodeLineWidths.append(0) + nodeEdgeColors.append(nodeColor) + + if overwrite or nodeColors != drawnGraphNodeColors or nodeLabels != drawnGraphNodeLabels \ + or nodeLineWidths != drawnGraphNodeLineWidths or nodeEdgeColors != drawnGraphNodeEdgeColors: + drawnGraphNodeColors = list(nodeColors) + drawnGraphNodeLabels = list(nodeLabels) + drawnGraphNodeLineWidths = list(nodeLineWidths) + drawnGraphNodeEdgeColors = list(nodeEdgeColors) + + labels = nx.get_node_attributes(mstG, 'label') + labelPos = {} + centerX, centerY = pos[0] + sumX, sumY = 0, 0 + for key in pos: + if key == 0: + pass + x, y = pos[key] + sumX, sumY = sumX + x, sumY + y + theta = atan2(centerY - y, centerX - x) + if theta >= 0: + labelPos[key] = (x + labelDistance * cos(theta), y + labelDistance) + else: + labelPos[key] = (x + labelDistance * cos(theta), y - labelDistance) + meanX, meanY = sumX / len(pos), sumY / len(pos) + theta = atan2(meanY - centerY, meanX - centerX) + if theta >= 0: + labelPos[0] = (centerX + labelDistance * cos(theta), centerY + labelDistance) + else: + labelPos[0] = (centerX + labelDistance * cos(theta), centerY - labelDistance) + + nx.draw(mstG, pos, node_color=nodeColors, edge_color=MST_EDGE_COLOR, linewidths=nodeLineWidths, + edgecolors=nodeEdgeColors, with_labels=True, font_weight='bold') + nx.draw_networkx_edges(mstG, pos, edgelist=G.edges-mstG.edges, edge_color=EDGE_COLOR, style='dashed') + nx.draw_networkx_labels(mstG, labelPos, labels) + + plt.draw() + if SAVING_ENABLED: + path = os.path.join(SAVE_PATH, f"r_{SAVED_FILE_INDEX}.png") + plt.savefig(path, format="PNG") + SAVED_FILE_INDEX += 1 + plt.show() + +def graphDrawingDaemon(): + while True: + drawGraph() + sleep(1.0 / FPS) + +def completeBinomialGraph(n, p, seed=None): + if seed is not None: + random.seed(seed) + + if p <= 0: + G = nx.empty_graph(n) + elif p >= 1: + G = nx.complete_graph(n) + else: + allEdges = list(combinations(range(n), 2)) + G = nx.empty_graph(n) + + for node, nodeEdges in groupby(allEdges, key=lambda x: x[0]): + nodeEdges = list(nodeEdges) + randomEdge = random.choice(nodeEdges) + G.add_edge(*randomEdge) + for edge in nodeEdges: + if random.random() < p: + G.add_edge(*edge) + + if seed is not None: + random.seed() + + return G + +def main(): + global labelDistance + + G = completeBinomialGraph(5, 0.2, seed=15) + labelDistance = len(G.nodes) + + topology = Topology() + topology.construct_from_graph(G, RaymondNode, P2PFIFOPerfectChannel) + topology.start() + + if os.path.exists(SAVE_PATH): + shutil.rmtree(SAVE_PATH) + os.makedirs(SAVE_PATH) + + graphDaemon = threading.Thread(target=graphDrawingDaemon, daemon=True) + graphDaemon.start() + + while True: + userInput = input("User Command: \n") + processUserCommand(userInput) + + +if __name__ == "__main__": + main() -- GitLab From e41442d93d55aa454c3793939bad0db1b2d0320d Mon Sep 17 00:00:00 2001 From: berkeracir Date: Sun, 23 May 2021 15:29:39 +0300 Subject: [PATCH 3/5] finalize Raymond's Algorithm --- MutualExclusion/Raymond.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MutualExclusion/Raymond.py b/MutualExclusion/Raymond.py index 0a9fe63..6db7ff6 100644 --- a/MutualExclusion/Raymond.py +++ b/MutualExclusion/Raymond.py @@ -141,7 +141,6 @@ class RaymondNode(ComponentModel): self.pop() def token_received(self, eventobj: Event): - print(f"{self.componentinstancenumber} - token received from {self.parentNodeID}") self.receivedTokenCount += 1 self.isRoot = True self.parentNodeID = None @@ -153,13 +152,11 @@ class RaymondNode(ComponentModel): self.send_token(head) def request_received(self, eventobj: Event): - print(f"{self.componentinstancenumber} - request received from {eventobj.eventcontent.payload.nodeID}") self.receivedRequestCount += 1 receivedRequestNodeID = eventobj.eventcontent.payload.nodeID self.put(receivedRequestNodeID) def send_token(self, nodeID): - print(f"{self.componentinstancenumber} - send token to {nodeID}") self.sentTokenCount += 1 self.isRoot = False self.parentNodeID = nodeID @@ -175,7 +172,6 @@ class RaymondNode(ComponentModel): self.pop() def send_request(self): - print(f"{self.componentinstancenumber} - send request to {self.parentNodeID}") self.sentRequestCount += 1 nextHop = self.parentNodeID interfaceID = f"{self.componentinstancenumber}-{nextHop}" -- GitLab From 2762f40659482f951e5d815dbd5371c9f15171cb Mon Sep 17 00:00:00 2001 From: berkeracir Date: Tue, 25 May 2021 02:19:20 +0300 Subject: [PATCH 4/5] increment node's own clock value upon sending request to other nodes --- MutualExclusion/RicartAgrawala.py | 1 + 1 file changed, 1 insertion(+) diff --git a/MutualExclusion/RicartAgrawala.py b/MutualExclusion/RicartAgrawala.py index c67d331..26e5cd3 100644 --- a/MutualExclusion/RicartAgrawala.py +++ b/MutualExclusion/RicartAgrawala.py @@ -150,6 +150,7 @@ class RicartAgrawalaNode(ComponentModel): self.sentRequestCount += 1 self.havePendingRequest = True self.pendingRequestClock = self.clock + self.clock += 1 for nodeID in self.otherNodeIDs: nextHop = Topology().get_next_hop(self.componentinstancenumber, nodeID) -- GitLab From 274b91bf32814b1107e51e6762f149c9c24c2e7d Mon Sep 17 00:00:00 2001 From: berkeracir Date: Wed, 26 May 2021 16:06:46 +0300 Subject: [PATCH 5/5] finalize the project --- MutualExclusion/Raymond.py | 4 +--- tests/MutualExclusion/testRaymond.py | 9 +++++---- tests/MutualExclusion/testRicartAgrawala.py | 9 +++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/MutualExclusion/Raymond.py b/MutualExclusion/Raymond.py index 6db7ff6..f7bdeb9 100644 --- a/MutualExclusion/Raymond.py +++ b/MutualExclusion/Raymond.py @@ -15,13 +15,11 @@ __maintainer__ = "developer" __status__ = "Production" __version__ = "0.0.1" -import random from enum import Enum from time import sleep import networkx as nx -from Ahc import ComponentModel, Event, EventTypes, GenericMessage, GenericMessagePayload, GenericMessageHeader, inf, \ - Topology +from Ahc import ComponentModel, Event, EventTypes, GenericMessage, GenericMessagePayload, GenericMessageHeader, Topology class RaymondEventTypes(Enum): diff --git a/tests/MutualExclusion/testRaymond.py b/tests/MutualExclusion/testRaymond.py index 1886b70..7fc461c 100644 --- a/tests/MutualExclusion/testRaymond.py +++ b/tests/MutualExclusion/testRaymond.py @@ -16,7 +16,7 @@ from Channels import P2PFIFOPerfectChannel SAVED_FILE_INDEX = 0 -SAVING_ENABLED = True +SAVING_ENABLED = False SAVE_PATH = os.path.join(os.path.dirname(__file__), "raymondOut") FPS = 24.0 @@ -262,10 +262,11 @@ def getCommand(args): node.receivedRequestCount += Topology().nodes[nodeID].receivedRequestCount node.receivedTokenCount += Topology().nodes[nodeID].receivedTokenCount node.forwardedMessageCount += Topology().nodes[nodeID].forwardedMessageCount + totalMessageCount = node.receivedRequestCount + node.receivedTokenCount if isTotal: node.componentinstancenumber = f"Total of {N} Nodes" - print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded)) + print(getNodeInformation(node, isRequest, isToken, isPrivilege, isForwarded), f"=> Total Message Count: {totalMessageCount}") if isMean: node.componentinstancenumber = f"Mean of {N} Nodes" node.privilegeCount /= N @@ -371,7 +372,7 @@ def graphDrawingDaemon(): drawGraph() sleep(1.0 / FPS) -def completeBinomialGraph(n, p, seed=None): +def connectedBinomialGraph(n, p, seed=None): if seed is not None: random.seed(seed) @@ -399,7 +400,7 @@ def completeBinomialGraph(n, p, seed=None): def main(): global labelDistance - G = completeBinomialGraph(5, 0.2, seed=15) + G = connectedBinomialGraph(5, 0.2, seed=5) labelDistance = len(G.nodes) topology = Topology() diff --git a/tests/MutualExclusion/testRicartAgrawala.py b/tests/MutualExclusion/testRicartAgrawala.py index 0e7663f..cfb4b2e 100644 --- a/tests/MutualExclusion/testRicartAgrawala.py +++ b/tests/MutualExclusion/testRicartAgrawala.py @@ -16,7 +16,7 @@ from Channels import P2PFIFOPerfectChannel SAVED_FILE_INDEX = 0 -SAVING_ENABLED = True +SAVING_ENABLED = False SAVE_PATH = os.path.join(os.path.dirname(__file__), "ricartAgrawalaOut") FPS = 24.0 @@ -257,10 +257,11 @@ def getCommand(args): node.receivedRequestCount += Topology().nodes[nodeID].receivedRequestCount node.receivedReplyCount += Topology().nodes[nodeID].receivedReplyCount node.forwardedMessageCount += Topology().nodes[nodeID].forwardedMessageCount + totalMessageCount = node.receivedRequestCount + node.receivedReplyCount + node.forwardedMessageCount if isTotal: node.componentinstancenumber = f"Total of {N} Nodes" - print(getNodeInformation(node, isRequest, isReply, isPrivilege, isForwarded)) + print(getNodeInformation(node, isRequest, isReply, isPrivilege, isForwarded), f"=> Total Message Count: {totalMessageCount}") if isMean: node.componentinstancenumber = f"Mean of {N} Nodes" node.privilegeCount /= N @@ -343,7 +344,7 @@ def graphDrawingDaemon(): drawGraph() sleep(1.0/FPS) -def completeBinomialGraph(n, p, seed=None): +def connectedBinomialGraph(n, p, seed=None): if seed is not None: random.seed(seed) @@ -371,7 +372,7 @@ def completeBinomialGraph(n, p, seed=None): def main(): global labelDistance - G = completeBinomialGraph(5, 0.2, seed=15) + G = connectedBinomialGraph(5, 0.2, seed=5) labelDistance = len(G.nodes) topology = Topology() -- GitLab