Search in sources :

Example 1 with LogEntry

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;
}
Also used : LogId(io.dingodb.raft.entity.LogId) LogEntry(io.dingodb.raft.entity.LogEntry)

Example 2 with LogEntry

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);
    }
}
Also used : Status(io.dingodb.raft.Status) RaftOutter(io.dingodb.raft.entity.RaftOutter) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) LogEntry(io.dingodb.raft.entity.LogEntry) PeerId(io.dingodb.raft.entity.PeerId)

Example 3 with LogEntry

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);
}
Also used : UserLog(io.dingodb.raft.entity.UserLog) LogIndexOutOfBoundsException(io.dingodb.raft.error.LogIndexOutOfBoundsException) LogNotFoundException(io.dingodb.raft.error.LogNotFoundException) LogEntry(io.dingodb.raft.entity.LogEntry)

Example 4 with LogEntry

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;
    }
}
Also used : ByteString(com.google.protobuf.ByteString) ArrayList(java.util.ArrayList) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) LogEntry(io.dingodb.raft.entity.LogEntry) PeerId(io.dingodb.raft.entity.PeerId)

Example 5 with LogEntry

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;
}
Also used : LogEntry(io.dingodb.raft.entity.LogEntry) LogEntryCorruptedException(io.dingodb.raft.error.LogEntryCorruptedException)

Aggregations

LogEntry (io.dingodb.raft.entity.LogEntry)23 LogId (io.dingodb.raft.entity.LogId)11 ArrayList (java.util.ArrayList)8 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)7 Status (io.dingodb.raft.Status)6 PeerId (io.dingodb.raft.entity.PeerId)6 Configuration (io.dingodb.raft.conf.Configuration)5 ConfigurationEntry (io.dingodb.raft.conf.ConfigurationEntry)4 ConfigurationManager (io.dingodb.raft.conf.ConfigurationManager)4 RaftOptions (io.dingodb.raft.option.RaftOptions)4 Disruptor (com.lmax.disruptor.dsl.Disruptor)3 ProducerType (com.lmax.disruptor.dsl.ProducerType)3 Closure (io.dingodb.raft.Closure)3 FSMCaller (io.dingodb.raft.FSMCaller)3 SynchronizedClosure (io.dingodb.raft.closure.SynchronizedClosure)3 RaftError (io.dingodb.raft.error.RaftError)3 RaftException (io.dingodb.raft.error.RaftException)3 LogManagerOptions (io.dingodb.raft.option.LogManagerOptions)3 NodeOptions (io.dingodb.raft.option.NodeOptions)3 LogManager (io.dingodb.raft.storage.LogManager)3