Search in sources :

Example 26 with Status

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

the class ReadOnlyServiceImpl method join.

@Override
public void join() throws InterruptedException {
    if (this.shutdownLatch != null) {
        this.shutdownLatch.await();
    }
    this.readIndexDisruptor.unsubscribe(groupId);
    resetPendingStatusError(new Status(RaftError.ESTOP, "Node is quit."));
}
Also used : Status(org.apache.ignite.raft.jraft.Status) ReadIndexStatus(org.apache.ignite.raft.jraft.entity.ReadIndexStatus)

Example 27 with Status

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

the class Replicator method sendHeartbeat.

public static void sendHeartbeat(final ThreadId id, final RpcResponseClosure<AppendEntriesResponse> closure, ExecutorService executor) {
    final Replicator r = (Replicator) id.lock();
    if (r == null) {
        Utils.runClosureInThread(executor, closure, new Status(RaftError.EHOSTDOWN, "Peer %s is not connected", id));
        return;
    }
    // id unlock in send empty entries.
    r.sendEmptyEntries(true, closure);
}
Also used : Status(org.apache.ignite.raft.jraft.Status)

Example 28 with Status

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

the class Replicator method sendEntries.

/**
 * Send log entries to follower, returns true when success, otherwise false and unlock the id.
 *
 * @param nextSendingIndex next sending index
 * @return send result.
 */
private boolean sendEntries(final long nextSendingIndex) {
    final AppendEntriesRequestBuilder rb = raftOptions.getRaftMessagesFactory().appendEntriesRequest();
    if (!fillCommonFields(rb, nextSendingIndex - 1, false)) {
        // unlock id in installSnapshot
        installSnapshot();
        return false;
    }
    ByteBufferCollector dataBuf = null;
    final int maxEntriesSize = this.raftOptions.getMaxEntriesSize();
    final RecyclableByteBufferList byteBufList = RecyclableByteBufferList.newInstance();
    try {
        List<RaftOutter.EntryMeta> entries = new ArrayList<>();
        for (int i = 0; i < maxEntriesSize; i++) {
            final EntryMetaBuilder emb = raftOptions.getRaftMessagesFactory().entryMeta();
            if (!prepareEntry(nextSendingIndex, i, emb, byteBufList)) {
                break;
            }
            entries.add(emb.build());
        }
        rb.entriesList(entries);
        if (entries.isEmpty()) {
            if (nextSendingIndex < this.options.getLogManager().getFirstLogIndex()) {
                installSnapshot();
                return false;
            }
            // _id is unlock in _wait_more
            waitMoreEntries(nextSendingIndex);
            return false;
        }
        if (byteBufList.getCapacity() > 0) {
            dataBuf = ByteBufferCollector.allocateByRecyclers(byteBufList.getCapacity());
            for (final ByteBuffer b : byteBufList) {
                dataBuf.put(b);
            }
            final ByteBuffer buf = dataBuf.getBuffer();
            buf.flip();
            rb.data(new ByteString(buf));
        }
    } finally {
        RecycleUtil.recycle(byteBufList);
    }
    final AppendEntriesRequest request = rb.build();
    if (LOG.isDebugEnabled()) {
        LOG.debug("Node {} send AppendEntriesRequest to {} term {} lastCommittedIndex {} prevLogIndex {} prevLogTerm {} logIndex {} count {}", this.options.getNode().getNodeId(), this.options.getPeerId(), this.options.getTerm(), request.committedIndex(), request.prevLogIndex(), request.prevLogTerm(), nextSendingIndex, Utils.size(request.entriesList()));
    }
    this.statInfo.runningState = RunningState.APPENDING_ENTRIES;
    this.statInfo.firstLogIndex = request.prevLogIndex() + 1;
    this.statInfo.lastLogIndex = request.prevLogIndex() + Utils.size(request.entriesList());
    final Recyclable recyclable = dataBuf;
    final int v = this.version;
    final long monotonicSendTimeMs = Utils.monotonicMs();
    final int seq = getAndIncrementReqSeq();
    Future<Message> rpcFuture = null;
    try {
        rpcFuture = this.rpcService.appendEntries(this.options.getPeerId().getEndpoint(), request, -1, new RpcResponseClosureAdapter<AppendEntriesResponse>() {

            @Override
            public void run(final Status status) {
                if (status.isOk()) {
                    // TODO: recycle on send success, not response received IGNITE-14832.
                    // Also, this closure can be executed when rpcFuture was cancelled, but the request was not sent (meaning
                    // it's too early to recycle byte buffer)
                    RecycleUtil.recycle(recyclable);
                }
                onRpcReturned(Replicator.this.id, RequestType.AppendEntries, status, request, getResponse(), seq, v, monotonicSendTimeMs);
            }
        });
    } catch (final Throwable t) {
        RecycleUtil.recycle(recyclable);
        ThrowUtil.throwException(t);
    }
    addInflight(RequestType.AppendEntries, nextSendingIndex, Utils.size(request.entriesList()), request.data() == null ? 0 : request.data().size(), seq, rpcFuture);
    return true;
}
Also used : Status(org.apache.ignite.raft.jraft.Status) RecyclableByteBufferList(org.apache.ignite.raft.jraft.util.RecyclableByteBufferList) Message(org.apache.ignite.raft.jraft.rpc.Message) ByteString(org.apache.ignite.raft.jraft.util.ByteString) ArrayList(java.util.ArrayList) RpcResponseClosureAdapter(org.apache.ignite.raft.jraft.rpc.RpcResponseClosureAdapter) AppendEntriesRequest(org.apache.ignite.raft.jraft.rpc.RpcRequests.AppendEntriesRequest) ByteBuffer(java.nio.ByteBuffer) ByteBufferCollector(org.apache.ignite.raft.jraft.util.ByteBufferCollector) AppendEntriesRequestBuilder(org.apache.ignite.raft.jraft.rpc.AppendEntriesRequestBuilder) Recyclable(org.apache.ignite.raft.jraft.util.Recyclable) EntryMetaBuilder(org.apache.ignite.raft.jraft.entity.EntryMetaBuilder)

