Esempio n. 1
0
    def entry_pop(self, ety, ety_idx):
        # logging.warning("POP {} {}".format(self, ety_idx))

        e = self._check_committed_entry_popping(ety_idx)
        if e != 0:
            return e

        self.fsm_log.pop()
        self.network.log_pops += 1

        change = ffi.from_handle(ety.data.buf)
        if ety.type == lib.RAFT_LOGTYPE_DEMOTE_NODE:
            pass

        elif ety.type == lib.RAFT_LOGTYPE_REMOVE_NODE:
            if change.node_id == lib.raft_get_nodeid(self.raft):
                self.set_connection_status(NODE_CONNECTED)

        elif ety.type == lib.RAFT_LOGTYPE_ADD_NONVOTING_NODE:
            if change.node_id == lib.raft_get_nodeid(self.raft):
                logging.error("POP disconnect {} {}".format(self, ety_idx))
                self.set_connection_status(NODE_DISCONNECTED)

        elif ety.type == lib.RAFT_LOGTYPE_ADD_NODE:
            if change.node_id == lib.raft_get_nodeid(self.raft):
                self.set_connection_status(NODE_CONNECTING)

        return 0
Esempio n. 2
0
 def debug_statistics(self):
     return {
         "node":
         lib.raft_get_nodeid(self.raft),
         "state":
         state2str(lib.raft_get_state(self.raft)),
         "current_idx":
         lib.raft_get_current_idx(self.raft),
         "last_log_term":
         lib.raft_get_last_log_term(self.raft),
         "current_term":
         lib.raft_get_current_term(self.raft),
         "commit_idx":
         lib.raft_get_commit_idx(self.raft),
         "last_applied_idx":
         lib.raft_get_last_applied_idx(self.raft),
         "log_count":
         lib.raft_get_log_count(self.raft),
         "peers":
         lib.raft_get_num_nodes(self.raft),
         "voting_peers":
         lib.raft_get_num_voting_nodes(self.raft),
         "connection_status":
         connectstatus2str(self.connection_status),
         "voting_change_in_progress":
         lib.raft_voting_change_is_in_progress(self.raft),
         "removed":
         getattr(self, 'removed', False),
     }
Esempio n. 3
0
    def entry_apply(self, ety, idx):
        # collect stats
        if self.network.latest_applied_log_idx < idx:
            self.network.latest_applied_log_idx = idx
            self.network.latest_applied_log_iteration = self.network.iteration

        e = self._check_log_matching(ety, idx)
        if e is not None:
            return e

        change = ffi.from_handle(ety.data.buf)

        if ety.type == lib.RAFT_LOGTYPE_NORMAL:
            self.fsm_dict[change.key] = change.val

        elif ety.type == lib.RAFT_LOGTYPE_DEMOTE_NODE:
            if change.node_id == lib.raft_get_nodeid(self.raft):
                # logging.warning("{} shutting down because of demotion".format(self))
                return lib.RAFT_ERR_SHUTDOWN

            # Follow up by removing the node by receiving new entry
            elif lib.raft_is_leader(self.raft):
                new_ety = ffi.new('msg_entry_t*')
                new_ety.term = 0
                new_ety.id = self.network.new_entry_id()
                new_ety.type = lib.RAFT_LOGTYPE_REMOVE_NODE
                new_ety.data.buf = ety.data.buf
                new_ety.data.len = ffi.sizeof(ety.data.buf)
                assert(lib.raft_entry_is_cfg_change(new_ety))
                e = self.recv_entry(new_ety)
                assert e == 0

        elif ety.type == lib.RAFT_LOGTYPE_REMOVE_NODE:
            if change.node_id == lib.raft_get_nodeid(self.raft):
                # logging.warning("{} shutting down because of removal".format(self))
                return lib.RAFT_ERR_SHUTDOWN

        elif ety.type == lib.RAFT_LOGTYPE_ADD_NODE:
            if change.node_id == self.id:
                self.set_connection_status(NODE_CONNECTED)

        elif ety.type == lib.RAFT_LOGTYPE_ADD_NONVOTING_NODE:
            pass

        return 0
Esempio n. 4
0
    def load_snapshot(self, snapshot, other):
        # logging.warning('{} loading snapshot'.format(self))
        e = lib.raft_begin_load_snapshot(
            self.raft,
            snapshot.last_term,
            snapshot.last_idx,
        )
        if e == -1:
            return 0
        elif e == lib.RAFT_ERR_SNAPSHOT_ALREADY_LOADED:
            return 0
        elif e == 0:
            pass
        else:
            assert False

        # Send appendentries response for this snapshot
        response = ffi.new('msg_appendentries_response_t*')
        response.success = 1
        response.current_idx = snapshot.last_idx
        response.term = lib.raft_get_current_term(self.raft)
        response.first_idx = response.current_idx
        self.network.enqueue_msg(response, self, other)

        node_id = lib.raft_get_nodeid(self.raft)

        # set membership configuration according to snapshot
        for member in snapshot.members:
            if -1 == member.id:
                continue

            node = lib.raft_get_node(self.raft, member.id)

            if not node:
                udata = ffi.NULL
                try:
                    node_sv = self.network.id2server(member.id)
                    udata = node_sv.udata
                except ServerDoesNotExist:
                    pass

                node = lib.raft_add_node(self.raft, udata, member.id, member.id == node_id)

            lib.raft_node_set_active(node, 1)

            if member.voting and not lib.raft_node_is_voting(node):
                lib.raft_node_set_voting(node, 1)
            elif not member.voting and lib.raft_node_is_voting(node):
                lib.raft_node_set_voting(node, 0)

            if node_id != member.id:
                assert node

        # TODO: this is quite ugly
        # we should have a function that removes all nodes by ourself
        # if (!raft_get_my_node(self->raft)) */
        #     raft_add_non_voting_node(self->raft, NULL, node_id, 1); */

        e = lib.raft_end_load_snapshot(self.raft)
        assert(0 == e)
        assert(lib.raft_get_log_count(self.raft) == 0)

        self.do_membership_snapshot()
        self.snapshot.image = dict(snapshot.image)
        self.snapshot.last_term = snapshot.last_term
        self.snapshot.last_idx = snapshot.last_idx

        assert(lib.raft_get_my_node(self.raft))
        # assert(sv->snapshot_fsm);

        self.fsm_dict = dict(snapshot.image)

        logging.warning('{} loaded snapshot t:{} idx:{}'.format(
            self, snapshot.last_term, snapshot.last_idx))