Exemplo n.º 1
0
    def new_request(self, value):
        print("trying to insert {} inside the log".format(value))
        logger.debug("trying to insert {} inside the log".format(value))

        self.lock.acquire()
        self.staged = value

        waited = 0

        log_message = raft_definitions.raft_packet(
            sourceID=0x0,
            destinationID=0x1,
            data=value,
            logIndex=self.commitIndex,
            srcIP=self.address,
            dstIP=None,  # will be defined inside spread_update!
            currentTerm=self.term,
            messageType=raft_definitions.COMMANDS['AppendEntries'])

        log_confirmations = [False] * len(
            self.nodes)  # to see how many have approved the new value
        threading.Thread(target=self.spread_update,
                         args=(log_message, log_confirmations)).start()

        while sum(log_confirmations) + 1 < self.majority:
            waited += 0.005
            time.sleep(0.005)

            if waited > raft_definitions.MAX_LOG_WAIT / 1000:
                print("waited {} ms, update rejected:".format(
                    raft_definitions.MAX_LOG_WAIT))
                logger.debug("waited {} ms, update rejected:".format(
                    raft_definitions.MAX_LOG_WAIT))
                logger.debug("confirmations: {}".format(log_confirmations))

                self.lock.release()
                return False

        # reach this point only if a majority has replied and tell everyone to commit
        commit_message = raft_definitions.raft_packet(
            sourceID=0x0,
            destinationID=0x1,
            srcIP=self.address,
            dstIP=None,  # will be defined inside spread update!
            messageType=raft_definitions.COMMANDS['CommitValue'],
            data=value,
            logIndex=self.commitIndex,
            currentTerm=self.term)
        self.commit()
        threading.Thread(target=self.spread_update,
                         args=(commit_message, None, self.lock)).start()
        print("majority reached, replied to client, sending message to commit")
        return True
Exemplo n.º 2
0
def handle_vote_request(packet):
    logger.debug("{} handle vote request from {}".format(n.address, packet[IP].src))
    req_term = packet[Raft].currentTerm
    log_index = packet[Raft].logIndex
    requester_ip = packet[IP].src
    staged = None if packet[Raft].data == 0x0 else packet[Raft].data

    choice, term = n.decide_vote(ip=requester_ip, term=req_term, commitIdx=log_index, staged=staged)
    logger.debug("decided: {} , my_term: {}, his_term: {}".format(choice, term, req_term))
    print("decided: {} , my_term: {}, his_term: {}".format(choice, term, req_term))

    voted = 0x1 if choice else 0x0

    message = raft_definitions.raft_packet(
        sourceID=0,
        destinationID=1,
        dstIP=requester_ip,
        srcIP=n.address,  # my ip
        voted=voted,
        currentTerm=term,
        data=0x0,
        logIndex=n.commitIndex,  # CHECK ME
        messageType=COMMANDS['ResponseVote']
    )

    raft_definitions.send_no_reply(message)
    return
Exemplo n.º 3
0
def handle_heartbeat(packet):
    logger.debug("{} received heartbeat from:{}".format(n.address, packet.sprintf("IP:%IP.src%")))

    term, commit_index = n.heartbeat_follower(packet)
    response_ip = packet[IP].src

    command = COMMANDS['HeartBeatResponse']

    message = raft_definitions.raft_packet(
        sourceID=0,
        destinationID=1,
        logIndex=commit_index,
        currentTerm=term,
        dstIP=response_ip,
        srcIP=n.address,
        data=0x0,
        messageType=command
    )

    if packet[Raft].messageType == COMMANDS['AppendEntries']:  # it was an append entry
        # I have to reply with append entry reply to let the leader know that I handled the new value
        message[Raft].messageType = COMMANDS['AppendEntriesReply']
        raft_definitions.send_no_reply(message)
    else:
        raft_definitions.send_no_reply(message)