Example 29 with Status

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

the class Replicator method onTimeoutNowReturned.

@SuppressWarnings("unused")
static void onTimeoutNowReturned(final ThreadId id, final Status status, final TimeoutNowRequest request, final TimeoutNowResponse response, final boolean stopAfterFinish) {
    final Replicator r = (Replicator) id.lock();
    if (r == null) {
        return;
    }
    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 TimeoutNowResponse from ").append(r.options.getPeerId());
    }
    if (!status.isOk()) {
        if (isLogDebugEnabled) {
            sb.append(" fail:").append(status);
            LOG.debug(sb.toString());
        }
        notifyReplicatorStatusListener(r, ReplicatorEvent.ERROR, status);
        if (stopAfterFinish) {
            r.notifyOnCaughtUp(RaftError.ESTOP.getNumber(), true);
            r.destroy();
        } else {
            id.unlock();
        }
        return;
    }
    if (isLogDebugEnabled) {
        sb.append(response.success() ? " success" : " fail");
        LOG.debug(sb.toString());
    }
    if (response.term() > r.options.getTerm()) {
        final NodeImpl node = r.options.getNode();
        r.notifyOnCaughtUp(RaftError.EPERM.getNumber(), true);
        r.destroy();
        node.increaseTermTo(response.term(), new Status(RaftError.EHIGHERTERMRESPONSE, "Leader receives higher term timeout_now_response from peer:%s", r.options.getPeerId()));
        return;
    }
    if (stopAfterFinish) {
        r.notifyOnCaughtUp(RaftError.ESTOP.getNumber(), true);
        r.destroy();
    } else {
        id.unlock();
    }
}
Also used : Status(org.apache.ignite.raft.jraft.Status)

Example 30 with Status

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

the class Replicator method onAppendEntriesReturned.

