use of com.alipay.sofa.jraft.entity.PeerId in project sofa-jraft by sofastack.
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.timerManager.schedule(() -> onTransferTimeout(stopArg), this.options.getElectionTimeoutMs(), TimeUnit.MILLISECONDS);
} finally {
this.writeLock.unlock();
}
return Status.OK();
}
use of com.alipay.sofa.jraft.entity.PeerId in project sofa-jraft by sofastack.
the class NodeImpl method checkDeadNodes.
private boolean checkDeadNodes(final Configuration conf, final long monotonicNowMs, final boolean stepDownOnCheckFail) {
// Check learner replicators at first.
for (final PeerId peer : conf.getLearners()) {
checkReplicator(peer);
}
// Ensure quorum nodes alive.
final List<PeerId> peers = conf.listPeers();
final Configuration deadNodes = new Configuration();
if (checkDeadNodes0(peers, monotonicNowMs, true, deadNodes)) {
return true;
}
if (stepDownOnCheckFail) {
LOG.warn("Node {} steps down when alive nodes don't satisfy quorum, term={}, deadNodes={}, conf={}.", getNodeId(), this.currTerm, deadNodes, conf);
final Status status = new Status();
status.setError(RaftError.ERAFTTIMEDOUT, "Majority of the group dies: %d/%d", deadNodes.size(), peers.size());
stepDown(this.currTerm, false, status);
}
return false;
}
use of com.alipay.sofa.jraft.entity.PeerId in project sofa-jraft by sofastack.
the class NodeImpl method handleInstallSnapshot.
@Override
public Message handleInstallSnapshot(final InstallSnapshotRequest request, final RpcRequestClosure done) {
if (this.snapshotExecutor == null) {
return //
RpcFactoryHelper.responseFactory().newResponse(InstallSnapshotResponse.getDefaultInstance(), RaftError.EINVAL, "Not supported snapshot");
}
final PeerId serverId = new PeerId();
if (!serverId.parse(request.getServerId())) {
LOG.warn("Node {} ignore InstallSnapshotRequest from {} bad server id.", getNodeId(), request.getServerId());
return //
RpcFactoryHelper.responseFactory().newResponse(InstallSnapshotResponse.getDefaultInstance(), RaftError.EINVAL, "Parse serverId failed: %s", request.getServerId());
}
this.writeLock.lock();
try {
if (!this.state.isActive()) {
LOG.warn("Node {} ignore InstallSnapshotRequest as it is not in active state {}.", getNodeId(), this.state);
return //
RpcFactoryHelper.responseFactory().newResponse(InstallSnapshotResponse.getDefaultInstance(), RaftError.EINVAL, "Node %s:%s is not in active state, state %s.", this.groupId, this.serverId, this.state.name());
}
if (request.getTerm() < this.currTerm) {
LOG.warn("Node {} ignore stale InstallSnapshotRequest from {}, term={}, currTerm={}.", getNodeId(), request.getPeerId(), request.getTerm(), this.currTerm);
return //
InstallSnapshotResponse.newBuilder().setTerm(//
this.currTerm).setSuccess(//
false).build();
}
checkStepDown(request.getTerm(), serverId);
if (!serverId.equals(this.leaderId)) {
LOG.error("Another peer {} declares that it is the leader at term {} which was occupied by leader {}.", serverId, this.currTerm, this.leaderId);
// Increase the term by 1 and make both leaders step down to minimize the
// loss of split brain
stepDown(request.getTerm() + 1, false, new Status(RaftError.ELEADERCONFLICT, "More than one leader in the same term."));
return //
InstallSnapshotResponse.newBuilder().setTerm(//
request.getTerm() + 1).setSuccess(//
false).build();
}
} finally {
this.writeLock.unlock();
}
final long startMs = Utils.monotonicMs();
try {
if (LOG.isInfoEnabled()) {
LOG.info("Node {} received InstallSnapshotRequest from {}, lastIncludedLogIndex={}, lastIncludedLogTerm={}, lastLogId={}.", getNodeId(), request.getServerId(), request.getMeta().getLastIncludedIndex(), request.getMeta().getLastIncludedTerm(), this.logManager.getLastLogId(false));
}
this.snapshotExecutor.installSnapshot(request, InstallSnapshotResponse.newBuilder(), done);
return null;
} finally {
this.metrics.recordLatency("install-snapshot", Utils.monotonicMs() - startMs);
}
}
use of com.alipay.sofa.jraft.entity.PeerId in project sofa-jraft by sofastack.
the class NodeImpl method handlePreVoteRequest.
@Override
public Message handlePreVoteRequest(final RequestVoteRequest request) {
boolean doUnlock = true;
this.writeLock.lock();
try {
if (!this.state.isActive()) {
LOG.warn("Node {} is not in active state, currTerm={}.", getNodeId(), this.currTerm);
return //
RpcFactoryHelper.responseFactory().newResponse(RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Node %s is not in active state, state %s.", getNodeId(), this.state.name());
}
final PeerId candidateId = new PeerId();
if (!candidateId.parse(request.getServerId())) {
LOG.warn("Node {} received PreVoteRequest from {} serverId bad format.", getNodeId(), request.getServerId());
return //
RpcFactoryHelper.responseFactory().newResponse(RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Parse candidateId failed: %s.", request.getServerId());
}
boolean granted = false;
// noinspection ConstantConditions
do {
if (!this.conf.contains(candidateId)) {
LOG.warn("Node {} ignore PreVoteRequest from {} as it is not in conf <{}>.", getNodeId(), request.getServerId(), this.conf);
break;
}
if (this.leaderId != null && !this.leaderId.isEmpty() && isCurrentLeaderValid()) {
LOG.info("Node {} ignore PreVoteRequest from {}, term={}, currTerm={}, because the leader {}'s lease is still valid.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm, this.leaderId);
break;
}
if (request.getTerm() < this.currTerm) {
LOG.info("Node {} ignore PreVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
// A follower replicator may not be started when this node become leader, so we must check it.
checkReplicator(candidateId);
break;
}
// A follower replicator may not be started when this node become leader, so we must check it.
// check replicator state
checkReplicator(candidateId);
doUnlock = false;
this.writeLock.unlock();
final LogId lastLogId = this.logManager.getLastLogId(true);
doUnlock = true;
this.writeLock.lock();
final LogId requestLastLogId = new LogId(request.getLastLogIndex(), request.getLastLogTerm());
granted = requestLastLogId.compareTo(lastLogId) >= 0;
LOG.info("Node {} received PreVoteRequest from {}, term={}, currTerm={}, granted={}, requestLastLogId={}, lastLogId={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm, granted, requestLastLogId, lastLogId);
} while (false);
return //
RequestVoteResponse.newBuilder().setTerm(//
this.currTerm).setGranted(//
granted).build();
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
}
}
use of com.alipay.sofa.jraft.entity.PeerId in project sofa-jraft by sofastack.
the class NodeImpl method fillLogEntryPeers.
private void fillLogEntryPeers(final RaftOutter.EntryMeta entry, final LogEntry logEntry) {
// TODO refactor
if (entry.getPeersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getPeersCount());
for (final String peerStr : entry.getPeersList()) {
final PeerId peer = new PeerId();
peer.parse(peerStr);
peers.add(peer);
}
logEntry.setPeers(peers);
}
if (entry.getOldPeersCount() > 0) {
final List<PeerId> oldPeers = new ArrayList<>(entry.getOldPeersCount());
for (final String peerStr : entry.getOldPeersList()) {
final PeerId peer = new PeerId();
peer.parse(peerStr);
oldPeers.add(peer);
}
logEntry.setOldPeers(oldPeers);
}
if (entry.getLearnersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getLearnersCount());
for (final String peerStr : entry.getLearnersList()) {
final PeerId peer = new PeerId();
peer.parse(peerStr);
peers.add(peer);
}
logEntry.setLearners(peers);
}
if (entry.getOldLearnersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getOldLearnersCount());
for (final String peerStr : entry.getOldLearnersList()) {
final PeerId peer = new PeerId();
peer.parse(peerStr);
peers.add(peer);
}
logEntry.setOldLearners(peers);
}
}
Aggregations