예제 #1
0
class Acceptor(object):
    def __init__(self, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.uid = uid

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def reset(self):
        # self.messenger = Messenger(self)
        # self.server = Server(self, port)
        self.server.queue = queue.Queue()

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def recv_message(self, msg):
        if msg.type == Message.MSG_PREPARE:
            self.recv_prepare(msg.from_uid,
                              msg.data)  # the data is simply one tuple
        elif msg.type == Message.MSG_ACCEPT:
            self.recv_accept_request(msg.from_uid, msg.data[0], msg.data[1])

    def recv_prepare(self, from_uid, proposal_id):
        """
        Called when a Prepare message is received from a Proposer
        """
        if proposal_id == self.promised_id:
            # Duplicate prepare message
            self.messenger.send_promise(from_uid, proposal_id,
                                        self.accepted_id, self.accepted_value)

        elif proposal_id > self.promised_id:
            self.promised_id = proposal_id
            self.messenger.send_promise(from_uid, proposal_id,
                                        self.accepted_id, self.accepted_value)

    def recv_accept_request(self, from_uid, proposal_id, value):
        """
        Called when an Accept! message is received from a Proposer
        """
        if proposal_id >= self.promised_id:
            self.promised_id = proposal_id
            self.accepted_id = proposal_id
            self.accepted_value = value
            self.messenger.send_accepted(proposal_id, self.accepted_value)
예제 #2
0
class DandelionApp:
    def __init__(self, config_file=None):
        self._config_manager = ConfigurationManager(config_file)

    def start_server(self):
        self._server = Server(
            self._config_manager.local_address,
            self._config_manager.local_port,
            self._config_manager.server,  # info_dict
            self._config_manager.content_db,
        )
        self._server.start()

    def start_content_synchronizer(self):
        self._synchronizer = Synchronizer(
            self._config_manager.local_address,
            self._config_manager.local_port,
            self._config_manager.type,
            self._config_manager.content_db,
        )
        self._synchronizer.start()

    def run_ui(self):

        self._ui = UI(
            self._config_manager.ui, self._config_manager.content_db, self._server, self._synchronizer  # dict
        )
        self._ui.run()

    def exit(self):
        self._synchronizer.stop()
        self._server.stop()
예제 #3
0
    def test_play_match(self):
        server = Server()
        server.start(False)

        client1 = Client('localhost', 8081)
        client2 = Client('localhost', 8081)

        client1_moves = [(1, 1), (2, 2), (3, 3)]
        client2_moves = [(3, 1), (3, 2)]

        client1.on_move_required = lambda ct: (client1_moves
                                               if ct else client2_moves).pop(0)
        client1.on_game_over = lambda winner: self.assertTrue(winner)

        client2.on_move_required = lambda ct: (client1_moves
                                               if ct else client2_moves).pop(0)
        client2.on_game_over = lambda winner: self.assertTrue(winner)

        client1.start(False)
        client2.start(False)

        client1.wait()
        client2.wait()

        server.stop()
예제 #4
0
class DandelionApp:

    def __init__(self, config_file=None):
        self._config_manager = ConfigurationManager(config_file)
    
    def start_server(self): 
        self._server = Server(self._config_manager.local_address, 
                              self._config_manager.local_port, 
                              self._config_manager.server,  #info_dict
                              self._config_manager.content_db) 
        self._server.start()
    
    def start_content_synchronizer(self): 
        self._synchronizer = Synchronizer(self._config_manager.local_address,
                                          self._config_manager.local_port,
                                          self._config_manager.type,
                                          self._config_manager.content_db)
        self._synchronizer.start()
    
    def run_ui(self): 
        
        self._ui = UI(self._config_manager.ui,  #dict 
                      self._config_manager.content_db,
                      self._server, 
                      self._synchronizer)
        self._ui.run()
    
    def exit(self):
        self._synchronizer.stop()
        self._server.stop()
예제 #5
0
class Acceptor(object):
    def __init__(self, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.uid = uid

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def reset(self):
        # self.messenger = Messenger(self)
        # self.server = Server(self, port)
        self.server.queue = queue.Queue()

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def recv_message(self, msg):
        if msg.type == Message.MSG_PREPARE:
            self.recv_prepare(msg.from_uid, msg.data)  # the data is simply one tuple
        elif msg.type == Message.MSG_ACCEPT:
            self.recv_accept_request(msg.from_uid, msg.data[0], msg.data[1])

    def recv_prepare(self, from_uid, proposal_id):
        """
        Called when a Prepare message is received from a Proposer
        """
        if proposal_id == self.promised_id:
            # Duplicate prepare message
            self.messenger.send_promise(from_uid, proposal_id, self.accepted_id, self.accepted_value)

        elif proposal_id > self.promised_id:
            self.promised_id = proposal_id
            self.messenger.send_promise(from_uid, proposal_id, self.accepted_id, self.accepted_value)

    def recv_accept_request(self, from_uid, proposal_id, value):
        """
        Called when an Accept! message is received from a Proposer
        """
        if proposal_id >= self.promised_id:
            self.promised_id = proposal_id
            self.accepted_id = proposal_id
            self.accepted_value = value
            self.messenger.send_accepted(proposal_id, self.accepted_value)
예제 #6
0
class WebchatManager(QObject):
    WEBCHAT_SERVER_PORT = 22334

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.server = Server(self.WEBCHAT_SERVER_PORT)
        self.dispatcher = WebchatDispatcher(self.server)
        self.server.setDispatcher(self.dispatcher)

    def start(self):
        self.server.start()
예제 #7
0
class WebchatManager(QObject):
    WEBCHAT_SERVER_PORT = 22334

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.server = Server(self.WEBCHAT_SERVER_PORT)
        self.dispatcher = WebchatDispatcher(self.server)
        self.server.setDispatcher(self.dispatcher)

    def start(self):
        self.server.start()
예제 #8
0
class ExternalManager(QObject):
    EXTERNAL_SERVER_PORT = 22333

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.server = Server(self.EXTERNAL_SERVER_PORT)
        self.dispatcher = ExternalDispatcher(self.server)
        self.server.setDispatcher(self.dispatcher)

    def start(self):
        self.server.start()
예제 #9
0
class ExternalManager(QObject):
    EXTERNAL_SERVER_PORT = 22333

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.server = Server(self.EXTERNAL_SERVER_PORT)
        self.dispatcher = ExternalDispatcher(self.server)
        self.server.setDispatcher(self.dispatcher)

    def start(self):
        self.server.start()
예제 #10
0
class Proposer(object):

    def __init__(self, owner, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.owner = owner
        self.uid = uid
        self.proposer_uid = uid
        self.quorum_size = 3

        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        self.next_proposal_number = 1
        self.promises_rcvd = None

    def reset(self):
        self.server.queue = queue.Queue()
        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        # self.next_proposal_number = 1
        self.promises_rcvd = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def set_proposal(self, value):
        """
        Sets the proposal value for this node iff this node is not already aware of
        another proposal having already been accepted.
        """
        if self.proposed_value is None:
            self.proposed_value = value

    def propose(self):
        """
        Send the proposal (uid, proposed_value) over all acceptors
        """
        self.owner.log.append(LogEntry(self.uid, self.proposed_value, False))
        self.messenger.send_proposal(self.uid, self.proposed_value)

    def recv_message(self, msg):
        print('illegal!')
예제 #11
0
class Acceptor(object):
    def __init__(self, owner, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.owner = owner
        self.uid = uid

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def reset(self):
        # self.messenger = Messenger(self)
        # self.server = Server(self, port)
        self.server.queue = queue.Queue()

        self.promised_id = ProposalID(-1, -1)
        self.accepted_id = ProposalID(-1, -1)
        self.accepted_value = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def recv_message(self, msg):
        if msg.type == Message.MSG_ACCEPT:
            self.recv_accept_request(msg.from_uid, msg.data[0], msg.data[1])

    def recv_accept_request(self, from_uid, proposal_uid, value):  # from_uid is same as proposal uid
        """
        Called when an Accept! message is received from a Proposer
        """

        # write log immediately
        self.owner.log.append(LogEntry(proposal_uid, value, False))

        # broadcast for voting
        self.messenger.send_accepted(proposal_uid, value)
예제 #12
0
 def run(self):
     server = Server(self.port)
     server.start()
     while not self.stopped:
         requests = server.get_requests()
         for r in requests:
             nums = r.split(',')
             self.connected = True
             if len(nums) == 2:
                 self.connected = True
                 self.depth_queue.append(int(nums[0]))
                 self.angle = int(nums[1])
             response = "{},{},{},{},{}\n".format(
                 self.convert(-self.m_front_left),
                 self.convert(-self.m_front_right),
                 self.convert(-self.m_back_left),
                 self.convert(-self.m_back_right),
                 self.convert(self.m_tail))
             response = response.encode('utf-8')
             server.offer_data(r, response)
             break
     server.stop()
예제 #13
0
class GUI(tk.Frame):

    # Inherits from Tk.Frame
    def __init__(self, master, address, port, *args, **kwargs):
        # Pass the arguments to the superclass
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.master = master

        # Some GUI Configurations
        self.master.resizable(False, False)
        self.master.title("BergRat")
        self.master.geometry("650x650")

        # Create a TreeView and add som columns
        self.tree = ttk.Treeview(self)
        self.tree["columns"] = ("one", "two", "three", "four")

        self.tree.heading("#0", text="ID", anchor="w")
        self.tree.column("#0", stretch=tk.YES, width=100, anchor="w")

        self.tree.column("one", width=100)
        self.tree.heading("one", text="IP")

        self.tree.column("two", width=100)
        self.tree.heading("two", text="User")

        self.tree.column("three", width=100)
        self.tree.heading("three", text="Online")

        self.tree.column("four", width=100)
        self.tree.heading("four", text="Install Date")

        # Create Ba button to create a Backdoor
        self.button = tk.Button(self,
                                text="Create a Backdoor",
                                command=self.create_backdoor)

        # Pack all the objects
        self.tree.pack(fill="both", expand=True)
        self.button.pack()

        # Bind the double-click in a element from TreeView
        self.tree.bind("<Double-1>", lambda event: self.double_click_tree())

        # After all widgets being packed, the master is show
        self.master.deiconify()

        # Start the network class
        self.Network = Server(address, port)

        # Start a Get-Sessions Thread
        t_get_sessions = Thread(target=self.get_sessions)
        t_get_sessions.daemon = True
        t_get_sessions.start()

    def create_backdoor(self):
        """ Method used to call the Builder """
        Builder(self.master)

    def double_click_tree(self):
        """ Function used to call the remote shell """
        # Check what item is selected from TreeView
        try:
            item = self.tree.selection()[0]
        except IndexError:
            return

        # Get the Item UID
        uid = int(self.tree.item(item, "text"))

        # Starts the remote shell
        RemoteShell(self.Network, uid, self.master,
                    self.Network.Sessions[uid][2])

    def get_sessions(self):
        """ Function used to update the TreeView with the connected users """

        # Start the network
        self.Network.start()

        while True:
            # Creates a copy of Network.Sessions (To avoid bugs)
            for key in self.Network.Sessions.copy():
                if not self.Network.Sessions[key][5]:
                    # Add to TreeView
                    self.add_user(key, self.Network.Sessions[key][1],
                                  self.Network.Sessions[key][2],
                                  self.Network.Sessions[key][3],
                                  self.Network.Sessions[key][4])
                    self.Network.Sessions[key][5] = True

    def add_user(self, uid, ip, username, online, date):
        """ Method used to add things to TreeView """
        self.tree.insert("",
                         "end",
                         text=uid,
                         values=(ip, username, online, date))
예제 #14
0
class Learner(object):
    def __init__(self, owner, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.owner = owner
        self.uid = uid

        self.quorum_size = 3
        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def reset(self):
        self.server.queue = queue.Queue()

        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    @property
    def complete(self):
        return self.final_proposal_id is not None

    def recv_message(self, msg):
        if msg.type == Message.MSG_DECIDE:
            self.recv_accepted(msg.src, msg.data[0], msg.data[1])

    def recv_accepted(self, from_uid, proposal_id, accepted_value):
        """
        Called when an Accepted message is received from an acceptor
        """

        if self.final_value is not None:
            return  # already done

        if self.proposals is None:
            self.proposals = dict()
            self.acceptors = dict()

        last_proposal_number = self.acceptors.get(from_uid)

        if last_proposal_number is not None and not proposal_id > last_proposal_number:
            return  # Old message

        self.acceptors[from_uid] = proposal_id

        if last_proposal_number is not None:
            old_proposal = self.proposals[last_proposal_number]
            old_proposal[1] -= 1
            if old_proposal[1] == 0:
                del self.proposals[last_proposal_number]

        if not proposal_id in self.proposals:
            self.proposals[proposal_id] = [0, 0, accepted_value]

        t = self.proposals[proposal_id]

        assert accepted_value == t[2], 'Value mismatch for single proposal!'

        t[0] += 1
        t[1] += 1

        if t[0] == self.quorum_size:
            self.final_value = accepted_value
            self.final_proposal_id = proposal_id
            self.proposals = None
            self.acceptors = None

            self.messenger.on_resolution(proposal_id, accepted_value,
                                         self.owner.log)
예제 #15
0
class Node(threading.Thread):
    class Daemon(threading.Thread):
        def __init__(self, owner):
            threading.Thread.__init__(self)
            self.owner = owner
            #self.counter = time.time()

        def run(self):
            while True:
                if self.owner.in_propose_time_frame:
                    #if time.time() - self.counter > 2:
                    #    print('Daemon is alive!')
                    #    self.counter = time.time()

                    self.owner.in_propose_time_frame = False

                    if self.owner.last_decided_proposer_id == self.owner.uid or self.owner.next_post is None:
                        self.owner.next_post = self.owner.queue.get(True)
                        print('Propose next available value {}.'.format(
                            self.owner.next_post))
                        self.owner.proposer.set_proposal(self.owner.next_post)
                        self.owner.proposer.prepare()
                    elif self.owner.next_post is not None:
                        print('Propose old value {}'.format(
                            self.owner.next_post))
                        self.owner.proposer.set_proposal(self.owner.next_post)
                        self.owner.proposer.prepare()

    def __init__(self, uid, addr, port):
        threading.Thread.__init__(self)
        self.address = addr
        self.port = port
        self.server = Server(self, port, address=addr)
        self.queue = queue.Queue()

        self.abort = False

        self.uid = uid
        self.next_post = None

        # local log of the Node
        self.log = []

        self.proposer = Proposer(uid, addr, port + 1)
        self.acceptor = Acceptor(uid, addr, port + 2)
        self.learner = Learner(self, uid, addr, port + 3)

        self.stopped_proposal_id = None

        self.lock = threading.Lock()

        self.last_decided_proposer_id = None

        self.in_propose_time_frame = True

        self.daemon = Node.Daemon(self)

    def recv_message(self, msg):
        if msg.type == Message.MSG_STOP and msg.data[
                0] != self.stopped_proposal_id:

            # set local log
            accepted_log = msg.data[2]
            if len(accepted_log) > len(self.log):
                self.log = accepted_log

            if len(self.log) > 0:
                if self.log[-1] != msg.data[1]:
                    self.log.append(msg.data[1])
            else:
                self.log.append(msg.data[1])

            print('Log after this round: ', self.log)

            self.stopped_proposal_id = msg.data[0]
            self.proposer.reset()
            self.acceptor.reset()
            self.learner.reset()

            self.last_decided_proposer_id = msg.data[0].uid

            time.sleep(3)

            self.in_propose_time_frame = True

    def fail(self):
        self.proposer.fail()
        self.acceptor.fail()
        self.learner.fail()

        self.abort = True
        self.server.do_abort()

    def recover(self):
        self.server.recover()
        self.proposer.recover()
        self.acceptor.recover()
        self.learner.recover()

        self.abort = False

    def run(self):
        self.server.start()
        self.proposer.start()
        self.acceptor.start()
        self.learner.start()

        self.daemon.start()
예제 #16
0
class Learner(object):
    def __init__(self, owner, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.owner = owner
        self.uid = uid

        self.quorum_size = 3
        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def reset(self):
        self.server.queue = queue.Queue()

        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    @property
    def complete(self):
        return self.final_proposal_id is not None

    def recv_message(self, msg):
        if msg.type == Message.MSG_DECIDE:
            self.recv_accepted(msg.src, msg.data[0], msg.data[1])

    def recv_accepted(self, from_uid, proposal_id, accepted_value):
        """
        Called when an Accepted message is received from an acceptor
        """

        if self.final_value is not None:
            return  # already done

        if self.proposals is None:
            self.proposals = dict()
            self.acceptors = dict()

        last_proposal_number = self.acceptors.get(from_uid)

        if last_proposal_number is not None and not proposal_id > last_proposal_number:
            return  # Old message

        self.acceptors[from_uid] = proposal_id

        if last_proposal_number is not None:
            old_proposal = self.proposals[last_proposal_number]
            old_proposal[1] -= 1
            if old_proposal[1] == 0:
                del self.proposals[last_proposal_number]

        if not proposal_id in self.proposals:
            self.proposals[proposal_id] = [0, 0, accepted_value]

        t = self.proposals[proposal_id]

        assert accepted_value == t[2], 'Value mismatch for single proposal!'

        t[0] += 1
        t[1] += 1

        if t[0] == self.quorum_size:
            self.final_value = accepted_value
            self.final_proposal_id = proposal_id
            self.proposals = None
            self.acceptors = None

            self.messenger.on_resolution(proposal_id, accepted_value, self.owner.log)
예제 #17
0
class Node(threading.Thread):
    class Daemon(threading.Thread):
        def __init__(self, owner):
            threading.Thread.__init__(self)
            self.owner = owner
            #self.counter = time.time()

        def run(self):
            while True:
                if self.owner.in_propose_time_frame:
                    #if time.time() - self.counter > 2:
                    #    print('Daemon is alive!')
                    #    self.counter = time.time()

                    self.owner.in_propose_time_frame = False

                    if self.owner.last_decided_proposer_id == self.owner.uid or self.owner.next_post is None:
                        self.owner.next_post = self.owner.queue.get(True)
                        print('Propose next available value {}.'.format(self.owner.next_post))
                        self.owner.proposer.set_proposal(self.owner.next_post)
                        self.owner.proposer.prepare()
                    elif self.owner.next_post is not None:
                        print('Propose old value {}'.format(self.owner.next_post))
                        self.owner.proposer.set_proposal(self.owner.next_post)
                        self.owner.proposer.prepare()

    def __init__(self, uid, addr, port):
        threading.Thread.__init__(self)
        self.address = addr
        self.port = port
        self.server = Server(self, port, address=addr)
        self.queue = queue.Queue()

        self.abort = False

        self.uid = uid
        self.next_post = None

        # local log of the Node
        self.log = []

        self.proposer = Proposer(uid, addr, port + 1)
        self.acceptor = Acceptor(uid, addr, port + 2)
        self.learner = Learner(self, uid, addr, port + 3)

        self.stopped_proposal_id = None

        self.lock = threading.Lock()

        self.last_decided_proposer_id = None

        self.in_propose_time_frame = True

        self.daemon = Node.Daemon(self)

    def recv_message(self, msg):
        if msg.type == Message.MSG_STOP and msg.data[0] != self.stopped_proposal_id:

            # set local log
            accepted_log = msg.data[2]
            if len(accepted_log) > len(self.log):
                self.log = accepted_log

            if len(self.log) > 0:
                if self.log[-1] != msg.data[1]:
                    self.log.append(msg.data[1])
            else:
                self.log.append(msg.data[1])

            print('Log after this round: ', self.log)

            self.stopped_proposal_id = msg.data[0]
            self.proposer.reset()
            self.acceptor.reset()
            self.learner.reset()

            self.last_decided_proposer_id = msg.data[0].uid

            time.sleep(3)

            self.in_propose_time_frame = True

    def fail(self):
        self.proposer.fail()
        self.acceptor.fail()
        self.learner.fail()

        self.abort = True
        self.server.do_abort()

    def recover(self):
        self.server.recover()
        self.proposer.recover()
        self.acceptor.recover()
        self.learner.recover()

        self.abort = False

    def run(self):
        self.server.start()
        self.proposer.start()
        self.acceptor.start()
        self.learner.start()

        self.daemon.start()
예제 #18
0
class Proposer(object):

    def __init__(self, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.uid = uid
        self.proposer_uid = uid
        self.quorum_size = 3

        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        self.next_proposal_number = 1
        self.promises_rcvd = None

    def reset(self):
        self.server.queue = queue.Queue()
        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        # self.next_proposal_number = 1
        self.promises_rcvd = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def set_proposal(self, value):
        """
        Sets the proposal value for this node iff this node is not already aware of
        another proposal having already been accepted.
        """
        if self.proposed_value is None:
            self.proposed_value = value

    def prepare(self):
        """
        Sends a prepare request to all Acceptors as the first step in attempting to
        acquire leadership of the Paxos instance.
        """
        self.promises_rcvd = set()
        self.proposal_id = ProposalID(self.next_proposal_number, self.proposer_uid)

        self.next_proposal_number += 1

        self.messenger.send_prepare(self.proposal_id)

    def recv_message(self, msg):
        if msg.type == Message.MSG_PROMISE:
            self.recv_promise(msg.src, msg.data[0], msg.data[1], msg.data[2])

    def recv_promise(self, from_uid, proposal_id, prev_accepted_id, prev_accepted_value):
        """
        Called when a Promise message is received from an Acceptor
        """

        # Ignore the message if it's for an old proposal or we have already received
        # a response from this Acceptor
        if proposal_id != self.proposal_id or from_uid in self.promises_rcvd:
            return

        self.promises_rcvd.add(from_uid)

        if prev_accepted_id > self.last_accepted_id:
            self.last_accepted_id = prev_accepted_id
            # If the Acceptor has already accepted a value, we MUST set our proposal
            # to that value.
            if prev_accepted_value is not None:
                self.proposed_value = prev_accepted_value

        if len(self.promises_rcvd) == self.quorum_size:
            if self.proposed_value is not None:
                self.messenger.send_accept(self.proposal_id, self.proposed_value)
예제 #19
0
    help='Port to listen to'
)

parser.add_argument(
    '-v',
    '--verbose',
    action='store_true',
    help='Be verbose'
)

args = parser.parse_args()

logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)


server = Server(
    args.field_size,
    args.row_length,
    args.host,
    args.port
)


def signal_handler(sig, frame):
    server.stop()


signal.signal(signal.SIGINT, signal_handler)

server.start()
예제 #20
0
class Learner(object):
    class AsynchronousMessenger(threading.Thread):
        def __init__(self, owner, proposal_uid, value, log=None):
            threading.Thread.__init__(self)
            self.owner = owner
            self.proposal_uid = proposal_uid
            self.value = value
            self.log = log

        def run(self):
            time.sleep(3)
            self.owner.proposals = None
            self.owner.acceptors = None
            self.owner.messenger.on_resolution(self.proposal_uid, self.value, self.log)

    def __init__(self, owner, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.owner = owner
        self.uid = uid

        self.quorum_size = 3
        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def reset(self):
        self.server.queue = queue.Queue()

        self.proposals = None  # maps proposal_id => [accept_count, retain_count, value]
        self.acceptors = None  # maps from_uid => last_accepted_proposal_id
        self.final_value = None
        self.final_proposal_id = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    @property
    def complete(self):
        return self.final_proposal_id is not None

    def recv_message(self, msg):
        if msg.type == Message.MSG_DECIDE:
            self.recv_accepted(msg.src, msg.data[0], msg.data[1])

    def recv_accepted(self, from_uid, proposal_uid, accepted_value):
        """
        Called when an Accepted message is received from an acceptor
        """

        #if self.final_value is not None:
        #    return  # already done

        if self.proposals is None:
            self.proposals = dict()
            self.proposals[self.uid] = 1
            self.acceptors = dict()

        if from_uid in self.acceptors:
            if accepted_value in self.acceptors[from_uid]:
                return
            else:
                self.acceptors[from_uid].add(accepted_value)
        else:
            self.acceptors[from_uid] = {accepted_value}

        # self.proposals: map from proposal_uid => (num_votes, accepted_value)
        if proposal_uid in self.proposals:
            self.proposals[proposal_uid] += 1
        else:
            self.proposals[proposal_uid] = 1

        if self.proposals[proposal_uid] == self.quorum_size:
            accepted_value_tuple = LogEntry(proposal_uid, accepted_value, False)
            accepted_value_tuple_true = LogEntry(proposal_uid, accepted_value, True)
            is_found = False
            i = len(self.owner.log) - 1
            while i >= 0:
                if self.owner.log[i] == accepted_value_tuple_true:
                    is_found = True

                if self.owner.log[i] == accepted_value_tuple:
                    self.owner.log[i].is_accepted = True
                    is_found = True
                    break

                i -= 1

            if not is_found:
                accepted_value_tuple.is_accepted = True
                self.owner.log.append(accepted_value_tuple)

            m = Learner.AsynchronousMessenger(self, proposal_uid, accepted_value, self.owner.log)
            m.start()
예제 #21
0
class Node(threading.Thread):
    class Daemon(threading.Thread):
        def __init__(self, owner):
            threading.Thread.__init__(self)
            self.owner = owner

        def run(self):
            while True:
                if self.owner.abort:
                    continue

                if self.owner.in_propose_time_frame:
                    self.owner.in_propose_time_frame = False

                    #if self.owner.is_last_decided or self.owner.next_post is None:

                    self.owner.is_last_decided = False

                    self.owner.next_post = self.owner.queue.get(True)
                    print('Propose next available value {}.'.format(self.owner.next_post))
                    self.owner.proposer.set_proposal(self.owner.next_post)
                    self.owner.proposer.propose()
                    #elif self.owner.next_post is not None:
                    #    print('Propose old value {}'.format(self.owner.next_post))
                    #    self.owner.proposer.set_proposal(self.owner.next_post)
                    #    self.owner.proposer.propose()

    def __init__(self, uid, addr, port):
        threading.Thread.__init__(self)
        self.address = addr
        self.port = port
        self.server = Server(self, port, address=addr)
        self.queue = queue.Queue()

        self.abort = False

        self.uid = uid
        self.next_post = None

        # local log of the Node
        self.log = []

        self.proposer = Proposer(self, uid, addr, port + 1)
        self.acceptor = Acceptor(self, uid, addr, port + 2)
        self.learner = Learner(self, uid, addr, port + 3)

        self.stopped_proposal_id = None

        self.lock = threading.Lock()

        self.last_decided_proposer_id = None
        self.is_last_decided = False

        self.in_propose_time_frame = True

        self.daemon = Node.Daemon(self)

    def recv_message(self, msg):
        with self.lock:
            #if msg.type == Message.MSG_STOP and msg.data[0].number != self.stopped_proposal_id:
            if msg.type == Message.MSG_STOP and not self.is_last_decided:
                self.is_last_decided = True
                # set local log
                accepted_log = msg.data[2]
                if len(accepted_log) > len(self.log):
                    self.log = accepted_log

                i = len(self.log) - 1
                while i >= 0:
                    if not self.log[i].is_accepted:
                        del self.log[i]

                    i -= 1

                #print('Log after this round on site {}: '.format(self.uid))
                #print('[', end='')
                #for log_entry in self.log:
                #    print(log_entry, end=', ')
                #
                #print(']\n')

                # self.stopped_proposal_id = msg.data[0].number
                self.proposer.reset()
                self.acceptor.reset()
                self.learner.reset()

                #self.last_decided_proposer_id = msg.data[0]
                #if msg.data[0] == self.uid:

                time.sleep(6)

                self.in_propose_time_frame = True

    def fail(self):
        self.proposer.fail()
        self.acceptor.fail()
        self.learner.fail()

        self.abort = True
        self.server.do_abort()

    def recover(self):
        self.server.recover()
        self.proposer.recover()
        self.acceptor.recover()
        self.learner.recover()

        self.abort = False

    def run(self):
        self.server.start()
        self.proposer.start()
        self.acceptor.start()
        self.learner.start()

        self.daemon.start()
예제 #22
0
class Proposer(object):
    def __init__(self, uid, addr, port):
        self.messenger = Messenger(self)
        self.server = Server(self, port, address=addr)

        self.uid = uid
        self.proposer_uid = uid
        self.quorum_size = 3

        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        self.next_proposal_number = 1
        self.promises_rcvd = None

    def reset(self):
        self.server.queue = queue.Queue()
        self.proposed_value = None
        self.proposal_id = None
        self.last_accepted_id = (-1, -1)
        # self.next_proposal_number = 1
        self.promises_rcvd = None

    def start(self):
        self.server.start()

    def fail(self):
        self.server.do_abort()

    def recover(self):
        self.reset()
        self.server.recover()

    def set_proposal(self, value):
        """
        Sets the proposal value for this node iff this node is not already aware of
        another proposal having already been accepted.
        """
        if self.proposed_value is None:
            self.proposed_value = value

    def prepare(self):
        """
        Sends a prepare request to all Acceptors as the first step in attempting to
        acquire leadership of the Paxos instance.
        """
        self.promises_rcvd = set()
        self.proposal_id = ProposalID(self.next_proposal_number,
                                      self.proposer_uid)

        self.next_proposal_number += 1

        self.messenger.send_prepare(self.proposal_id)

    def recv_message(self, msg):
        if msg.type == Message.MSG_PROMISE:
            self.recv_promise(msg.src, msg.data[0], msg.data[1], msg.data[2])

    def recv_promise(self, from_uid, proposal_id, prev_accepted_id,
                     prev_accepted_value):
        """
        Called when a Promise message is received from an Acceptor
        """

        # Ignore the message if it's for an old proposal or we have already received
        # a response from this Acceptor
        if proposal_id != self.proposal_id or from_uid in self.promises_rcvd:
            return

        self.promises_rcvd.add(from_uid)

        if prev_accepted_id > self.last_accepted_id:
            self.last_accepted_id = prev_accepted_id
            # If the Acceptor has already accepted a value, we MUST set our proposal
            # to that value.
            if prev_accepted_value is not None:
                self.proposed_value = prev_accepted_value

        if len(self.promises_rcvd) == self.quorum_size:
            if self.proposed_value is not None:
                self.messenger.send_accept(self.proposal_id,
                                           self.proposed_value)