def create_edges(name, seedy,neighbors =[]): #In order to perform "A Distributed Algorithm for random.seed(2**seedy) #Spanning Trees " by R. G. GALLAGER we need edges = [] #to give the edges weights that are equal to the for friend in neighbors: #communication delay between two processes timey = time.clock() #In order to avoid complications I added a little tiny bit my_first_message = message("", name, "first", "", timey) #of random noise (because random.random() \in (0,1)) friend.ssssend(0,my_first_message) #to avoid having two edges with the same weights, new_edge = [time,friend] #further we pick the larger of the two delays or else edges.append(new_edge) #we would have to implement a directed edge for edge in edges: #algorithm (which is easy but tedious) friends_firstmessage = edge[1].rrrrecv(0) edge[1].ssssend(0,friends_firstmessage) edge.append(friends_firstmessage.fromy) for edge in edges: my_first_message_returns = edge[1].rrrrecv(0) timey = time.clock() #I had to force the noise to have an exponential effect or timey = 2**( random.random()*(timey- my_first_message_returns.time))#else there is a small chance that edge[0] = timey #two edges have the same weight creating errors my_second_message = message("", name, "second", "", timey) edge[1].ssssend(0,my_second_message) for edge in edges: friends_second_message = edge[1].rrrrecv(0) if friends_second_message.time > edge[0]: #We take the larger of the two comunication delays edge[0] = friends_second_message.time #as the weight of the edge return edges
def ecome_to_life(self, mbox, life_of_universe, thermobox, heaterbox, envirotomotdet, lit_bubtoenviro, clockboxes, berkeley_or_lamport): if berkeley_or_lamport == "berkeley": neighbors = create_edges("enviro",6,clockboxes) parent, children, status = find_MST("enviro", neighbors) self.time=berkeley_clock_synch("enviro", self.offset, parent, children, status) mbox.wait_on_mail("enviro") time_until_we_all_die = 0 while time_until_we_all_die < life_of_universe: self.temperature_change(time_until_we_all_die) temp = message("thermo","enviro", "", self.temperature, thermobox.timestamp(self.offset)) thermobox.deliver_mail(self.offset,temp) x = heaterbox.wait_on_mail(self.offset) if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = heaterbox.timestamp(self.offset) #recieves a new message it compares it's own clock time to that of the if x.time > current_time : #timestamp in the message; if the time in the timestamp is larger than the self.offset = x.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and if x.data == "on": #it must add the difference between (plus 1) to its current offset self.is_heater_on = "yes" else: self.is_heater_on = "no" time_until_we_all_die = time_until_we_all_die + 1 self.intruder_change(time_until_we_all_die) isthereintruder = message("mot_det","enviro", "", self.intruder, envirotomotdet.timestamp(self.offset)) envirotomotdet.deliver_mail(self.offset,isthereintruder) x = lit_bubtoenviro.wait_on_mail(self.offset) if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = lit_bubtoenviro.timestamp(self.offset) #recieves a new message it compares it's own clock time to that of the if x.time > current_time : #timestamp in the message; if the time in the timestamp is larger than the self.offset = x.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and if x.data == "on": #it must add the difference between (plus 1) to its current offset self.is_light_on = "yes" else: self.is_light_on = "no" if berkeley_or_lamport == "berkeley": self.time=berkeley_clock_synch("enviro", self.offset, parent, children, status)
def should_i_alert_heater(self, temp, backbox): oldbelief = self.alertheater if temp < 1: #a simple function that computes whether self.alertheater = "on" #or not it is cold. if temp > 0: self.alertheater = "off" if oldbelief != self.alertheater: newstatus = message("backend", "gate", "heater_change", self.alertheater, backbox.timestamp(self.offset)) backbox.deliver_mail(self.offset, newstatus) else: oldstatus = message("backend", "gate", "no_change", "", backbox.timestamp(self.offset)) backbox.deliver_mail(self.offset, oldstatus)
def register_device(self, rbox, registrationform): #box and appends the data to its devicedata = registrationform.data #registry. the wrongid is a timestamp used correctidnum = len( self.registry) #by the device to temporaily identify itself self.registry.append( devicedata) #in the registration box until it is given a wrongid = registrationform.fromy #"correctid" which it then stores in update_addressbook() correctid = message(wrongid, "gate", "correctid", correctidnum, rbox.timestamp(self.offset)) rbox.deliver_mail(correctid) self.update_addressbook(devicedata, correctidnum)
def register_self( self, mbox ): #creating a temporary "wrongid" using a timestamp and filling out wrongid = mbox.timestamp( self.offset ) #a registration form, it then listens in for the gateway to send a self.idnum = wrongid #message addressed to the "wrongid", which itself contains the "correctid" registrationform = message("gate", wrongid, "register", [self.state, self.typer, self.name], mbox.timestamp(self.offset)) mbox.deliver_mail(registrationform) self.idnum = mbox.wait_on_mail(wrongid).data
def query_state(self, idnum, pipeboxes, life, death, backbox, berkeley_or_lamport): hola = message(idnum, "gate", "query", "", pipeboxes[idnum].timestamp(self.offset)) pipeboxes[idnum].deliver_mail(self.offset, hola) if life + 1 < death: #sometimes there is a deadlock issue x = pipeboxes[idnum].wait_on_query( self.offset, "gate") #on the last iteration of the if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = pipeboxes[idnum].timestamp( self.offset ) #recieves a new message it compares it's own clock time to that of the if x.time > current_time: #timestamp in the message; if the time in the timestamp is larger than the self.offset = x.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and self.should_i_alert_heater( x.data, backbox ) #while loop and therefore #it must add the difference between (plus 1) to its current offset newstatus = message("backend", "gate", "temp_change", x.data, backbox.timestamp(self.offset)) backbox.deliver_mail( self.offset, newstatus) #the gateway ignores the final messsage
def ucome_to_life(self, mbox, life_of_universe, usertogate, usertodoor, clockboxes, berkeley_or_lamport): if berkeley_or_lamport == "berkeley": neighbors = create_edges("user", 4, clockboxes) parent, children, status = find_MST("user", neighbors) self.time = berkeley_clock_synch("user", self.offset, parent, children, status) mbox.wait_on_mail("user") time_until_we_all_die = 0 self.name = "home" while time_until_we_all_die < life_of_universe: x = usertogate.wait_on_query(self.offset, "user") if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = usertogate.timestamp( self.offset ) #recieves a new message it compares it's own clock time to that of the if x.time > current_time: #timestamp in the message; if the time in the timestamp is larger than the self.offset = x.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and time_until_we_all_die = time_until_we_all_die + 1 #it must add the difference between (plus 1) to its current offset if x.data == "yes" and self.name == "away": print( " A L EEEEEEEEEEE RRRRRRRR TTTTTTTTTTTTT" ) print( " A A L E R R T " ) print( " A A L E R R T " ) print( " AAAAAAA L EEEEEEEEEEE R RRRRRR T " ) print( " A A L E R R T " ) print( " A A L E R R T " ) print( "A A LLLLLLLLLLL EEEEEEEEEEE R R T " ) else: pass prevstate = self.name home_or_not = input('') if home_or_not == "away": self.name = "away" elif home_or_not == "home": self.name = "home" report = message("gate", "user", "", self.name, usertogate.timestamp(self.offset)) usertogate.deliver_mail(self.offset, report) if self.name != prevstate: door = message("door", "user", "statechange", self.name, usertodoor.timestamp(self.offset)) usertodoor.deliver_mail(self.offset, door) else: door = message("door", "user", "nochange", "", usertodoor.timestamp(self.offset)) usertodoor.deliver_mail(self.offset, door) if berkeley_or_lamport == "berkeley": self.time = berkeley_clock_synch("user", self.offset, parent, children, status)
def gcome_to_life(self, rbox, life_of_universe, num_of_devices, pipeboxes, usertogate, gatetobackend, clockboxes, berkeley_or_lamport): if berkeley_or_lamport == "berkeley": neighbors = create_edges("gate", 2, clockboxes) parent, children, status = find_MST("gate", neighbors) self.time = berkeley_clock_synch("gate", self.offset, parent, children, status) self.activate_devices(rbox, num_of_devices) activate_enviroment = message("enviro", "gate", "activate", "", rbox.timestamp(self.offset)) rbox.deliver_mail(activate_enviroment) activate_user_interface = message("user", "gate", "activate", "", rbox.timestamp(self.offset)) rbox.deliver_mail(activate_user_interface) activate_backend = message("backend", "gate", "activate", self.registry, rbox.timestamp(self.offset)) rbox.deliver_mail(activate_backend) time_until_we_all_die = 0 oldmotdetdata = "no" while time_until_we_all_die < life_of_universe: time_until_we_all_die = time_until_we_all_die + 1 self.change_state(self.heateridnum, self.alertheater, pipeboxes) self.query_state(self.thermoidnum, pipeboxes, time_until_we_all_die, life_of_universe, gatetobackend, berkeley_or_lamport) isthere_intruder = pipeboxes[self.mot_detidnum].wait_on_query( self.offset, "gate") if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = pipeboxes[self.mot_detidnum].timestamp( self.offset ) #recieves a new message it compares it's own clock time to that of the if isthere_intruder.time > current_time: #timestamp in the message; if the time in the timestamp is larger than the self.offset = isthere_intruder.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and oldbulbstatus = self.should_i_turn_on_bulb #it must add the difference between (plus 1) to its current offset if oldmotdetdata != isthere_intruder.data: newmotdetbstatus = message( "backend", "gate", "motion_change", isthere_intruder.data, gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, newmotdetbstatus) else: oldstatus = message("backend", "gate", "no_change", "", gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, oldstatus) oldmotdetdata = isthere_intruder.data if self.mode == "home": if isthere_intruder.data == "yes": self.should_i_turn_on_bulb = "on" self.time_since_last_intruder = 0 else: self.time_since_last_intruder = self.time_since_last_intruder + 1 if self.time_since_last_intruder == 5: self.should_i_turn_on_bulb = "off" hola = message("user", "gate", "", "", usertogate.timestamp(self.offset)) usertogate.deliver_mail(self.offset, hola) elif self.mode == "away": self.should_i_turn_on_bulb = "off" intruder_alert = message("user", "gate", "", isthere_intruder.data, usertogate.timestamp(self.offset)) usertogate.deliver_mail(self.offset, intruder_alert) self.change_state(self.lit_bubidnum, self.should_i_turn_on_bulb, pipeboxes) if oldbulbstatus != self.should_i_turn_on_bulb: newbulbstatus = message("backend", "gate", "bulb_change", self.should_i_turn_on_bulb, gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, newbulbstatus) else: oldstatus = message("backend", "gate", "no_change", "", gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, oldstatus) userstatus = usertogate.wait_on_query(self.offset, "gate") if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = usertogate.timestamp( self.offset ) #recieves a new message it compares it's own clock time to that of the if userstatus.time > current_time: #timestamp in the message; if the time in the timestamp is larger than the self.offset = userstatus.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and oldpresencestatus = self.mode #it must add the difference between (plus 1) to its current offset if userstatus.data == "home": self.mode = "home" elif userstatus.data == "away": self.mode = "away" if oldpresencestatus != self.mode: newpresencestatus = message( "backend", "gate", "presence_change", self.mode, gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, newpresencestatus) else: oldstatus = message("backend", "gate", "no_change", "", gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, oldstatus) doorstatus = pipeboxes[self.door_detidnum].wait_on_query( self.offset, "gate") if berkeley_or_lamport == "lamport": #This performs the Lamport logical clocks algorithm: everytime the process current_time = pipeboxes[self.door_detidnum].timestamp( self.offset ) #recieves a new message it compares it's own clock time to that of the if doorstatus.time > current_time: #timestamp in the message; if the time in the timestamp is larger than the self.offset = doorstatus.time - current_time + 1 #time in its own logical clock then it knows that it is a contradicton and if doorstatus.data == "statechange": #it must add the difference between (plus 1) to its current offset newdoorstatus = message("backend", "gate", "door_change", self.mode, gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, newdoorstatus) else: oldstatus = message("backend", "gate", "no_change", "", gatetobackend.timestamp(self.offset)) gatetobackend.deliver_mail(self.offset, oldstatus) if berkeley_or_lamport == "berkeley": self.time = berkeley_clock_synch("gate", self.offset, parent, children, status)
def change_state(self, idnum, state, pipeboxes): ff = message(idnum, "gate", "change", state, pipeboxes[idnum].timestamp(self.offset)) pipeboxes[idnum].deliver_mail(self.offset, ff)
def find_MST(name, edges = []): original_name = name #Find_MST employs the famous algorithm from "A Distributed Algorithm for my_rank = 0 #Spanning Trees " by R. G. GALLAGER to find the minimum spaaning tree miny = find_min(edges) #for the network and while simaltanously electing a leader. status = "leader" #The name data type keeps the name of the village or city of the node parent = "" #miny is the current best minimum edge, status is whether the node is children = [] #currently a leader or follower, parent is the node's parent (if any) q = 1 #and children is the nodes children (if any) love_letter = message(["to",miny[2],"from",original_name, "time",q], name, "i_choose_you", my_rank, time.clock()) miny[1].send(0,love_letter) #the algorithm begins with every node picking their min edge and wating to be picked in return mail = miny[1].recv(0,) if mail.data == my_rank: #if they both agree that they if mail.fromy < name: #are each others minedge then children.append(miny) #a friendly merge occurs my_rank = my_rank+1 #we compare names to break potential elif mail.fromy > name: #ties in leader elections parent = miny my_rank = mail.data+1 #ties are broken with names name = mail.fromy status = "follower" elif mail.data > my_rank: #if the other city/village has a higher rank then parent = miny #the city is absorbed and it changes its name my_rank = mail.data #and rank to the other cities name and rank name = mail.fromy status = "follower" if parent != "": #the edge list must be updating by deleting edges for edge in edges: #that have become children or parents if parent == edge: edges.remove(edge) if len(children) != 0: for edge in edges: if children[0] == edge: edges.remove(edge) finished_children = [] #this keeps track of the children that are finished and is #returned by find_MST() print("NEW NODE AWOKEN!!!",status,"names is ",original_name,"city is ",name," parent is ",parent,"children are",children,"edges are ",edges) while len(edges)!=0 or len(children)!=0: q=q+1 if status == "follower": orders = parent[1].recv(0,) #a follower node awaits instructions from its parent my_rank = orders.data #node and constantly updates its name and rank to name = orders.fromy #that of the city it is currently part of if orders.command == "search": miny = find_min(edges) #the search message begins a sequence of questions and answers did_i_find_min = "yes" #between a parent node and a child node. Every node "searches" for its did_i_find_cycle = "no" #min by looking through its edges and asking each of their children for j=0 #their min. did_i_find_min is equal to yes if the min is an edge while j < len(children): #and is equal to no if one of the edges is a min. did_i_find_cycle indicates child = children[j] #whether a cycle was found j=j+1 if did_i_find_cycle == "no": child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "search", my_rank, time.clock())) mail = child[1].recv(0,) #In this step a node looks through if mail.command == "my_min_is": #its children and checks if any if mail.data < miny[0]: #of them found a better edge if did_i_find_min == "yes": #if NEW MIN then we must did_i_find_min = "no" #update any old information and else: #inform the old min that the are not a min miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) oldminy = miny miny = [mail.data, child[1],child[2]] elif mail.data == miny[0]: #because all edges have been forced to have different did_i_find_cycle = "yes" #weights this boolean implies NEW CYCLE has been found. if did_i_find_min == "no": #we must inform any children of the cycle miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) miny = oldminy #we must return to the old min if a cycle was found else: child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) for edge in edges: #if one of the min was actually found by this node if miny == edge: #then this node must delete this edge edges.remove(edge) miny = find_min(edges) for edge in edges: #this returns the state of the found min to the if miny == edge: #previous correct state before a cycle was found did_i_find_min = "yes" if len(miny) == 1: did_i_find_min = "yes" else: #we must inform any children if they are not min child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) if mail.command == "i_am_finished": #one of the children has finished_children.append(child) #run out of territory to explore children.remove(child) #we place them in the finished list j=j-1 if mail.command == "cycle": #if one of the children found a cycle we alert_min = "yes" #must tell the parent because every phase must be for edge in edges: #synchronized so as to not create any if miny == edge: #the leader will later restart the next phase alert_min == "no" #with a search command did_i_find_cycle = "yes" if len(miny) != 1: if alert_min == "yes": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) if did_i_find_cycle == "yes": #The child alerts the parent of any cycles parent[1].send(0,message(["to",parent[2],"from",original_name, "time",q], name, "cycle", miny[0], time.clock())) elif len(edges)!=0 or len(children)!=0: parent[1].send(0,message(["to",parent[2],"from",original_name, "time",q], name, "my_min_is", miny[0], time.clock())) response = parent[1].recv(0,) #The chld now waits to update any information my_rank = response.data #about the city rank and/or name and also whats name = response.fromy #its next command is if response.command == "you_are_min": if did_i_find_min == "yes": #If the parent alerts you that you are min miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "i_choose_you", my_rank, time.clock())) #you try to merge with the city/or village by sending it a elif did_i_find_min == "no": #and waiting for a response miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_min", my_rank, time.clock())) mail = miny[1].recv(0,) #when the other village/city responds parent[1].send(0,mail) #to the request to merge you then send the response = parent[1].recv(0,) #up to your parent(leader) who will my_rank = response.data #then inform you of the next move name = response.fromy if response.command == "we_lost": #if the neighboring city is stronger children.append(parent) #then the current city of this node was if did_i_find_min == "yes": #absorbed by a larger city and therefore parent = miny #the order of communication is now reversed for edge in edges: #and therefore the parent becomes the child if parent == edge: edges.remove(edge) #the new node becomes the new parent of this node elif did_i_find_min == "no": #and this node must update other information miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_lost", my_rank, time.clock())) for child in children: #such as deleting old nodes if miny[2] == child[2]: parent = child children.remove(child) elif response.command == "we_won": #if the neighboring city is stronger if did_i_find_min == "yes": #then node appends the new city as one children.append(miny) #of its children and updates its edge list for edge in edges: if miny == edge: edges.remove(edge) elif did_i_find_min == "no": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_won", my_rank, time.clock())) elif response.command == "cycle": #if the parent reports that the new min that this node if did_i_find_min == "yes": #found is a cycle then it must be deleted from the list for edge in edges: #or if did_i_find_min == "no" then this node will send the if miny == edge: #message down to its children and eventually by recursion a edges.remove(edge) #solution will be found elif did_i_find_min == "no": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) elif response.command == "you_are_not_min": #if the child is not a min it then goes back to the top if did_i_find_min == "no": #of the loop and awaits a search command from its parent miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) #the leader routine starts here. the leader commences all phases in a city by issuing a search command. #the find min process is similar to a follower but eventually the leader is the only node allowed to make "decisions" if status == "leader": miny = find_min(edges) #the search message begins a sequence of questions and answers did_i_find_min = "yes" #between a parent node and a child node. Every node "searches" for its did_i_find_cycle = "no" #min by looking through its edges and asking each of their children for #their min. did_i_find_min is equal to yes if the min is an edge j=0 #and is equal to no if one of the edges is a min. did_i_find_cycle indicates while j < len(children): #whether a cycle was found child = children[j] j=j+1 if did_i_find_cycle == "no": child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "search", my_rank, time.clock())) mail = child[1].recv(0,) #In this step a node looks through #its children and checks if any if mail.command == "my_min_is": #of them found a better edge if mail.data < miny[0]: #if NEW MIN then we must if did_i_find_min == "yes": #update any old information and did_i_find_min = "no" #inform the old min that the are not a min else: miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) oldminy = miny miny = [mail.data, child[1],child[2]] elif mail.data == miny[0]: #because all edges have been forced to have different did_i_find_cycle = "yes" #weights this boolean implies NEW CYCLE has been found. if did_i_find_min == "no": #we must inform any children of the cycle miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) miny = oldminy #we must return to the old min if a cycle was found else: child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "cycle", my_rank, time.clock())) for edge in edges: #if one of the min was actually found by this node if miny == edge: #then this node must delete this edge edges.remove(edge) miny = find_min(edges) for edge in edges: if miny == edge: #this returns the state of the found min to the did_i_find_min = "yes" #previous correct state before a cycle was found if len(miny) == 1: did_i_find_min = "yes" else: child[1].send(0,message(["to",child[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) if mail.command == "i_am_finished": #one of the children has finished_children.append(child) #run out of territory to explore children.remove(child) #we place them in the finished list j=j-1 if mail.command == "cycle": #if one of the children found a cycle we alert_min = "yes" #must tell the parent because every phase must be for edge in edges: #synchronized so as to not create any if miny == edge: #the leader will later restart the next phase alert_min == "no" #with a search command did_i_find_cycle = "yes" if len(miny) != 1: if alert_min == "yes": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_not_min", my_rank, time.clock())) if len(miny) == 1: #This checks if there is a miny. As stated previously find_min() pass #returns a singleton if there is no min elif did_i_find_cycle == "yes": #If did_I_find cycle is true then we must restart a new phase pass elif len(edges)!=0 or len(children)!=0: #If the leader node found the min then he/she will broadcast the desire to if did_i_find_min == "yes": #merge to the adjacent node and await a response miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "i_choose_you", my_rank, time.clock())) elif did_i_find_min == "no": #If the leader did not find the min then he broadcasts to the min edge to merge and that broadcast miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "you_are_min", my_rank, time.clock())) #will be recursively sent down the city-tree until it arrives at the desired node mail = miny[1].recv(0,) #The leader then awaits a response from a min edge and then makes a decision based on the response if mail.data == my_rank: #If the rank of the city/village on the adjacent edge is equal then #a merge occurs if mail.fromy < name: if did_i_find_min == "yes": #A tie is broken by lexicographic order of city names children.append(miny) my_rank = my_rank+1 #If a merger of two equal sized cities occurs then they must for edge in edges: #increase the rank by one if edge == miny: edges.remove(edge) #Then update the list elif did_i_find_min == "no": #If the leader did not find the min then he sends a message to the relevant nodes miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_won", my_rank, time.clock())) #letting them know what action to take elif mail.fromy > name: my_rank = mail.data+1 name = mail.fromy #if the leader loses the tie he then makes the min status = "follower" #he takes the name of the min's city and then he ... if did_i_find_min == "yes": #...he then makes the min his parent if he found min parent = miny # and he updates his edge list or ... for edge in edges: if edge == miny: edges.remove(edge) #... if he did not find the min then he procedes he makes the min child his parent and if did_i_find_min == "no": #sends a "we lost" broadcest to his child which propagates downward to the relevant nodes miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_lost", my_rank, time.clock())) for child in children: if miny[2] == child[2]: parent = child children.remove(child) elif mail.data > my_rank: my_rank = mail.data name = mail.fromy status = "follower" if did_i_find_min == "yes": #Similalry if a city with a larger rank is on parent = miny #the other side of the communication then the for edge in edges: #leader makes the min his parent and broadcasts if edge == miny: #the "we lost" message down to all the relevant nodes edges.remove(edge) #but the rank is not increased this time around if did_i_find_min == "no": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_lost", my_rank, time.clock())) for child in children: if miny[2] == child[2]: parent = child children.remove(child) elif mail.data < my_rank: #If the rank is smaller then we absorb the if did_i_find_min == "yes": #smaller city and very little updates need to children.append(miny) #made. The rank stays the same and we just delete for edge in edges: #the edge and turn into a chlid edge if edge == miny: edges.remove(edge) elif did_i_find_min == "no": miny[1].send(0,message(["to",miny[2],"from",original_name, "time",q], name, "we_won", my_rank, time.clock())) #finally if a follower finishes he alerts his parent and when everyone is finsihed they return with the if status == "follower": #updated child paretn structure of minimum spanning tree with a unique leader which has a small amount of communication overhead letter_of_resignation = message(["to",parent[2],"from",original_name, "time",q], name, "i_am_finished", my_rank, time.clock()) parent[1].send(0,letter_of_resignation) print("I AM FINISHED",parent, finished_children, status) return parent, finished_children, status
def berkeley_clock_synch(name, offset, parent, children, status): if status == "leader": #This is a modified Berkeley algorithm which exploits the tree communication_delays = [] #tree structure from leaderelect.py in order to reduce the times_and_weight = [] #complexity of the algorithm from O(n) to O(blog_b(n)+wlog_b(n)) for child in children: #the proof of this is given in the write up send_time = my_time(offset) child[1].send(offset,message(child[2], name, "lets_see_how_fast_you_are", "", my_time(offset))) child[1].recv(0,) child_delay = my_time(offset)-send_time communication_delays.append(child_delay) #the algorithm begins by the checking the current communication for child in children: #latency bewteen a parent and his children. As proven in the child[1].send(offset,message(child[2], name, "give_me_your_time", "", my_time(offset))) child_time_and_weight = child[1].recv(0,).data #write up the parent only needs to know the latency between him and times_and_weight.append(child_time_and_weight) #his direct children and only keep a count of the number of ancestors average_time = 0 total_weight = 1 for times in times_and_weight: average_time = average_time + (times[0]*times[1]) #he then computes a weighted average and sends the average along with total_weight = total_weight + times[1] #the appropriate offset to his children who then recursively do the same old_time = my_time(offset) average_time = (average_time+old_time)/total_weight for j,child in enumerate(children): child[1].send(offset,message(child[2], name, "your_time_is", average_time + communication_delays[j], my_time(offset))) return old_time - average_time + offset if status == "follower": orders = parent[1].recv(0,) #the followers algorithm is essentially the same as the parents algorithm with the exception if orders.command == "lets_see_how_fast_you_are": #that the child must clear the pipe of any old messages in order to avoid parent[1].send(offset,message(parent[2], name, "this_is_how_fast_i_am", "", my_time(offset))) #undefined behavior elif orders.command == "search": orders = parent[1].recv(0,) parent[1].send(offset,message(parent[2], name, "this_is_how_fast_i_am", "", my_time(offset))) communication_delays = [] times_and_weight = [] for child in children: #the algorithm begins by the checking the current communication send_time = my_time(offset) #latency bewteen a parent and his children. As proven in the child[1].send(offset,message(child[2], name, "lets_see_how_fast_you_are", "", my_time(offset))) child[1].recv(0,) #write up the parent only needs to know the latency between him and child_delay = my_time(offset)-send_time #his direct children and only keep a count of the number of ancestors communication_delays.append(child_delay) for child in children: child[1].send(offset,message(child[2], name, "give_me_your_time", "", my_time(offset))) child_time_and_weight = child[1].recv(0,).data times_and_weight.append(child_time_and_weight) average_time = 0 total_weight = 1 for times in times_and_weight: average_time = average_time + (times[0]*times[1]) #he then computes a weighted average and sends the average along with total_weight = total_weight + times[1] #the appropriate offset to his children who then recursively do the same old_time = my_time(offset) average_time = (average_time + old_time)/total_weight orders = parent[1].recv(0,) if orders.command == "give_me_your_time": parent[1].send(offset,message(parent[2], name, "my_time_is", [average_time,total_weight], my_time(offset))) orders = parent[1].recv(0,) if orders.command == "your_time_is": new_offset=orders.data-old_time for j,child in enumerate(children): child[1].send(offset,message(child[2], name, "your_time_is", orders.data + new_offset + communication_delays[j], my_time(offset))) return new_offset + offset
def query_response(self, pipeboxes): report = message("gate", self.idnum, "report", self.state, pipeboxes[self.idnum].timestamp(self.offset)) pipeboxes[self.idnum].deliver_mail(self.offset, report)