use of com.alipay.sofa.jraft.entity.LogEntry in project sofa-jraft by sofastack.
the class NodeImpl method unsafeApplyConfiguration.
private void unsafeApplyConfiguration(final Configuration newConf, final Configuration oldConf, final boolean leaderStart) {
Requires.requireTrue(this.confCtx.isBusy(), "ConfigurationContext is not busy");
final LogEntry entry = new LogEntry(EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION);
entry.setId(new LogId(0, this.currTerm));
entry.setPeers(newConf.listPeers());
entry.setLearners(newConf.listLearners());
if (oldConf != null) {
entry.setOldPeers(oldConf.listPeers());
entry.setOldLearners(oldConf.listLearners());
}
final ConfigurationChangeDone configurationChangeDone = new ConfigurationChangeDone(this.currTerm, leaderStart);
// Use the new_conf to deal the quorum of this very log
if (!this.ballotBox.appendPendingTask(newConf, oldConf, configurationChangeDone)) {
Utils.runClosureInThread(configurationChangeDone, new Status(RaftError.EINTERNAL, "Fail to append task."));
return;
}
final List<LogEntry> entries = new ArrayList<>();
entries.add(entry);
this.logManager.appendEntries(entries, new LeaderStableClosure(entries));
checkAndSetConfiguration(false);
}
use of com.alipay.sofa.jraft.entity.LogEntry in project sofa-jraft by sofastack.
the class Replicator method prepareEntry.
boolean prepareEntry(final long nextSendingIndex, final int offset, final RaftOutter.EntryMeta.Builder emb, final RecyclableByteBufferList dateBuffer) {
if (dateBuffer.getCapacity() >= this.raftOptions.getMaxBodySize()) {
return false;
}
final long logIndex = nextSendingIndex + offset;
final LogEntry entry = this.options.getLogManager().getEntry(logIndex);
if (entry == null) {
return false;
}
emb.setTerm(entry.getId().getTerm());
if (entry.hasChecksum()) {
// since 1.2.6
emb.setChecksum(entry.getChecksum());
}
emb.setType(entry.getType());
if (entry.getPeers() != null) {
Requires.requireTrue(!entry.getPeers().isEmpty(), "Empty peers at logIndex=%d", logIndex);
fillMetaPeers(emb, entry);
} else {
Requires.requireTrue(entry.getType() != EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION, "Empty peers but is ENTRY_TYPE_CONFIGURATION type at logIndex=%d", logIndex);
}
final int remaining = entry.getData() != null ? entry.getData().remaining() : 0;
emb.setDataLen(remaining);
if (entry.getData() != null) {
// should slice entry data
dateBuffer.add(entry.getData().slice());
}
return true;
}
use of com.alipay.sofa.jraft.entity.LogEntry in project sofa-jraft by sofastack.
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 com.alipay.sofa.jraft.entity.LogEntry in project sofa-jraft by sofastack.
the class NodeImpl method handleAppendEntriesRequest.
@Override
public Message handleAppendEntriesRequest(final AppendEntriesRequest request, final RpcRequestClosure done) {
boolean doUnlock = true;
final long startMs = Utils.monotonicMs();
this.writeLock.lock();
final int entriesCount = request.getEntriesCount();
boolean success = false;
try {
if (!this.state.isActive()) {
LOG.warn("Node {} is not in active state, currTerm={}.", getNodeId(), this.currTerm);
return //
RpcFactoryHelper.responseFactory().newResponse(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(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 //
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 //
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(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 //
AppendEntriesResponse.newBuilder().setSuccess(//
false).setTerm(//
this.currTerm).setLastLogIndex(//
lastLogIndex).build();
}
if (entriesCount == 0) {
// heartbeat or probe request
final AppendEntriesResponse.Builder respBuilder = //
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();
}
// fast checking if log manager is overloaded
if (!this.logManager.hasAvailableCapacityToAppendEntries(1)) {
LOG.warn("Node {} received AppendEntriesRequest but log manager is busy.", getNodeId());
return //
RpcFactoryHelper.responseFactory().newResponse(AppendEntriesResponse.getDefaultInstance(), RaftError.EBUSY, "Node %s:%s log manager is busy.", this.groupId, this.serverId);
}
// 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(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, 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);
success = true;
return null;
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
final long processLatency = Utils.monotonicMs() - startMs;
if (entriesCount == 0) {
this.metrics.recordLatency("handle-heartbeat-requests", processLatency);
} else {
this.metrics.recordLatency("handle-append-entries", processLatency);
}
if (success) {
// Don't stats heartbeat requests.
this.metrics.recordSize("handle-append-entries-count", entriesCount);
}
}
}
use of com.alipay.sofa.jraft.entity.LogEntry in project sofa-jraft by sofastack.
the class V1Decoder method decode.
@Override
public LogEntry decode(final byte[] content) {
if (content == null || content.length == 0) {
return null;
}
if (content[0] != LogEntryV1CodecFactory.MAGIC) {
// Corrupted log
return null;
}
LogEntry log = new LogEntry();
decode(log, content);
return log;
}
Aggregations