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
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), }
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
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))