Search in sources :

Example 1 with AppendEntriesResponseBuilder

use of org.apache.ignite.raft.jraft.rpc.AppendEntriesResponseBuilder in project ignite-3 by apache.

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 = Utils.size(request.entriesList());
    try {
        if (!this.state.isActive()) {
            LOG.warn("Node {} is not in active state, currTerm={}.", getNodeId(), this.currTerm);
            return // 
            RaftRpcFactory.DEFAULT.newResponse(raftOptions.getRaftMessagesFactory(), RaftError.EINVAL, "Node %s is not in active state, state %s.", getNodeId(), this.state.name());
        }
        final PeerId serverId = new PeerId();
        if (!serverId.parse(request.serverId())) {
            LOG.warn("Node {} received AppendEntriesRequest from {} serverId bad format.", getNodeId(), request.serverId());
            return // 
            RaftRpcFactory.DEFAULT.newResponse(raftOptions.getRaftMessagesFactory(), RaftError.EINVAL, "Parse serverId failed: %s.", request.serverId());
        }
        // Check stale term
        if (request.term() < this.currTerm) {
            LOG.warn("Node {} ignore stale AppendEntriesRequest from {}, term={}, currTerm={}.", getNodeId(), request.serverId(), request.term(), this.currTerm);
            return raftOptions.getRaftMessagesFactory().appendEntriesResponse().success(false).term(this.currTerm).build();
        }
        // Check term and state to step down
        checkStepDown(request.term(), 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.term() + 1, false, new Status(RaftError.ELEADERCONFLICT, "More than one leader in the same term."));
            return raftOptions.getRaftMessagesFactory().appendEntriesResponse().success(// 
            false).term(// 
            request.term() + 1).build();
        }
        updateLastLeaderTimestamp(Utils.monotonicMs());
        if (entriesCount > 0 && this.snapshotExecutor != null && this.snapshotExecutor.isInstallingSnapshot()) {
            LOG.warn("Node {} received AppendEntriesRequest while installing snapshot.", getNodeId());
            return // 
            RaftRpcFactory.DEFAULT.newResponse(raftOptions.getRaftMessagesFactory(), RaftError.EBUSY, "Node %s:%s is installing snapshot.", this.groupId, this.serverId);
        }
        final long prevLogIndex = request.prevLogIndex();
        final long prevLogTerm = request.prevLogTerm();
        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.serverId(), request.term(), prevLogIndex, prevLogTerm, localPrevLogTerm, lastLogIndex, entriesCount);
            return raftOptions.getRaftMessagesFactory().appendEntriesResponse().success(false).term(this.currTerm).lastLogIndex(lastLogIndex).build();
        }
        if (entriesCount == 0) {
            // heartbeat or probe request
            final AppendEntriesResponseBuilder respBuilder = raftOptions.getRaftMessagesFactory().appendEntriesResponse().success(true).term(this.currTerm).lastLogIndex(this.logManager.getLastLogIndex());
            doUnlock = false;
            this.writeLock.unlock();
            // see the comments at FollowerStableClosure#run()
            this.ballotBox.setLastCommittedIndex(Math.min(request.committedIndex(), prevLogIndex));
            return respBuilder.build();
        }
        // Parse request
        long index = prevLogIndex;
        final List<LogEntry> entries = new ArrayList<>(entriesCount);
        ByteBuffer allData = request.data() != null ? request.data().asReadOnlyByteBuffer() : ByteString.EMPTY.asReadOnlyByteBuffer();
        final Collection<RaftOutter.EntryMeta> entriesList = request.entriesList();
        for (RaftOutter.EntryMeta entry : entriesList) {
            index++;
            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 // 
                    RaftRpcFactory.DEFAULT.newResponse(raftOptions.getRaftMessagesFactory(), 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, raftOptions.getRaftMessagesFactory().appendEntriesResponse().term(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);
    }
}
Also used : Status(org.apache.ignite.raft.jraft.Status) RaftOutter(org.apache.ignite.raft.jraft.entity.RaftOutter) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) AppendEntriesResponseBuilder(org.apache.ignite.raft.jraft.rpc.AppendEntriesResponseBuilder) LogEntry(org.apache.ignite.raft.jraft.entity.LogEntry) PeerId(org.apache.ignite.raft.jraft.entity.PeerId)

Aggregations

ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)1 Status (org.apache.ignite.raft.jraft.Status)1 LogEntry (org.apache.ignite.raft.jraft.entity.LogEntry)1 PeerId (org.apache.ignite.raft.jraft.entity.PeerId)1 RaftOutter (org.apache.ignite.raft.jraft.entity.RaftOutter)1 AppendEntriesResponseBuilder (org.apache.ignite.raft.jraft.rpc.AppendEntriesResponseBuilder)1