Search in sources :

Example 1 with LogId

use of io.dingodb.raft.entity.LogId in project dingo by dingodb.

the class NodeImpl method handleRequestVoteRequest.

@Override
public Message handleRequestVoteRequest(final RpcRequests.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 // 
            RpcFactoryHelper.responseFactory().newResponse(RpcRequests.RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Node %s is not in active state, state %s.", getNodeId(), this.state.name());
        }
        final PeerId candidateId = new PeerId();
        if (!candidateId.parse(request.getServerId())) {
            LOG.warn("Node {} received RequestVoteRequest from {} serverId bad format.", getNodeId(), request.getServerId());
            return // 
            RpcFactoryHelper.responseFactory().newResponse(RpcRequests.RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Parse candidateId failed: %s.", request.getServerId());
        }
        // noinspection ConstantConditions
        do {
            // check term
            if (request.getTerm() >= this.currTerm) {
                LOG.info("Node {} received RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
                // increase current term, change state to follower
                if (request.getTerm() > this.currTerm) {
                    stepDown(request.getTerm(), false, new Status(RaftError.EHIGHERTERMRESPONSE, "Raft node receives higher term RequestVoteRequest."));
                }
            } else {
                // ignore older term
                LOG.info("Node {} ignore RequestVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), 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.getTerm() != this.currTerm) {
                LOG.warn("Node {} raise term {} when get lastLogId.", getNodeId(), this.currTerm);
                break;
            }
            final boolean logIsOk = new LogId(request.getLastLogIndex(), request.getLastLogTerm()).compareTo(lastLogId) >= 0;
            if (logIsOk && (this.votedId == null || this.votedId.isEmpty())) {
                stepDown(request.getTerm(), 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 // 
        RpcRequests.RequestVoteResponse.newBuilder().setTerm(// 
        this.currTerm).setGranted(// 
        request.getTerm() == this.currTerm && candidateId.equals(this.votedId)).build();
    } finally {
        if (doUnlock) {
            this.writeLock.unlock();
        }
    }
}
Also used : Status(io.dingodb.raft.Status) LogId(io.dingodb.raft.entity.LogId) PeerId(io.dingodb.raft.entity.PeerId)

Example 2 with LogId

use of io.dingodb.raft.entity.LogId in project dingo by dingodb.

the class NodeImpl method preVote.

// in writeLock
private void preVote() {
    long oldTerm;
    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;
        }
        oldTerm = 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 (oldTerm != 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;
            }
            if (!this.rpcService.connect(peer.getEndpoint())) {
                LOG.warn("Node {} channel init failed, address={}.", getNodeId(), peer.getEndpoint());
                continue;
            }
            final OnPreVoteRpcDone done = new OnPreVoteRpcDone(peer, this.currTerm);
            done.request = // 
            RpcRequests.RequestVoteRequest.newBuilder().setPreVote(// it's a pre-vote request.
            true).setGroupId(// 
            this.groupId).setServerId(// 
            this.serverId.toString()).setPeerId(// 
            peer.toString()).setTerm(// next term
            this.currTerm + 1).setLastLogIndex(// 
            lastLogId.getIndex()).setLastLogTerm(// 
            lastLogId.getTerm()).build();
            this.rpcService.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(io.dingodb.raft.entity.LogId) PeerId(io.dingodb.raft.entity.PeerId)

Example 3 with LogId

use of io.dingodb.raft.entity.LogId 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 4 with LogId

use of io.dingodb.raft.entity.LogId in project dingo by dingodb.

the class NodeImpl method handlePreVoteRequest.

@Override
public Message handlePreVoteRequest(final RpcRequests.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 // 
            RpcFactoryHelper.responseFactory().newResponse(RpcRequests.RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Node %s is not in active state, state %s.", getNodeId(), this.state.name());
        }
        final PeerId candidateId = new PeerId();
        if (!candidateId.parse(request.getServerId())) {
            LOG.warn("Node {} received PreVoteRequest from {} serverId bad format.", getNodeId(), request.getServerId());
            return // 
            RpcFactoryHelper.responseFactory().newResponse(RpcRequests.RequestVoteResponse.getDefaultInstance(), RaftError.EINVAL, "Parse candidateId failed: %s.", request.getServerId());
        }
        boolean granted = false;
        // noinspection ConstantConditions
        do {
            if (!this.conf.contains(candidateId)) {
                LOG.warn("Node {} ignore PreVoteRequest from {} as it is not in conf <{}>.", getNodeId(), request.getServerId(), this.conf);
                break;
            }
            if (this.leaderId != null && !this.leaderId.isEmpty() && isCurrentLeaderValid()) {
                LOG.info("Node {} ignore PreVoteRequest from {}, term={}, currTerm={}, because the leader {}'s lease is still valid.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm, this.leaderId);
                break;
            }
            if (request.getTerm() < this.currTerm) {
                LOG.info("Node {} ignore PreVoteRequest from {}, term={}, currTerm={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm);
                // A follower replicator may not be started when this node become leader, so we must check it.
                checkReplicator(candidateId);
                break;
            }
            // A follower replicator may not be started when this node become leader, so we must check it.
            // check replicator state
            checkReplicator(candidateId);
            doUnlock = false;
            this.writeLock.unlock();
            final LogId lastLogId = this.logManager.getLastLogId(true);
            doUnlock = true;
            this.writeLock.lock();
            final LogId requestLastLogId = new LogId(request.getLastLogIndex(), request.getLastLogTerm());
            granted = requestLastLogId.compareTo(lastLogId) >= 0;
            LOG.info("Node {} received PreVoteRequest from {}, term={}, currTerm={}, granted={}, requestLastLogId={}, lastLogId={}.", getNodeId(), request.getServerId(), request.getTerm(), this.currTerm, granted, requestLastLogId, lastLogId);
        } while (false);
        return // 
        RpcRequests.RequestVoteResponse.newBuilder().setTerm(// 
        this.currTerm).setGranted(// 
        granted).build();
    } finally {
        if (doUnlock) {
            this.writeLock.unlock();
        }
    }
}
Also used : LogId(io.dingodb.raft.entity.LogId) PeerId(io.dingodb.raft.entity.PeerId)

Example 5 with LogId

use of io.dingodb.raft.entity.LogId in project dingo by dingodb.

the class NodeImpl method electSelf.

// should be in writeLock
private void electSelf() {
    long oldTerm;
    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());
        oldTerm = 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 (oldTerm != 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;
            }
            if (!this.rpcService.connect(peer.getEndpoint())) {
                LOG.warn("Node {} channel init failed, address={}.", getNodeId(), peer.getEndpoint());
                continue;
            }
            final OnRequestVoteRpcDone done = new OnRequestVoteRpcDone(peer, this.currTerm, this);
            done.request = // 
            RpcRequests.RequestVoteRequest.newBuilder().setPreVote(// It's not a pre-vote request.
            false).setGroupId(// 
            this.groupId).setServerId(// 
            this.serverId.toString()).setPeerId(// 
            peer.toString()).setTerm(// 
            this.currTerm).setLastLogIndex(// 
            lastLogId.getIndex()).setLastLogTerm(// 
            lastLogId.getTerm()).build();
            this.rpcService.requestVote(peer.getEndpoint(), done.request, done);
        }
        this.metaStorage.setTermAndVotedFor(this.currTerm, this.serverId);
        this.voteCtx.grant(this.serverId);
        if (this.voteCtx.isGranted()) {
            becomeLeader();
        }
    } finally {
        this.writeLock.unlock();
    }
}
Also used : Status(io.dingodb.raft.Status) LogId(io.dingodb.raft.entity.LogId) PeerId(io.dingodb.raft.entity.PeerId)

Aggregations

LogId (io.dingodb.raft.entity.LogId)22 PeerId (io.dingodb.raft.entity.PeerId)10 LogEntry (io.dingodb.raft.entity.LogEntry)9 Status (io.dingodb.raft.Status)7 ArrayList (java.util.ArrayList)6 Configuration (io.dingodb.raft.conf.Configuration)5 ConfigurationEntry (io.dingodb.raft.conf.ConfigurationEntry)4 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)4 ConfigurationManager (io.dingodb.raft.conf.ConfigurationManager)3 EntryType (io.dingodb.raft.entity.EnumOutter.EntryType)2 RaftException (io.dingodb.raft.error.RaftException)2 LogStorageOptions (io.dingodb.raft.option.LogStorageOptions)2 RaftOptions (io.dingodb.raft.option.RaftOptions)2 DisruptorMetricSet (io.dingodb.raft.util.DisruptorMetricSet)2 NamedThreadFactory (io.dingodb.raft.util.NamedThreadFactory)2 ByteBuffer (java.nio.ByteBuffer)2 com.lmax.disruptor (com.lmax.disruptor)1 BlockingWaitStrategy (com.lmax.disruptor.BlockingWaitStrategy)1 Disruptor (com.lmax.disruptor.dsl.Disruptor)1 ProducerType (com.lmax.disruptor.dsl.ProducerType)1