use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class NodeImpl method addLearners.
@Override
public void addLearners(final List<PeerId> learners, final Closure done) {
checkPeers(learners);
this.writeLock.lock();
try {
final Configuration newConf = new Configuration(this.conf.getConf());
for (final PeerId peer : learners) {
newConf.addLearner(peer);
}
unsafeRegisterConfChange(this.conf.getConf(), newConf, done);
} finally {
this.writeLock.unlock();
}
}
use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
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 io.dingodb.raft.entity.PeerId 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.entity.PeerId in project dingo by dingodb.
the class Configuration method parse.
public boolean parse(final String conf) {
if (StringUtils.isBlank(conf)) {
return false;
}
reset();
final String[] peerStrs = StringUtils.split(conf, ',');
for (String peerStr : peerStrs) {
final PeerId peer = new PeerId();
int index;
boolean isLearner = false;
if ((index = peerStr.indexOf(LEARNER_POSTFIX)) > 0) {
// It's a learner
peerStr = peerStr.substring(0, index);
isLearner = true;
}
if (peer.parse(peerStr)) {
if (isLearner) {
addLearner(peer);
} else {
addPeer(peer);
}
} else {
LOG.error("Fail to parse peer {} in {}, ignore it.", peerStr, conf);
}
}
return true;
}
use of io.dingodb.raft.entity.PeerId 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;
}
Aggregations