Search in sources :

Example 21 with LogId

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

the class NodeImpl method handleRequestVoteRequest.

@Override
public Message handleRequestVoteRequest(final RequestVoteRequest request) {
    boolean doUnlock = true;
    this.writeLock.lock();
    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 candidateId = new PeerId();
        if (!candidateId.parse(request.serverId())) {
            LOG.warn("Node {} received RequestVoteRequest from {} serverId bad format.", getNodeId(), request.serverId());
            return // 
            RaftRpcFactory.DEFAULT.newResponse(raftOptions.getRaftMessagesFactory(), RaftError.EINVAL, "Parse candidateId failed: %s.", request.serverId());
        }
        // noinspection ConstantConditions
        do {
            // check term
            if (request.term() >= this.currTerm) {
                LOG.info("Node {} received RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.serverId(), request.term(), this.currTerm);
                // increase current term, change state to follower
                if (request.term() > this.currTerm) {
                    stepDown(request.term(), false, new Status(RaftError.EHIGHERTERMRESPONSE, "Raft node receives higher term RequestVoteRequest."));
                } else if (candidateId.equals(leaderId)) {
                    // Already follows a leader in this term.
                    LOG.info("Node {} ignores RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.serverId(), request.term(), this.currTerm);
                    break;
                }
            } else {
                // ignore older term
                LOG.info("Node {} ignores RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.serverId(), request.term(), this.currTerm);
                break;
            }
            doUnlock = false;
            this.writeLock.unlock();
            final LogId lastLogId = this.logManager.getLastLogId(true);
            doUnlock = true;
            this.writeLock.lock();
            // vote need ABA check after unlock&writeLock
            if (request.term() != this.currTerm) {
                LOG.warn("Node {} raise term {} when get lastLogId.", getNodeId(), this.currTerm);
                break;
            }
            final boolean logIsOk = new LogId(request.lastLogIndex(), request.lastLogTerm()).compareTo(lastLogId) >= 0;
            if (logIsOk && (this.votedId == null || this.votedId.isEmpty())) {
                stepDown(request.term(), false, new Status(RaftError.EVOTEFORCANDIDATE, "Raft node votes for some candidate, step down to restart election_timer."));
                this.votedId = candidateId.copy();
                this.metaStorage.setVotedFor(candidateId);
            }
        } while (false);
        return raftOptions.getRaftMessagesFactory().requestVoteResponse().term(this.currTerm).granted(request.term() == this.currTerm && candidateId.equals(this.votedId)).build();
    } finally {
        if (doUnlock) {
            this.writeLock.unlock();
        }
    }
}
Also used : Status(org.apache.ignite.raft.jraft.Status) LogId(org.apache.ignite.raft.jraft.entity.LogId) PeerId(org.apache.ignite.raft.jraft.entity.PeerId)

Example 22 with LogId

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

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(this.getOptions().getCommonExecutor(), 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);
}
Also used : Status(org.apache.ignite.raft.jraft.Status) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) LogId(org.apache.ignite.raft.jraft.entity.LogId) LogEntry(org.apache.ignite.raft.jraft.entity.LogEntry)

Example 23 with LogId

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

the class NodeImpl method electSelf.

// should be in writeLock
private void electSelf() {
    long electSelfTerm;
    try {
        LOG.info("Node {} start vote and grant vote self, term={}.", getNodeId(), this.currTerm);
        if (!this.conf.contains(this.serverId)) {
            LOG.warn("Node {} can't do electSelf as it is not in {}.", getNodeId(), this.conf);
            return;
        }
        if (this.state == State.STATE_FOLLOWER) {
            LOG.debug("Node {} stop election timer, term={}.", getNodeId(), this.currTerm);
            this.electionTimer.stop();
        }
        resetLeaderId(PeerId.emptyPeer(), new Status(RaftError.ERAFTTIMEDOUT, "A follower's leader_id is reset to NULL as it begins to request_vote."));
        this.state = State.STATE_CANDIDATE;
        this.currTerm++;
        this.votedId = this.serverId.copy();
        LOG.debug("Node {} start vote timer, term={} .", getNodeId(), this.currTerm);
        this.voteTimer.start();
        this.voteCtx.init(this.conf.getConf(), this.conf.isStable() ? null : this.conf.getOldConf());
        electSelfTerm = this.currTerm;
    } finally {
        this.writeLock.unlock();
    }
    final LogId lastLogId = this.logManager.getLastLogId(true);
    this.writeLock.lock();
    try {
        // vote need defense ABA after unlock&writeLock
        if (electSelfTerm != this.currTerm) {
            LOG.warn("Node {} raise term {} when getLastLogId.", getNodeId(), this.currTerm);
            return;
        }
        for (final PeerId peer : this.conf.listPeers()) {
            if (peer.equals(this.serverId)) {
                continue;
            }
            rpcClientService.connectAsync(peer.getEndpoint()).thenAccept(ok -> {
                if (!ok) {
                    LOG.warn("Node {} failed to init channel, address={}.", getNodeId(), peer.getEndpoint());
                    return;
                }
                final OnRequestVoteRpcDone done = new OnRequestVoteRpcDone(peer, electSelfTerm, this);
                done.request = raftOptions.getRaftMessagesFactory().requestVoteRequest().preVote(// It's not a pre-vote request.
                false).groupId(this.groupId).serverId(this.serverId.toString()).peerId(peer.toString()).term(electSelfTerm).lastLogIndex(lastLogId.getIndex()).lastLogTerm(lastLogId.getTerm()).build();
                this.rpcClientService.requestVote(peer.getEndpoint(), done.request, done);
            });
        }
        this.metaStorage.setTermAndVotedFor(electSelfTerm, this.serverId);
        this.voteCtx.grant(this.serverId);
        if (this.voteCtx.isGranted()) {
            becomeLeader();
        }
    } finally {
        this.writeLock.unlock();
    }
}
Also used : Status(org.apache.ignite.raft.jraft.Status) LogId(org.apache.ignite.raft.jraft.entity.LogId) PeerId(org.apache.ignite.raft.jraft.entity.PeerId)