private static boolean onAppendEntriesReturned(final ThreadId id, final Inflight inflight, final Status status, final AppendEntriesRequest request, final AppendEntriesResponse response, final long rpcSendTime, final long startTimeMs, final Replicator r) {
    if (inflight.startIndex != request.prevLogIndex() + 1) {
        LOG.warn("Replicator {} received invalid AppendEntriesResponse, in-flight startIndex={}, request prevLogIndex={}, reset the replicator state and probe again.", r, inflight.startIndex, request.prevLogIndex());
        r.resetInflights();
        r.state = State.Probe;
        // unlock id in sendEmptyEntries
        r.sendEmptyEntries(false);
        return false;
    }
    // record metrics
    if (request.entriesList() != null) {
        r.nodeMetrics.recordLatency("replicate-entries", Utils.monotonicMs() - rpcSendTime);
        r.nodeMetrics.recordSize("replicate-entries-count", request.entriesList().size());
        r.nodeMetrics.recordSize("replicate-entries-bytes", request.data() != null ? request.data().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.prevLogIndex()).append(// 
        " prevLogTerm=").append(// 
        request.prevLogTerm()).append(// 
        " count=").append(Utils.size(request.entriesList()));
    }
    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.state = State.Probe;
        // unlock in in block
        r.block(startTimeMs, status.getCode());
        return false;
    }
    r.consecutiveErrorTimes = 0;
    if (!response.success()) {
        if (response.term() > r.options.getTerm()) {
            if (isLogDebugEnabled) {
                // 
                sb.append(" fail, greater term ").append(// 
                response.term()).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.term(), 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.lastLogIndex()).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.lastLogIndex() + 1 < r.nextIndex) {
            LOG.debug("LastLogIndex at peer={} is {}", r.options.getPeerId(), response.lastLogIndex());
            // The peer contains less logs than leader
            r.nextIndex = response.lastLogIndex() + 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.sendEmptyEntries(false);
        return false;
    }
    if (isLogDebugEnabled) {
        sb.append(", success");
        LOG.debug(sb.toString());
    }
    // success
    if (response.term() != r.options.getTerm()) {
        r.resetInflights();
        r.state = State.Probe;
        LOG.error("Fail, response term {} dismatch, expect term {}", response.term(), r.options.getTerm());
        id.unlock();
        return false;
    }
    if (rpcSendTime > r.lastRpcSendTimestamp) {
        r.lastRpcSendTimestamp = rpcSendTime;
    }
    final int entriesSize = Utils.size(request.entriesList());
    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.state = 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;
}
Also used : Status(org.apache.ignite.raft.jraft.Status)

Aggregations

Status (org.apache.ignite.raft.jraft.Status)121 Test (org.junit.jupiter.api.Test)49 PeerId (org.apache.ignite.raft.jraft.entity.PeerId)43 CountDownLatch (java.util.concurrent.CountDownLatch)31 Message (org.apache.ignite.raft.jraft.rpc.Message)21 ArrayList (java.util.ArrayList)20 Node (org.apache.ignite.raft.jraft.Node)20 Configuration (org.apache.ignite.raft.jraft.conf.Configuration)20 ReadIndexClosure (org.apache.ignite.raft.jraft.closure.ReadIndexClosure)16 LogId (org.apache.ignite.raft.jraft.entity.LogId)14 RaftException (org.apache.ignite.raft.jraft.error.RaftException)14 LogEntry (org.apache.ignite.raft.jraft.entity.LogEntry)11 JRaftException (org.apache.ignite.raft.jraft.error.JRaftException)11 SynchronizedClosure (org.apache.ignite.raft.jraft.closure.SynchronizedClosure)10 Endpoint (org.apache.ignite.raft.jraft.util.Endpoint)10 ByteBuffer (java.nio.ByteBuffer)9 List (java.util.List)9 ConfigurationEntry (org.apache.ignite.raft.jraft.conf.ConfigurationEntry)9 Task (org.apache.ignite.raft.jraft.entity.Task)8 RaftOptions (org.apache.ignite.raft.jraft.option.RaftOptions)8