use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class CliServiceImpl method removeLearners.
@Override
public Status removeLearners(final String groupId, final Configuration conf, final List<PeerId> learners) {
checkLearnersOpParams(groupId, conf, learners);
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);
}
final CliRequests.RemoveLearnersRequest.Builder rb = //
CliRequests.RemoveLearnersRequest.newBuilder().setGroupId(//
groupId).setLeaderId(leaderId.toString());
for (final PeerId peer : learners) {
rb.addLearners(peer.toString());
}
try {
final Message result = this.cliClientService.removeLearners(leaderId.getEndpoint(), rb.build(), null).get();
return processLearnersOpResponse(groupId, result, "removing learners: %s", learners);
} catch (final Exception e) {
return new Status(-1, e.getMessage());
}
}
use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class NodeImpl method checkPeers.
private void checkPeers(final List<PeerId> peers) {
Requires.requireNonNull(peers, "Null peers");
Requires.requireTrue(!peers.isEmpty(), "Empty peers");
for (final PeerId peer : peers) {
Requires.requireNonNull(peer, "Null peer");
}
}
use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class NodeImpl method preVote.
// in writeLock
private void preVote() {
long oldTerm;
try {
LOG.info("Node {} term {} start preVote.", getNodeId(), this.currTerm);
if (this.snapshotExecutor != null && this.snapshotExecutor.isInstallingSnapshot()) {
LOG.warn("Node {} term {} doesn't do preVote when installing snapshot as the configuration may be out of date.", getNodeId(), this.currTerm);
return;
}
if (!this.conf.contains(this.serverId)) {
LOG.warn("Node {} can't do preVote as it is not in conf <{}>.", getNodeId(), this.conf);
return;
}
oldTerm = this.currTerm;
} finally {
this.writeLock.unlock();
}
final LogId lastLogId = this.logManager.getLastLogId(true);
boolean doUnlock = true;
this.writeLock.lock();
try {
// pre_vote need defense ABA after unlock&writeLock
if (oldTerm != this.currTerm) {
LOG.warn("Node {} raise term {} when get lastLogId.", getNodeId(), this.currTerm);
return;
}
this.prevVoteCtx.init(this.conf.getConf(), this.conf.isStable() ? null : this.conf.getOldConf());
for (final PeerId peer : this.conf.listPeers()) {
if (peer.equals(this.serverId)) {
continue;
}
if (!this.rpcService.connect(peer.getEndpoint())) {
LOG.warn("Node {} channel init failed, address={}.", getNodeId(), peer.getEndpoint());
continue;
}
final OnPreVoteRpcDone done = new OnPreVoteRpcDone(peer, this.currTerm);
done.request = //
RpcRequests.RequestVoteRequest.newBuilder().setPreVote(// it's a pre-vote request.
true).setGroupId(//
this.groupId).setServerId(//
this.serverId.toString()).setPeerId(//
peer.toString()).setTerm(// next term
this.currTerm + 1).setLastLogIndex(//
lastLogId.getIndex()).setLastLogTerm(//
lastLogId.getTerm()).build();
this.rpcService.preVote(peer.getEndpoint(), done.request, done);
}
this.prevVoteCtx.grant(this.serverId);
if (this.prevVoteCtx.isGranted()) {
doUnlock = false;
electSelf();
}
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
}
}
use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class NodeImpl method handleInstallSnapshot.
@Override
public Message handleInstallSnapshot(final RpcRequests.InstallSnapshotRequest request, final RpcRequestClosure done) {
if (this.snapshotExecutor == null) {
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.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(RpcRequests.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(RpcRequests.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 //
RpcRequests.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 //
RpcRequests.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, RpcRequests.InstallSnapshotResponse.newBuilder(), done);
return null;
} finally {
this.metrics.recordLatency("install-snapshot", Utils.monotonicMs() - startMs);
}
}
use of io.dingodb.raft.entity.PeerId in project dingo by dingodb.
the class NodeImpl method handleAppendEntriesRequest.
@Override
public Message handleAppendEntriesRequest(final RpcRequests.AppendEntriesRequest request, final RpcRequestClosure done) {
boolean doUnlock = true;
final long startMs = Utils.monotonicMs();
this.writeLock.lock();
final int entriesCount = request.getEntriesCount();
try {
if (!this.state.isActive()) {
LOG.warn("Node {} is not in active state, currTerm={}.", getNodeId(), this.currTerm);
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.AppendEntriesResponse.getDefaultInstance(), RaftError.EINVAL, "Node %s is not in active state, state %s.", getNodeId(), this.state.name());
}
final PeerId serverId = new PeerId();
if (!serverId.parse(request.getServerId())) {
LOG.warn("Node {} received AppendEntriesRequest from {} serverId bad format.", getNodeId(), request.getServerId());
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.AppendEntriesResponse.getDefaultInstance(), RaftError.EINVAL, "Parse serverId failed: %s.", request.getServerId());
}
// Check stale term
if (request.getTerm() < this.currTerm) {
LOG.warn("Node {} ignore stale AppendEntriesRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
return //
RpcRequests.AppendEntriesResponse.newBuilder().setSuccess(//
false).setTerm(//
this.currTerm).build();
}
// Check term and state to step down
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 //
RpcRequests.AppendEntriesResponse.newBuilder().setSuccess(//
false).setTerm(//
request.getTerm() + 1).build();
}
updateLastLeaderTimestamp(Utils.monotonicMs());
if (entriesCount > 0 && this.snapshotExecutor != null && this.snapshotExecutor.isInstallingSnapshot()) {
LOG.warn("Node {} received AppendEntriesRequest while installing snapshot.", getNodeId());
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.AppendEntriesResponse.getDefaultInstance(), RaftError.EBUSY, "Node %s:%s is installing snapshot.", this.groupId, this.serverId);
}
final long prevLogIndex = request.getPrevLogIndex();
final long prevLogTerm = request.getPrevLogTerm();
final long localPrevLogTerm = this.logManager.getTerm(prevLogIndex);
if (localPrevLogTerm != prevLogTerm) {
final long lastLogIndex = this.logManager.getLastLogIndex();
LOG.warn("Node {} reject term_unmatched AppendEntriesRequest from {}, term={}, prevLogIndex={}, prevLogTerm={}, localPrevLogTerm={}, lastLogIndex={}, entriesSize={}.", getNodeId(), request.getServerId(), request.getTerm(), prevLogIndex, prevLogTerm, localPrevLogTerm, lastLogIndex, entriesCount);
return //
RpcRequests.AppendEntriesResponse.newBuilder().setSuccess(//
false).setTerm(//
this.currTerm).setLastLogIndex(//
lastLogIndex).build();
}
if (entriesCount == 0) {
// heartbeat or probe request
final RpcRequests.AppendEntriesResponse.Builder respBuilder = //
RpcRequests.AppendEntriesResponse.newBuilder().setSuccess(//
true).setTerm(//
this.currTerm).setLastLogIndex(this.logManager.getLastLogIndex());
doUnlock = false;
this.writeLock.unlock();
// see the comments at FollowerStableClosure#run()
this.ballotBox.setLastCommittedIndex(Math.min(request.getCommittedIndex(), prevLogIndex));
return respBuilder.build();
}
// Parse request
long index = prevLogIndex;
final List<LogEntry> entries = new ArrayList<>(entriesCount);
ByteBuffer allData = null;
if (request.hasData()) {
allData = request.getData().asReadOnlyByteBuffer();
}
final List<RaftOutter.EntryMeta> entriesList = request.getEntriesList();
for (int i = 0; i < entriesCount; i++) {
index++;
final RaftOutter.EntryMeta entry = entriesList.get(i);
final LogEntry logEntry = logEntryFromMeta(index, allData, entry);
if (logEntry != null) {
// Validate checksum
if (this.raftOptions.isEnableLogEntryChecksum() && logEntry.isCorrupted()) {
long realChecksum = logEntry.checksum();
LOG.error("Corrupted log entry received from leader, index={}, term={}, expectedChecksum={}, realChecksum={}", logEntry.getId().getIndex(), logEntry.getId().getTerm(), logEntry.getChecksum(), realChecksum);
return //
RpcFactoryHelper.responseFactory().newResponse(RpcRequests.AppendEntriesResponse.getDefaultInstance(), RaftError.EINVAL, "The log entry is corrupted, index=%d, term=%d, expectedChecksum=%d, realChecksum=%d", logEntry.getId().getIndex(), logEntry.getId().getTerm(), logEntry.getChecksum(), realChecksum);
}
entries.add(logEntry);
}
}
final FollowerStableClosure closure = new FollowerStableClosure(request, RpcRequests.AppendEntriesResponse.newBuilder().setTerm(this.currTerm), this, done, this.currTerm);
this.logManager.appendEntries(entries, closure);
// update configuration after _log_manager updated its memory status
checkAndSetConfiguration(true);
return null;
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
this.metrics.recordLatency("handle-append-entries", Utils.monotonicMs() - startMs);
this.metrics.recordSize("handle-append-entries-count", entriesCount);
}
}
Aggregations