Example #1
0
    def _(self, message, channel, create_reply=Response.create):
        """Learn Phase.

        To learn that a value has been chosen, a learner must find out that a
        proposal has been accepted by a majority of acceptors.

        """
        LOG.debug("RECEIVED message {0}".format(message))
        self.accepted_proposals.setdefault(message.proposal, set()) \
            .add(message.sender)

        minimum_quorum = len(channel.replicas) // 2 + 1
        accepted_quorum = len(self.accepted_proposals.get(message.proposal))

        if accepted_quorum == minimum_quorum:
            # Here we reset for the next round.
            self.state.write(Role.PROPOSED, self.state.read(Role.PROPOSED) \
                .next())
            self.state.write(Role.VALUE, None)

            channel.unicast(Request.create(receiver=message.receiver,
                                           sender=message.receiver))
            self.notification.send(create_reply(proposal=message.proposal))

        if accepted_quorum >= minimum_quorum:
            self._ledger.append(LedgerEntry(number=message.proposal.number,
                                            value=message.value))
            reply = create_reply(proposal=message.proposal)
            channel.unicast(reply)

        if accepted_quorum == len(channel.replicas):
            del self.accepted_proposals[message.proposal]
Example #2
0
    def _(self, message, channel, create_reply=Accept.create):
        """Accept Phase.

        If the proposer receives a response to its prepare requests (numbered
        n) from a majority of acceptors, then it sends an accept request to
        each of those acceptors for a proposal numbered n with a value v, where
        v is the value of the highest-numbered proposal among the responses, or
        is any value if the responses reported no proposals.

        """
        LOG.debug("RECEIVED message {0}".format(message))
        self.received_promises.setdefault(message.proposal, set()) \
            .add(message.sender)

        if (self.highest_proposal is None or
            message.accepted_proposal >= self.highest_proposal):
            self.highest_proposal = message.proposal
            if message.value:
                self.selector.set(message.proposal, message.value)

        value = self.selector.get(message.proposal)

        minimum_quorum = len(channel.replicas) // 2 + 1
        received_promises = len(self.received_promises.get(message.proposal))

        if received_promises >= minimum_quorum:
            reply = create_reply(sender=message.receiver,
                                 proposal=message.proposal,
                                 value=value)
            channel.broadcast(reply)
Example #3
0
    def _(self, message, channel):
        """Handle request from out-of-sync replica""" 

        LOG.debug("RECEIVED message {0}".format(message))
        proposals = self._ledger.get_range(message.proposal)[:Learner.SYNC_SIZE]
        is_finished = proposals[-1] == self.state.read(Role.ACCEPTED)

        channel.unicast(Synced.create(receiver=message.sender,
                                      sender=message.receiver,
                                      proposal=proposals,
                                      finished=is_finished))
Example #4
0
 def send(self, message):
     loop = asyncio.new_event_loop()
     asyncio.set_event_loop(loop)
     coro = loop.create_connection(lambda: RemoteProtocol(message, loop),
                                   self.ip, self.port)
     try:
         loop.run_until_complete(coro)
     except ConnectionRefusedError as e:
         LOG.debug("I/O send error({0}: {1}".format(message.receiver,
                                                    e.strerror))
         pass
     loop.close()
Example #5
0
    def _(self, message, channel, create_reply=Prepare.create):
        """Prepare Phase.

        A proposer selects a proposal number n and sends a prepare request
        with number n to a majority of acceptors.

        """
        LOG.debug("RECEIVED message {0}".format(message))
        if message.value:
            self.selector.add(message.value)

        if not self.selector.is_empty():
            current_proposal = self.state.read(Role.PROPOSED)
            reply = create_reply(sender=message.receiver,
                                 proposal=current_proposal)
            channel.broadcast(reply)
            self.notification.wait(current_proposal)
Example #6
0
    def _(self, message, channel):
        """Handle response for updating this replica"""

        LOG.debug("RECEIVED message {0}".format(message))
        synced_proposals = message.proposal
        self._ledger.extend(synced_proposals)

        current_proposal = Proposal("sync", synced_proposals[-1].number)
        next_proposal = Proposal("sync", synced_proposals[-1].number + 1)

        self.state.write(Role.PROPOSED, current_proposal)
        self.state.write(Role.PROMISED, current_proposal)
        self.state.write(Role.ACCEPTED, current_proposal)

        if not message.finished:
            channel.unicast(Sync.create(
                receiver=message.sender,
                sender=message.receiver,
                proposal=self.state.read(Role.ACCEPTED)))
        else:
            self.state.write(Role.PROPOSED, next_proposal)
            self.resume()
Example #7
0
    def _(self, message, channel, create_reply=Promise.create):
        """Promise Phase.

        If an acceptor receives a prepare request with number n greater than
        that of any prepare request to which it has already responded then it
        responds to the request with a promise not to accept any more
        proposals numbered less than n and with the highest-numbered proposal
        (if any) that it has accepted.

        """
        LOG.debug("RECEIVED message {0}".format(message))
        if message.proposal >= self.state.read(Role.PROMISED):
            self.state.write(Role.PROMISED, message.proposal)
            reply = create_reply(
                sender=message.receiver,
                receiver=message.sender,
                proposal=message.proposal,
                accepted_proposal=self.state.read(Role.ACCEPTED),
                value=self.state.read(Role.VALUE))
            channel.unicast(reply)
        else:
            reply = Nack.create(sender=message.receiver,
                                receiver=message.sender)
            channel.unicast(reply)
Example #8
0
    def _(self, message, channel, create_reply=Accepted.create):
        """Accepted Phase.

        If an acceptor receives an accept request for a proposal numbered n,
        it accepts the proposal unless it has already responded to a prepare
        request having a number greater than n.

        """
        LOG.debug("RECEIVED message {0}".format(message))
        if message.proposal >= self.state.read(Role.PROMISED):
            if message.proposal > self.state.read(Role.ACCEPTED):
                self.state.write(Role.ACCEPTED, message.proposal)
                self.state.write(Role.VALUE, message.value)

            reply = create_reply(sender=message.receiver,
                                 value=self.state.read(Role.VALUE),
                                 proposal=message.proposal)
            channel.broadcast(reply)
        else:
            reply = Nack.create(sender=message.receiver,
                                receiver=message.sender,
                                value=self.state.read(Role.VALUE),
                                proposal=message.proposal)
            channel.unicast(reply)