Exemplo n.º 1
0
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
Exemplo n.º 2
0
 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)
Exemplo n.º 3
0
 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)
Exemplo n.º 4
0
 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)
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
 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
Exemplo n.º 7
0
 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)
Exemplo n.º 8
0
 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)
Exemplo n.º 9
0
 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)
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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
Exemplo n.º 12
0
 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)