Example 24 with LogId

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

the class NodeImpl method bootstrap.

public boolean bootstrap(final BootstrapOptions opts) throws InterruptedException {
    if (opts.getLastLogIndex() > 0 && (opts.getGroupConf().isEmpty() || opts.getFsm() == null)) {
        LOG.error("Invalid arguments for bootstrap, groupConf={}, fsm={}, lastLogIndex={}.", opts.getGroupConf(), opts.getFsm(), opts.getLastLogIndex());
        return false;
    }
    if (opts.getGroupConf().isEmpty()) {
        LOG.error("Bootstrapping an empty node makes no sense.");
        return false;
    }
    Requires.requireNonNull(opts.getServiceFactory(), "Null jraft service factory");
    this.serviceFactory = opts.getServiceFactory();
    // Term is not an option since changing it is very dangerous
    final long bootstrapLogTerm = opts.getLastLogIndex() > 0 ? 1 : 0;
    final LogId bootstrapId = new LogId(opts.getLastLogIndex(), bootstrapLogTerm);
    this.options = opts.getNodeOptions() == null ? new NodeOptions() : opts.getNodeOptions();
    this.raftOptions = this.options.getRaftOptions();
    this.metrics = new NodeMetrics(opts.isEnableMetrics());
    this.options.setFsm(opts.getFsm());
    this.options.setLogUri(opts.getLogUri());
    this.options.setRaftMetaUri(opts.getRaftMetaUri());
    this.options.setSnapshotUri(opts.getSnapshotUri());
    this.configManager = new ConfigurationManager();
    // Create fsmCaller at first as logManager needs it to report error
    this.fsmCaller = new FSMCallerImpl();
    initPools(opts.getNodeOptions());
    if (!initLogStorage()) {
        LOG.error("Fail to init log storage.");
        return false;
    }
    if (!initMetaStorage()) {
        LOG.error("Fail to init meta storage.");
        return false;
    }
    if (this.currTerm == 0) {
        this.currTerm = 1;
        if (!this.metaStorage.setTermAndVotedFor(1, new PeerId())) {
            LOG.error("Fail to set term.");
            return false;
        }
    }
    if (opts.getFsm() != null && !initFSMCaller(bootstrapId)) {
        LOG.error("Fail to init fsm caller.");
        return false;
    }
    final LogEntry entry = new LogEntry(EnumOutter.EntryType.ENTRY_TYPE_CONFIGURATION);
    entry.getId().setTerm(this.currTerm);
    entry.setPeers(opts.getGroupConf().listPeers());
    entry.setLearners(opts.getGroupConf().listLearners());
    final List<LogEntry> entries = new ArrayList<>();
    entries.add(entry);
    final BootstrapStableClosure bootstrapDone = new BootstrapStableClosure();
    this.logManager.appendEntries(entries, bootstrapDone);
    if (!bootstrapDone.await().isOk()) {
        LOG.error("Fail to append configuration.");
        return false;
    }
    if (opts.getLastLogIndex() > 0) {
        if (!initSnapshotStorage()) {
            LOG.error("Fail to init snapshot storage.");
            return false;
        }
        final SynchronizedClosure snapshotDone = new SynchronizedClosure();
        this.snapshotExecutor.doSnapshot(snapshotDone);
        if (!snapshotDone.await().isOk()) {
            LOG.error("Fail to save snapshot, status={}.", snapshotDone.getStatus());
            return false;
        }
    }
    if (this.logManager.getFirstLogIndex() != opts.getLastLogIndex() + 1) {
        throw new IllegalStateException("First and last log index mismatch");
    }
    if (opts.getLastLogIndex() > 0) {
        if (this.logManager.getLastLogIndex() != opts.getLastLogIndex()) {
            throw new IllegalStateException("Last log index mismatch");
        }
    } else {
        if (this.logManager.getLastLogIndex() != opts.getLastLogIndex() + 1) {
            throw new IllegalStateException("Last log index mismatch");
        }
    }
    return true;
}
Also used : SynchronizedClosure(org.apache.ignite.raft.jraft.closure.SynchronizedClosure) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) NodeOptions(org.apache.ignite.raft.jraft.option.NodeOptions) LogId(org.apache.ignite.raft.jraft.entity.LogId) ConfigurationManager(org.apache.ignite.raft.jraft.conf.ConfigurationManager) LogEntry(org.apache.ignite.raft.jraft.entity.LogEntry) PeerId(org.apache.ignite.raft.jraft.entity.PeerId)