Exemplo n.º 4
0
    def update_follower_log(self, follower):
        """Every 5 seconds, send to the follower a recover entries to check that the log is consistent"""

        # TODO instead of doing a periodically recovering, use an event-based mechanism
        #  ( for example a node that goes up informs the leader that he is
        #  up again and that his log may be not consistent)
        while True:
            index = 0

            try:
                for val in self.log:
                    message = raft_definitions.raft_packet(
                        sourceID=0x0,
                        destinationID=0x1,
                        dstIP=follower,
                        srcIP=self.address,
                        data=val,
                        currentTerm=self.term,
                        logIndex=index,
                        messageType=raft_definitions.COMMANDS['RecoverEntries']
                    )
                    raft_definitions.send_raft_heartbeat_with_log(
                        follower, message)
                    index += 1

            except Exception as e:
                print('Error while sending recover messages: {}'.format(e))

            time.sleep(raft_definitions.RECOVER_TIME // 1000)
Exemplo n.º 5
0
    def ask_for_vote(self, voter_ip, term):
        # need to include self.commitIndex, only up-to-date candidate could win
        print("{} ASKING FOR VOTE".format(self.address))

        command = raft_definitions.COMMANDS['RequestVote']
        data = 0x0 if not self.staged else self.staged  # TODO CHECK ME

        message = raft_definitions.raft_packet(sourceID=0,
                                               destinationID=1,
                                               srcIP=self.address,
                                               dstIP=voter_ip,
                                               logIndex=self.commitIndex,
                                               currentTerm=term,
                                               data=data,
                                               messageType=command)

        while self.status == STATUSES['candidate'] and self.term == term:

            logger.debug("{} sending vote request to: {}".format(
                self.address, voter_ip, self.term))
            reply = raft_definitions.send_raft_vote_request(voter_ip, message)

            if reply:
                # logger.debug("got reply: %s" % reply.sprintf(
                #     "IP:%IP.src%:%UDP.dport%;Raft voted:%Raft.voted%, term:%Raft.currentTerm%"
                # ))
                # logger.debug("my_term: {}, my_log: {}".format(self.term, self.log))

                choice = True if reply[Raft].voted == 0x1 else False

                logger.debug('Received Vote: {} from {}'.format(
                    choice, reply[IP].src))

                if choice and self.status == STATUSES['candidate']:
                    self.increment_vote()

                elif not choice:
                    # they declined because either I'm out-of-date or not newest term
                    # update my term and terminate the vote_req
                    term = reply[Raft].currentTerm
                    if term > self.term:
                        self.term = term
                        self.status = STATUSES['follower']
                break
Exemplo n.º 6
0
    def send_heartbeat(self, follower):
        # check if the new follower have same commit index, else we tell them to update to our log level

        #if len(self.log) > 0:
        threading.Thread(target=self.update_follower_log,
                         args=(follower, )).start()

        command = raft_definitions.COMMANDS['HeartBeatRequest']
        message = raft_definitions.raft_packet(sourceID=0x0,
                                               destinationID=0x1,
                                               srcIP=self.address,
                                               dstIP=follower,
                                               currentTerm=self.term,
                                               messageType=command,
                                               logIndex=self.commitIndex,
                                               data=0x0)  # CHECK ME

        while self.status == STATUSES['leader']:
            # logger.debug("sending heartbeat request to: {}".format(follower))
            # print("sending heartbeat request to: {}".format(follower))

            start = time.time()

            reply = raft_definitions.send_raft_heartbeat(follower, message)

            if reply:
                term = reply[Raft].currentTerm

                self.heartbeat_reply_handler(term, follower)

            elif self.status != STATUSES['leader']:  # may be useless
                break

            delta = time.time() - start
            # keep the heartbeat constant even if the network speed is varying
            sleep_time = (raft_definitions.HEARTBEAT_TIME - delta) / 1000
            time.sleep(0 if sleep_time <= 0 else sleep_time)

        return