use of org.apache.ignite.raft.jraft.Status in project ignite-3 by apache.
the class NodeImpl method handleVoteTimeout.
private void handleVoteTimeout() {
this.writeLock.lock();
if (this.state != State.STATE_CANDIDATE) {
this.writeLock.unlock();
return;
}
// This is needed for the node, which won preVote in a previous iteration, but leader wasn't elected.
if (this.prevVoteCtx.isGranted())
adjustElectionTimeout();
if (this.raftOptions.isStepDownWhenVoteTimedout()) {
LOG.warn("Candidate node {} term {} steps down when election reaching vote timeout: fail to get quorum vote-granted.", this.nodeId, this.currTerm);
stepDown(this.currTerm, false, new Status(RaftError.ETIMEDOUT, "Vote timeout: fail to get quorum vote-granted."));
// unlock in preVote
preVote();
} else {
LOG.debug("Node {} term {} retry to vote self.", getNodeId(), this.currTerm);
// unlock in electSelf
electSelf();
}
}
use of org.apache.ignite.raft.jraft.Status in project ignite-3 by apache.
the class NodeImpl method onError.
public void onError(final RaftException error) {
LOG.warn("Node {} got error: {}.", getNodeId(), (Object) error);
if (this.fsmCaller != null) {
// onError of fsmCaller is guaranteed to be executed once.
this.fsmCaller.onError(error);
}
if (this.readOnlyService != null) {
this.readOnlyService.setError(error);
}
this.writeLock.lock();
try {
// If it is follower, also step down to call on_stop_following.
if (this.state.compareTo(State.STATE_FOLLOWER) <= 0) {
stepDown(this.currTerm, this.state == State.STATE_LEADER, new Status(RaftError.EBADNODE, "Raft node(leader or candidate) is in error."));
}
if (this.state.compareTo(State.STATE_ERROR) < 0) {
this.state = State.STATE_ERROR;
}
} finally {
this.writeLock.unlock();
}
}
use of org.apache.ignite.raft.jraft.Status in project ignite-3 by apache.
the class NodeImpl method transferLeadershipTo.
@Override
public Status transferLeadershipTo(final PeerId peer) {
Requires.requireNonNull(peer, "Null peer");
this.writeLock.lock();
try {
if (this.state != State.STATE_LEADER) {
LOG.warn("Node {} can't transfer leadership to peer {} as it is in state {}.", getNodeId(), peer, this.state);
return new Status(this.state == State.STATE_TRANSFERRING ? RaftError.EBUSY : RaftError.EPERM, "Not a leader");
}
if (this.confCtx.isBusy()) {
// It's very messy to deal with the case when the |peer| received
// TimeoutNowRequest and increase the term while somehow another leader
// which was not replicated with the newest configuration has been
// elected. If no add_peer with this very |peer| is to be invoked ever
// after nor this peer is to be killed, this peer will spin in the voting
// procedure and make the each new leader stepped down when the peer
// reached vote timeout and it starts to vote (because it will increase
// the term of the group)
// To make things simple, refuse the operation and force users to
// invoke transfer_leadership_to after configuration changing is
// completed so that the peer's configuration is up-to-date when it
// receives the TimeOutNowRequest.
LOG.warn("Node {} refused to transfer leadership to peer {} when the leader is changing the configuration.", getNodeId(), peer);
return new Status(RaftError.EBUSY, "Changing the configuration");
}
PeerId peerId = peer.copy();
// last_log_id will be selected.
if (peerId.equals(PeerId.ANY_PEER)) {
LOG.info("Node {} starts to transfer leadership to any peer.", getNodeId());
if ((peerId = this.replicatorGroup.findTheNextCandidate(this.conf)) == null) {
return new Status(-1, "Candidate not found for any peer");
}
}
if (peerId.equals(this.serverId)) {
LOG.info("Node {} transferred leadership to self.", this.serverId);
return Status.OK();
}
if (!this.conf.contains(peerId)) {
LOG.info("Node {} refused to transfer leadership to peer {} as it is not in {}.", getNodeId(), peer, this.conf);
return new Status(RaftError.EINVAL, "Not in current configuration");
}
final long lastLogIndex = this.logManager.getLastLogIndex();
if (!this.replicatorGroup.transferLeadershipTo(peerId, lastLogIndex)) {
LOG.warn("No such peer {}.", peer);
return new Status(RaftError.EINVAL, "No such peer %s", peer);
}
this.state = State.STATE_TRANSFERRING;
final Status status = new Status(RaftError.ETRANSFERLEADERSHIP, "Raft leader is transferring leadership to %s", peerId);
onLeaderStop(status);
LOG.info("Node {} starts to transfer leadership to peer {}.", getNodeId(), peer);
final StopTransferArg stopArg = new StopTransferArg(this, this.currTerm, peerId);
this.stopTransferArg = stopArg;
this.transferTimer = this.getOptions().getScheduler().schedule(() -> onTransferTimeout(stopArg), this.options.getElectionTimeoutMs(), TimeUnit.MILLISECONDS);
} finally {
this.writeLock.unlock();
}
return Status.OK();
}
use of org.apache.ignite.raft.jraft.Status in project ignite-3 by apache.
the class CliServiceImpl method removePeer.
@Override
public Status removePeer(final String groupId, final Configuration conf, final PeerId peer) {
Requires.requireTrue(!StringUtils.isBlank(groupId), "Blank group id");
Requires.requireNonNull(conf, "Null configuration");
Requires.requireNonNull(peer, "Null peer");
Requires.requireTrue(!peer.isEmpty(), "Removing peer is blank");
final PeerId leaderId = new PeerId();
final Status st = getLeader(groupId, conf, leaderId);
if (!st.isOk()) {
return st;
}
if (!this.cliClientService.connect(leaderId.getEndpoint())) {
return new Status(-1, "Fail to init channel to leader %s", leaderId);
}
RemovePeerRequest req = cliOptions.getRaftMessagesFactory().removePeerRequest().groupId(groupId).leaderId(leaderId.toString()).peerId(peer.toString()).build();
try {
final Message result = this.cliClientService.removePeer(leaderId.getEndpoint(), req, null).get();
if (result instanceof RemovePeerResponse) {
final RemovePeerResponse resp = (RemovePeerResponse) result;
final Configuration oldConf = new Configuration();
for (final String peerIdStr : resp.oldPeersList()) {
final PeerId oldPeer = new PeerId();
oldPeer.parse(peerIdStr);
oldConf.addPeer(oldPeer);
}
final Configuration newConf = new Configuration();
for (final String peerIdStr : resp.newPeersList()) {
final PeerId newPeer = new PeerId();
newPeer.parse(peerIdStr);
newConf.addPeer(newPeer);
}
LOG.info("Configuration of replication group {} changed from {} to {}", groupId, oldConf, newConf);
return Status.OK();
} else {
return statusFromResponse(result);
}
} catch (final Exception e) {
return new Status(-1, e.getMessage());
}
}
use of org.apache.ignite.raft.jraft.Status in project ignite-3 by apache.
the class CliServiceImpl method getLeader.
@Override
public Status getLeader(final String groupId, final Configuration conf, final PeerId leaderId) {
Requires.requireTrue(!StringUtils.isBlank(groupId), "Blank group id");
Requires.requireNonNull(leaderId, "Null leader id");
if (conf == null || conf.isEmpty()) {
return new Status(RaftError.EINVAL, "Empty group configuration");
}
final Status st = new Status(-1, "Fail to get leader of group %s", groupId);
for (final PeerId peer : conf) {
if (!this.cliClientService.connect(peer.getEndpoint())) {
LOG.error("Fail to connect peer {} to get leader for group {}.", peer, groupId);
continue;
}
GetLeaderRequest rb = cliOptions.getRaftMessagesFactory().getLeaderRequest().groupId(groupId).peerId(peer.toString()).build();
final Future<Message> result = this.cliClientService.getLeader(peer.getEndpoint(), rb, null);
try {
final Message msg = result.get(this.cliOptions.getTimeoutMs() <= 0 ? this.cliOptions.getRpcDefaultTimeout() : this.cliOptions.getTimeoutMs(), TimeUnit.MILLISECONDS);
if (msg instanceof ErrorResponse) {
if (st.isOk()) {
st.setError(-1, ((ErrorResponse) msg).errorMsg());
} else {
final String savedMsg = st.getErrorMsg();
st.setError(-1, "%s, %s", savedMsg, ((ErrorResponse) msg).errorMsg());
}
} else {
final GetLeaderResponse response = (GetLeaderResponse) msg;
if (leaderId.parse(response.leaderId())) {
break;
}
}
} catch (final Exception e) {
if (st.isOk()) {
st.setError(-1, e.getMessage());
} else {
final String savedMsg = st.getErrorMsg();
st.setError(-1, "%s, %s", savedMsg, e.getMessage());
}
}
}
if (leaderId.isEmpty()) {
return st;
}
return Status.OK();
}
Aggregations