use of org.apache.ratis.statemachine.SnapshotInfo in project incubator-ratis by apache.
the class LeaderElection method askForVotes.
/**
* After a peer changes its role to candidate, it invokes this method to
* send out requestVote rpc to all other peers.
*/
private void askForVotes() throws InterruptedException, IOException {
final ServerState state = server.getState();
while (running && server.isCandidate()) {
// one round of requestVotes
final long electionTerm;
synchronized (server) {
electionTerm = state.initElection();
server.getState().persistMetadata();
}
LOG.info(state.getSelfId() + ": begin an election in Term " + electionTerm);
TermIndex lastEntry = state.getLog().getLastEntryTermIndex();
if (lastEntry == null) {
// lastEntry may need to be derived from snapshot
SnapshotInfo snapshot = state.getLatestSnapshot();
if (snapshot != null) {
lastEntry = snapshot.getTermIndex();
}
}
final ResultAndTerm r;
if (others.isEmpty()) {
r = new ResultAndTerm(Result.PASSED, electionTerm);
} else {
try {
initExecutor();
int submitted = submitRequests(electionTerm, lastEntry);
r = waitForResults(electionTerm, submitted);
} finally {
if (executor != null) {
executor.shutdown();
}
}
}
synchronized (server) {
if (electionTerm != state.getCurrentTerm() || !running || !server.isCandidate()) {
// term already passed or no longer a candidate.
return;
}
switch(r.result) {
case PASSED:
server.changeToLeader();
return;
case SHUTDOWN:
LOG.info("{} received shutdown response when requesting votes.", server.getId());
server.getProxy().close();
return;
case REJECTED:
case DISCOVERED_A_NEW_TERM:
final long term = r.term > server.getState().getCurrentTerm() ? r.term : server.getState().getCurrentTerm();
server.changeToFollower(term, true);
return;
case TIMEOUT:
}
}
}
}
use of org.apache.ratis.statemachine.SnapshotInfo in project incubator-ratis by apache.
the class ServerState method isLogUpToDate.
boolean isLogUpToDate(TermIndex candidateLastEntry) {
TermIndex local = log.getLastEntryTermIndex();
// need to take into account snapshot
SnapshotInfo snapshot = server.getStateMachine().getLatestSnapshot();
if (local == null && snapshot == null) {
return true;
} else if (candidateLastEntry == null) {
return false;
}
if (local == null || (snapshot != null && snapshot.getIndex() > local.getIndex())) {
local = snapshot.getTermIndex();
}
return local.compareTo(candidateLastEntry) <= 0;
}
use of org.apache.ratis.statemachine.SnapshotInfo in project incubator-ratis by apache.
the class ServerState method initStatemachine.
private long initStatemachine(StateMachine sm, RaftProperties properties) throws IOException {
sm.initialize(selfId, properties, storage);
storage.setStateMachineStorage(sm.getStateMachineStorage());
SnapshotInfo snapshot = sm.getLatestSnapshot();
if (snapshot == null || snapshot.getTermIndex().getIndex() < 0) {
return RaftServerConstants.INVALID_LOG_INDEX;
}
// get the raft configuration from the snapshot
RaftConfiguration raftConf = sm.getRaftConfiguration();
if (raftConf != null) {
configurationManager.addConfiguration(raftConf.getLogEntryIndex(), raftConf);
}
return snapshot.getIndex();
}
use of org.apache.ratis.statemachine.SnapshotInfo in project incubator-ratis by apache.
the class StateMachineUpdater method run.
@Override
public void run() {
final RaftStorage storage = server.getState().getStorage();
while (isRunning()) {
try {
synchronized (this) {
// Thus initially lastAppliedIndex can be greater than lastCommitted.
while (lastAppliedIndex >= raftLog.getLastCommittedIndex()) {
wait();
}
}
final long committedIndex = raftLog.getLastCommittedIndex();
Preconditions.assertTrue(lastAppliedIndex < committedIndex);
if (state == State.RELOAD) {
Preconditions.assertTrue(stateMachine.getLifeCycleState() == LifeCycle.State.PAUSED);
stateMachine.reinitialize(server.getId(), properties, storage);
SnapshotInfo snapshot = stateMachine.getLatestSnapshot();
Preconditions.assertTrue(snapshot != null && snapshot.getIndex() > lastAppliedIndex, "Snapshot: %s, lastAppliedIndex: %s", snapshot, lastAppliedIndex);
lastAppliedIndex = snapshot.getIndex();
lastSnapshotIndex = snapshot.getIndex();
state = State.RUNNING;
}
final MemoizedSupplier<List<CompletableFuture<Message>>> futures = MemoizedSupplier.valueOf(() -> new ArrayList<>());
while (lastAppliedIndex < committedIndex) {
final long nextIndex = lastAppliedIndex + 1;
final LogEntryProto next = raftLog.get(nextIndex);
if (next != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("{}: applying nextIndex={}, nextLog={}", this, nextIndex, ServerProtoUtils.toString(next));
}
final CompletableFuture<Message> f = server.applyLogToStateMachine(next);
if (f != null) {
futures.get().add(f);
}
lastAppliedIndex = nextIndex;
} else {
LOG.debug("{}: logEntry {} is null. There may be snapshot to load. state:{}", this, nextIndex, state);
break;
}
}
// check if need to trigger a snapshot
if (shouldTakeSnapshot(lastAppliedIndex)) {
if (futures.isInitialized()) {
JavaUtils.allOf(futures.get()).get();
}
stateMachine.takeSnapshot();
// TODO purge logs, including log cache. but should keep log for leader's RPCSenders
lastSnapshotIndex = lastAppliedIndex;
}
} catch (InterruptedException e) {
if (!isRunning()) {
LOG.info("{}: the StateMachineUpdater is interrupted and will exit.", this);
} else {
final String s = this + ": the StateMachineUpdater is wrongly interrupted";
ExitUtils.terminate(1, s, e, LOG);
}
} catch (Throwable t) {
final String s = this + ": the StateMachineUpdater hits Throwable";
ExitUtils.terminate(2, s, t, LOG);
}
}
}
use of org.apache.ratis.statemachine.SnapshotInfo in project incubator-ratis by apache.
the class GRpcLogAppender method run.
@Override
public void run() {
while (isAppenderRunning()) {
if (shouldSendRequest()) {
SnapshotInfo snapshot = shouldInstallSnapshot();
if (snapshot != null) {
installSnapshot(snapshot, snapshotResponseHandler);
} else {
// keep appending log entries or sending heartbeats
try {
appendLog();
} catch (RaftLogIOException e) {
LOG.error(this + " hit IOException while loading raft log", e);
stopSender();
}
}
}
if (isAppenderRunning() && !shouldSendRequest()) {
// use lastSend time instead of lastResponse time
final long waitTime = getHeartbeatRemainingTime(follower.getLastRpcTime());
if (waitTime > 0) {
synchronized (this) {
try {
LOG.debug("{} decides to wait {}ms before appending to {}", server.getId(), waitTime, follower.getPeer());
wait(waitTime);
} catch (InterruptedException ignored) {
}
}
}
}
}
appendLogRequestObserver.onCompleted();
}
Aggregations