use of io.dingodb.raft.Status in project dingo by dingodb.
the class NodeImpl method handleRequestVoteRequest.
@Override
public Message handleRequestVoteRequest(final RpcRequests.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(RpcRequests.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 RequestVoteRequest from {} serverId bad format.", getNodeId(), request.getServerId());
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Parse candidateId failed: %s.", request.getServerId());
}
// noinspection ConstantConditions
do {
// check term
if (request.getTerm() >= this.currTerm) {
LOG.info("Node {} received RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
// increase current term, change state to follower
if (request.getTerm() > this.currTerm) {
stepDown(request.getTerm(), false, new Status(RaftError.EHIGHERTERMRESPONSE, "Raft node receives higher term RequestVoteRequest."));
}
} else {
// ignore older term
LOG.info("Node {} ignore RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
break;
}
doUnlock = false;
this.writeLock.unlock();
final LogId lastLogId = this.logManager.getLastLogId(true);
doUnlock = true;
this.writeLock.lock();
// vote need ABA check after unlock&writeLock
if (request.getTerm() != this.currTerm) {
LOG.warn("Node {} raise term {} when get lastLogId.", getNodeId(), this.currTerm);
break;
}
final boolean logIsOk = new LogId(request.getLastLogIndex(), request.getLastLogTerm()).compareTo(lastLogId) >= 0;
if (logIsOk && (this.votedId == null || this.votedId.isEmpty())) {
stepDown(request.getTerm(), false, new Status(RaftError.EVOTEFORCANDIDATE, "Raft node votes for some candidate, step down to restart election_timer."));
this.votedId = candidateId.copy();
this.metaStorage.setVotedFor(candidateId);
}
} while (false);
return //
RpcRequests.RequestVoteResponse.newBuilder().setTerm(//
this.currTerm).setGranted(//
request.getTerm() == this.currTerm && candidateId.equals(this.votedId)).build();
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
}
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class NodeImpl method onError.
public void onError(final RaftException error) {
LOG.warn("Node {} got error: {}.", getNodeId(), 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 io.dingodb.raft.Status in project dingo by dingodb.
the class CliServiceImpl method rebalance.
@Override
public Status rebalance(final Set<String> balanceGroupIds, final Configuration conf, final Map<String, PeerId> rebalancedLeaderIds) {
Requires.requireNonNull(balanceGroupIds, "Null balance group ids");
Requires.requireTrue(!balanceGroupIds.isEmpty(), "Empty balance group ids");
Requires.requireNonNull(conf, "Null configuration");
Requires.requireTrue(!conf.isEmpty(), "No peers of configuration");
LOG.info("Rebalance start with raft groups={}.", balanceGroupIds);
final long start = Utils.monotonicMs();
int transfers = 0;
Status failedStatus = null;
final Queue<String> groupDeque = new ArrayDeque<>(balanceGroupIds);
final LeaderCounter leaderCounter = new LeaderCounter(balanceGroupIds.size(), conf.size());
for (; ; ) {
final String groupId = groupDeque.poll();
if (groupId == null) {
// well done
break;
}
final PeerId leaderId = new PeerId();
final Status leaderStatus = getLeader(groupId, conf, leaderId);
if (!leaderStatus.isOk()) {
failedStatus = leaderStatus;
break;
}
if (rebalancedLeaderIds != null) {
rebalancedLeaderIds.put(groupId, leaderId);
}
if (leaderCounter.incrementAndGet(leaderId) <= leaderCounter.getExpectedAverage()) {
// The num of leaders is less than the expected average, we are going to deal with others
continue;
}
// Find the target peer and try to transfer the leader to this peer
final PeerId targetPeer = findTargetPeer(leaderId, groupId, conf, leaderCounter);
if (!targetPeer.isEmpty()) {
final Status transferStatus = transferLeader(groupId, conf, targetPeer);
transfers++;
if (!transferStatus.isOk()) {
// The failure of `transfer leader` usually means the node is busy,
// so we return failure status and should try `rebalance` again later.
failedStatus = transferStatus;
break;
}
LOG.info("Group {} transfer leader to {}.", groupId, targetPeer);
leaderCounter.decrementAndGet(leaderId);
groupDeque.add(groupId);
if (rebalancedLeaderIds != null) {
rebalancedLeaderIds.put(groupId, targetPeer);
}
}
}
final Status status = failedStatus != null ? failedStatus : Status.OK();
if (LOG.isInfoEnabled()) {
LOG.info("Rebalanced raft groups={}, status={}, number of transfers={}, elapsed time={} ms, rebalanced result={}.", balanceGroupIds, status, transfers, Utils.monotonicMs() - start, rebalancedLeaderIds);
}
return status;
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class CliServiceImpl method transferLeader.
@Override
public Status transferLeader(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");
final PeerId leaderId = new PeerId();
final Status st = checkLeaderAndConnect(groupId, conf, leaderId);
if (!st.isOk()) {
return st;
}
final CliRequests.TransferLeaderRequest.Builder rb = //
CliRequests.TransferLeaderRequest.newBuilder().setGroupId(//
groupId).setLeaderId(leaderId.toString());
if (!peer.isEmpty()) {
rb.setPeerId(peer.toString());
}
try {
final Message result = this.cliClientService.transferLeader(leaderId.getEndpoint(), rb.build(), null).get();
return statusFromResponse(result);
} catch (final Exception e) {
return new Status(-1, e.getMessage());
}
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class CliServiceImpl method resetPeer.
@Override
public Status resetPeer(final String groupId, final PeerId peerId, final Configuration newPeers) {
Requires.requireTrue(!StringUtils.isBlank(groupId), "Blank group id");
Requires.requireNonNull(peerId, "Null peerId");
Requires.requireNonNull(newPeers, "Null new peers");
if (!this.cliClientService.connect(peerId.getEndpoint())) {
return new Status(-1, "Fail to init channel to %s", peerId);
}
final CliRequests.ResetPeerRequest.Builder rb = //
CliRequests.ResetPeerRequest.newBuilder().setGroupId(//
groupId).setPeerId(peerId.toString());
for (final PeerId peer : newPeers) {
rb.addNewPeers(peer.toString());
}
try {
final Message result = this.cliClientService.resetPeer(peerId.getEndpoint(), rb.build(), null).get();
return statusFromResponse(result);
} catch (final Exception e) {
return new Status(-1, e.getMessage());
}
}
Aggregations