use of io.dingodb.raft.Status in project dingo by dingodb.
the class Replicator method installSnapshot.
void installSnapshot() {
if (getState() == State.Snapshot) {
LOG.warn("Replicator {} is installing snapshot, ignore the new request.", this.options.getPeerId());
unlockId();
return;
}
boolean doUnlock = true;
if (!rpcService.connect(options.getPeerId().getEndpoint())) {
LOG.error("Fail to check install snapshot connection to peer={}, give up to send install snapshot request.", options.getPeerId().getEndpoint());
block(Utils.nowMs(), RaftError.EHOSTDOWN.getNumber());
return;
}
try {
Requires.requireTrue(this.reader == null, "Replicator %s already has a snapshot reader, current state is %s", this.options.getPeerId(), getState());
this.reader = this.options.getSnapshotStorage().open();
if (this.reader == null) {
final NodeImpl node = this.options.getNode();
final RaftException error = new RaftException(EnumOutter.ErrorType.ERROR_TYPE_SNAPSHOT);
error.setStatus(new Status(RaftError.EIO, "Fail to open snapshot"));
unlockId();
doUnlock = false;
node.onError(error);
return;
}
final String uri = this.reader.generateURIForCopy();
if (uri == null) {
final NodeImpl node = this.options.getNode();
final RaftException error = new RaftException(EnumOutter.ErrorType.ERROR_TYPE_SNAPSHOT);
error.setStatus(new Status(RaftError.EIO, "Fail to generate uri for snapshot reader"));
releaseReader();
unlockId();
doUnlock = false;
node.onError(error);
return;
}
final RaftOutter.SnapshotMeta meta = this.reader.load();
if (meta == null) {
final String snapshotPath = this.reader.getPath();
final NodeImpl node = this.options.getNode();
final RaftException error = new RaftException(EnumOutter.ErrorType.ERROR_TYPE_SNAPSHOT);
error.setStatus(new Status(RaftError.EIO, "Fail to load meta from %s", snapshotPath));
releaseReader();
unlockId();
doUnlock = false;
node.onError(error);
return;
}
final RpcRequests.InstallSnapshotRequest.Builder rb = RpcRequests.InstallSnapshotRequest.newBuilder();
rb.setTerm(this.options.getTerm());
rb.setGroupId(this.options.getGroupId());
rb.setServerId(this.options.getServerId().toString());
rb.setPeerId(this.options.getPeerId().toString());
rb.setMeta(meta);
rb.setUri(uri);
this.statInfo.runningState = RunningState.INSTALLING_SNAPSHOT;
this.statInfo.lastLogIncluded = meta.getLastIncludedIndex();
this.statInfo.lastTermIncluded = meta.getLastIncludedTerm();
final RpcRequests.InstallSnapshotRequest request = rb.build();
setState(State.Snapshot);
// noinspection NonAtomicOperationOnVolatileField
this.installSnapshotCounter++;
final long monotonicSendTimeMs = Utils.monotonicMs();
final int stateVersion = this.version;
final int seq = getAndIncrementReqSeq();
final Future<Message> rpcFuture = this.rpcService.installSnapshot(this.options.getPeerId().getEndpoint(), request, new RpcResponseClosureAdapter<RpcRequests.InstallSnapshotResponse>() {
@Override
public void run(final Status status) {
onRpcReturned(Replicator.this.id, RequestType.Snapshot, status, request, getResponse(), seq, stateVersion, monotonicSendTimeMs);
}
});
addInflight(RequestType.Snapshot, this.nextIndex, 0, 0, seq, rpcFuture);
} finally {
if (doUnlock) {
unlockId();
}
}
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class Replicator method onAppendEntriesReturned.
private static boolean onAppendEntriesReturned(final ThreadId id, final Inflight inflight, final Status status, final RpcRequests.AppendEntriesRequest request, final RpcRequests.AppendEntriesResponse response, final long rpcSendTime, final long startTimeMs, final Replicator r) {
if (inflight.startIndex != request.getPrevLogIndex() + 1) {
LOG.warn("Replicator {} received invalid AppendEntriesResponse, in-flight startIndex={}, request prevLogIndex={}, reset the replicator state and probe again.", r, inflight.startIndex, request.getPrevLogIndex());
r.resetInflights();
r.setState(State.Probe);
// unlock id in sendEmptyEntries
r.sendProbeRequest();
return false;
}
// record metrics
if (request.getEntriesCount() > 0) {
r.nodeMetrics.recordLatency("replicate-entries", Utils.monotonicMs() - rpcSendTime);
r.nodeMetrics.recordSize("replicate-entries-count", request.getEntriesCount());
r.nodeMetrics.recordSize("replicate-entries-bytes", request.getData() != null ? request.getData().size() : 0);
}
final boolean isLogDebugEnabled = LOG.isDebugEnabled();
StringBuilder sb = null;
if (isLogDebugEnabled) {
sb = //
new StringBuilder("Node ").append(//
r.options.getGroupId()).append(//
':').append(//
r.options.getServerId()).append(//
" received AppendEntriesResponse from ").append(//
r.options.getPeerId()).append(//
" prevLogIndex=").append(//
request.getPrevLogIndex()).append(//
" prevLogTerm=").append(//
request.getPrevLogTerm()).append(//
" count=").append(request.getEntriesCount());
}
if (!status.isOk()) {
// dummy_id is unlock in block
if (isLogDebugEnabled) {
//
sb.append(" fail, sleep, status=").append(status);
LOG.debug(sb.toString());
}
notifyReplicatorStatusListener(r, ReplicatorEvent.ERROR, status);
if (++r.consecutiveErrorTimes % 10 == 0) {
LOG.warn("Fail to issue RPC to {}, consecutiveErrorTimes={}, error={}", r.options.getPeerId(), r.consecutiveErrorTimes, status);
}
r.resetInflights();
r.setState(State.Probe);
// unlock in in block
r.block(startTimeMs, status.getCode());
return false;
}
r.consecutiveErrorTimes = 0;
if (!response.getSuccess()) {
if (response.getTerm() > r.options.getTerm()) {
if (isLogDebugEnabled) {
//
sb.append(" fail, greater term ").append(//
response.getTerm()).append(//
" expect term ").append(r.options.getTerm());
LOG.debug(sb.toString());
}
final NodeImpl node = r.options.getNode();
r.notifyOnCaughtUp(RaftError.EPERM.getNumber(), true);
r.destroy();
node.increaseTermTo(response.getTerm(), new Status(RaftError.EHIGHERTERMRESPONSE, "Leader receives higher term heartbeat_response from peer:%s", r.options.getPeerId()));
return false;
}
if (isLogDebugEnabled) {
sb.append(" fail, find nextIndex remote lastLogIndex ").append(response.getLastLogIndex()).append(" local nextIndex ").append(r.nextIndex);
LOG.debug(sb.toString());
}
if (rpcSendTime > r.lastRpcSendTimestamp) {
r.lastRpcSendTimestamp = rpcSendTime;
}
// Fail, reset the state to try again from nextIndex.
r.resetInflights();
// prev_log_index and prev_log_term doesn't match
if (response.getLastLogIndex() + 1 < r.nextIndex) {
LOG.debug("LastLogIndex at peer={} is {}", r.options.getPeerId(), response.getLastLogIndex());
// The peer contains less logs than leader
r.nextIndex = response.getLastLogIndex() + 1;
} else {
// decrease _last_log_at_peer by one to test the right index to keep
if (r.nextIndex > 1) {
LOG.debug("logIndex={} dismatch", r.nextIndex);
r.nextIndex--;
} else {
LOG.error("Peer={} declares that log at index=0 doesn't match, which is not supposed to happen", r.options.getPeerId());
}
}
// dummy_id is unlock in _send_heartbeat
r.sendProbeRequest();
return false;
}
if (isLogDebugEnabled) {
sb.append(", success");
LOG.debug(sb.toString());
}
// success
if (response.getTerm() != r.options.getTerm()) {
r.resetInflights();
r.setState(State.Probe);
LOG.error("Fail, response term {} dismatch, expect term {}", response.getTerm(), r.options.getTerm());
id.unlock();
return false;
}
if (rpcSendTime > r.lastRpcSendTimestamp) {
r.lastRpcSendTimestamp = rpcSendTime;
}
final int entriesSize = request.getEntriesCount();
if (entriesSize > 0) {
if (r.options.getReplicatorType().isFollower()) {
// Only commit index when the response is from follower.
r.options.getBallotBox().commitAt(r.nextIndex, r.nextIndex + entriesSize - 1, r.options.getPeerId());
}
if (LOG.isDebugEnabled()) {
LOG.debug("Replicated logs in [{}, {}] to peer {}", r.nextIndex, r.nextIndex + entriesSize - 1, r.options.getPeerId());
}
}
r.setState(State.Replicate);
r.blockTimer = null;
r.nextIndex += entriesSize;
r.hasSucceeded = true;
r.notifyOnCaughtUp(RaftError.SUCCESS.getNumber(), false);
// dummy_id is unlock in _send_entries
if (r.timeoutNowIndex > 0 && r.timeoutNowIndex < r.nextIndex) {
r.sendTimeoutNow(false, false);
}
return true;
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class BaseCliRequestProcessor method processRequest.
@Override
public Message processRequest(T request, RpcRequestClosure done) {
String groupId = getGroupId(request);
String peerIdStr = getPeerId(request);
PeerId peerId = null;
if (!StringUtils.isBlank(peerIdStr)) {
peerId = new PeerId();
if (!peerId.parse(peerIdStr)) {
return //
RpcFactoryHelper.responseFactory().newResponse(defaultResp(), RaftError.EINVAL, "Fail to parse peer: %s", peerIdStr);
}
}
Status st = new Status();
Node node = getNode(groupId, peerId, st);
if (!st.isOk()) {
return //
RpcFactoryHelper.responseFactory().newResponse(defaultResp(), st.getCode(), st.getErrorMsg());
} else {
return processRequest0(new CliRequestContext(node, groupId, peerId), request, done);
}
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class AbstractClientService method handleErrorResponse.
private static Status handleErrorResponse(final RpcRequests.ErrorResponse eResp) {
final Status status = new Status();
status.setCode(eResp.getErrorCode());
if (eResp.hasErrorMsg()) {
status.setErrorMsg(eResp.getErrorMsg());
}
return status;
}
use of io.dingodb.raft.Status in project dingo by dingodb.
the class LogManagerImpl method checkConsistency.
@Override
public Status checkConsistency() {
this.readLock.lock();
try {
Requires.requireTrue(this.firstLogIndex > 0);
Requires.requireTrue(this.lastLogIndex >= 0);
if (this.lastSnapshotId.equals(new LogId(0, 0))) {
if (this.firstLogIndex == 1) {
return Status.OK();
}
return new Status(RaftError.EIO, "Missing logs in (0, %d)", this.firstLogIndex);
} else {
if (this.lastSnapshotId.getIndex() >= this.firstLogIndex - 1 && this.lastSnapshotId.getIndex() <= this.lastLogIndex) {
return Status.OK();
}
return new Status(RaftError.EIO, "There's a gap between snapshot={%d, %d} and log=[%d, %d] ", this.lastSnapshotId.toString(), this.lastSnapshotId.getTerm(), this.firstLogIndex, this.lastLogIndex);
}
} finally {
this.readLock.unlock();
}
}
Aggregations