Esempio n. 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)
Esempio n. 2
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)
Esempio n. 3
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!')
Esempio n. 4
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)
Esempio n. 5
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()
Esempio n. 6
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()
Esempio n. 7
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)
Esempio n. 8
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()
Esempio n. 9
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)
Esempio n. 10
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()
Esempio n. 11
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)
Esempio n. 12
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)