use of io.dingodb.raft.entity.LogEntry in project dingo by dingodb.
the class NodeImpl method logEntryFromMeta.
private LogEntry logEntryFromMeta(final long index, final ByteBuffer allData, final RaftOutter.EntryMeta entry) {
if (entry.getType() != EnumOutter.EntryType.ENTRY_TYPE_UNKNOWN) {
final LogEntry logEntry = new LogEntry();
logEntry.setId(new LogId(index, entry.getTerm()));
logEntry.setType(entry.getType());
if (entry.hasChecksum()) {
// since 1.2.6
logEntry.setChecksum(entry.getChecksum());
}
final long dataLen = entry.getDataLen();
if (dataLen > 0) {
final byte[] bs = new byte[(int) dataLen];
assert allData != null;
allData.get(bs, 0, bs.length);
logEntry.setData(ByteBuffer.wrap(bs));
}
if (entry.getPeersCount() > 0) {
if (entry.getType() != EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION) {
throw new IllegalStateException("Invalid log entry that contains peers but is not ENTRY_TYPE_CONFIGURATION type: " + entry.getType());
}
fillLogEntryPeers(entry, logEntry);
} else if (entry.getType() == EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION) {
throw new IllegalStateException("Invalid log entry that contains zero peers but is ENTRY_TYPE_CONFIGURATION type");
}
return logEntry;
}
return null;
}
use of io.dingodb.raft.entity.LogEntry 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);
}
}
use of io.dingodb.raft.entity.LogEntry in project dingo by dingodb.
the class NodeImpl method readCommittedUserLog.
@Override
public UserLog readCommittedUserLog(final long index) {
if (index <= 0) {
throw new LogIndexOutOfBoundsException("Request index is invalid: " + index);
}
final long savedLastAppliedIndex = this.fsmCaller.getLastAppliedIndex();
if (index > savedLastAppliedIndex) {
throw new LogIndexOutOfBoundsException("Request index " + index + " is greater than lastAppliedIndex: " + savedLastAppliedIndex);
}
long curIndex = index;
LogEntry entry = this.logManager.getEntry(curIndex);
if (entry == null) {
throw new LogNotFoundException("User log is deleted at index: " + index);
}
do {
if (entry.getType() == EnumOutter.EntryType.ENTRY_TYPE_DATA) {
return new UserLog(curIndex, entry.getData());
} else {
curIndex++;
}
if (curIndex > savedLastAppliedIndex) {
throw new IllegalStateException("No user log between index:" + index + " and last_applied_index:" + savedLastAppliedIndex);
}
entry = this.logManager.getEntry(curIndex);
} while (entry != null);
throw new LogNotFoundException("User log is deleted at index: " + curIndex);
}
use of io.dingodb.raft.entity.LogEntry in project dingo by dingodb.
the class V2Decoder method decode.
@Override
public LogEntry decode(final byte[] bs) {
if (bs == null || bs.length < LogEntryV2CodecFactory.HEADER_SIZE) {
return null;
}
int i = 0;
for (; i < LogEntryV2CodecFactory.MAGIC_BYTES.length; i++) {
if (bs[i] != LogEntryV2CodecFactory.MAGIC_BYTES[i]) {
return null;
}
}
if (bs[i++] != LogEntryV2CodecFactory.VERSION) {
return null;
}
// Ignored reserved
i += LogEntryV2CodecFactory.RESERVED.length;
try {
final LogOutter.PBLogEntry entry = LogOutter.PBLogEntry.parseFrom(ZeroByteStringHelper.wrap(bs, i, bs.length - i));
final LogEntry log = new LogEntry();
log.setType(entry.getType());
log.getId().setIndex(entry.getIndex());
log.getId().setTerm(entry.getTerm());
if (entry.hasChecksum()) {
log.setChecksum(entry.getChecksum());
}
if (entry.getPeersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getPeersCount());
for (final ByteString bstring : entry.getPeersList()) {
peers.add(JRaftUtils.getPeerId(AsciiStringUtil.unsafeDecode(bstring)));
}
log.setPeers(peers);
}
if (entry.getOldPeersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getOldPeersCount());
for (final ByteString bstring : entry.getOldPeersList()) {
peers.add(JRaftUtils.getPeerId(AsciiStringUtil.unsafeDecode(bstring)));
}
log.setOldPeers(peers);
}
if (entry.getLearnersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getLearnersCount());
for (final ByteString bstring : entry.getLearnersList()) {
peers.add(JRaftUtils.getPeerId(AsciiStringUtil.unsafeDecode(bstring)));
}
log.setLearners(peers);
}
if (entry.getOldLearnersCount() > 0) {
final List<PeerId> peers = new ArrayList<>(entry.getOldLearnersCount());
for (final ByteString bstring : entry.getOldLearnersList()) {
peers.add(JRaftUtils.getPeerId(AsciiStringUtil.unsafeDecode(bstring)));
}
log.setOldLearners(peers);
}
final ByteString data = entry.getData();
if (!data.isEmpty()) {
log.setData(ByteBuffer.wrap(ZeroByteStringHelper.getByteArray(data)));
}
return log;
} catch (final InvalidProtocolBufferException e) {
LOG.error("Fail to decode pb log entry", e);
return null;
}
}
use of io.dingodb.raft.entity.LogEntry in project dingo by dingodb.
the class LogManagerImpl method getTermFromLogStorage.
private long getTermFromLogStorage(final long index) {
final LogEntry entry = this.logStorage.getEntry(index);
if (entry != null) {
if (this.raftOptions.isEnableLogEntryChecksum() && entry.isCorrupted()) {
// Report error to node and throw exception.
final String msg = String.format("The log entry is corrupted, index=%d, term=%d, expectedChecksum=%d, realChecksum=%d", entry.getId().getIndex(), entry.getId().getTerm(), entry.getChecksum(), entry.checksum());
reportError(RaftError.EIO.getNumber(), msg);
throw new LogEntryCorruptedException(msg);
}
return entry.getId().getTerm();
}
return 0;
}
Aggregations