Example 25 with LogId

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

the class NodeImpl method preVote.

// in writeLock
private void preVote() {
    long preVoteTerm;
    try {
        LOG.info("Node {} term {} start preVote.", getNodeId(), this.currTerm);
        if (this.snapshotExecutor != null && this.snapshotExecutor.isInstallingSnapshot()) {
            LOG.warn("Node {} term {} doesn't do preVote when installing snapshot as the configuration may be out of date.", getNodeId(), this.currTerm);
            return;
        }
        if (!this.conf.contains(this.serverId)) {
            LOG.warn("Node {} can't do preVote as it is not in conf <{}>.", getNodeId(), this.conf);
            return;
        }
        preVoteTerm = this.currTerm;
    } finally {
        this.writeLock.unlock();
    }
    final LogId lastLogId = this.logManager.getLastLogId(true);
    boolean doUnlock = true;
    this.writeLock.lock();
    try {
        // pre_vote need defense ABA after unlock&writeLock
        if (preVoteTerm != this.currTerm) {
            LOG.warn("Node {} raise term {} when get lastLogId.", getNodeId(), this.currTerm);
            return;
        }
        this.prevVoteCtx.init(this.conf.getConf(), this.conf.isStable() ? null : this.conf.getOldConf());
        for (final PeerId peer : this.conf.listPeers()) {
            if (peer.equals(this.serverId)) {
                continue;
            }
            rpcClientService.connectAsync(peer.getEndpoint()).thenAccept(ok -> {
                if (!ok) {
                    LOG.warn("Node {} failed to init channel, address={}.", getNodeId(), peer.getEndpoint());
                    return;
                }
                final OnPreVoteRpcDone done = new OnPreVoteRpcDone(peer, preVoteTerm);
                done.request = raftOptions.getRaftMessagesFactory().requestVoteRequest().preVote(// it's a pre-vote request.
                true).groupId(this.groupId).serverId(this.serverId.toString()).peerId(peer.toString()).term(// next term
                preVoteTerm + 1).lastLogIndex(lastLogId.getIndex()).lastLogTerm(lastLogId.getTerm()).build();
                this.rpcClientService.preVote(peer.getEndpoint(), done.request, done);
            });
        }
        this.prevVoteCtx.grant(this.serverId);
        if (this.prevVoteCtx.isGranted()) {
            doUnlock = false;
            electSelf();
        }
    } finally {
        if (doUnlock) {
            this.writeLock.unlock();
        }
    }
}
Also used : LogId(org.apache.ignite.raft.jraft.entity.LogId) PeerId(org.apache.ignite.raft.jraft.entity.PeerId)

Aggregations

LogId (org.apache.ignite.raft.jraft.entity.LogId)41 LogEntry (org.apache.ignite.raft.jraft.entity.LogEntry)24 Test (org.junit.jupiter.api.Test)15 PeerId (org.apache.ignite.raft.jraft.entity.PeerId)14 ArrayList (java.util.ArrayList)10 Status (org.apache.ignite.raft.jraft.Status)10 BaseStorageTest (org.apache.ignite.raft.jraft.storage.BaseStorageTest)9 ConfigurationEntry (org.apache.ignite.raft.jraft.conf.ConfigurationEntry)7 Configuration (org.apache.ignite.raft.jraft.conf.Configuration)5 ByteBuffer (java.nio.ByteBuffer)4 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)4 CountDownLatch (java.util.concurrent.CountDownLatch)4 LogManager (org.apache.ignite.raft.jraft.storage.LogManager)4 ConfigurationManager (org.apache.ignite.raft.jraft.conf.ConfigurationManager)3 StripedDisruptor (org.apache.ignite.raft.jraft.disruptor.StripedDisruptor)2 EntryType (org.apache.ignite.raft.jraft.entity.EnumOutter.EntryType)2 RaftException (org.apache.ignite.raft.jraft.error.RaftException)2 LogStorageOptions (org.apache.ignite.raft.jraft.option.LogStorageOptions)2 NodeOptions (org.apache.ignite.raft.jraft.option.NodeOptions)2 RaftOptions (org.apache.ignite.raft.jraft.option.RaftOptions)2