private void doSnapshot(final Closure done, boolean sync) {
        boolean doUnlock = true;
        this.lock.lock();
        try {
            if (this.stopped) {
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EPERM,
                    "Is stopped."));
                return;
            }
            if (sync && !this.fsmCaller.isRunningOnFSMThread()) {
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EACCES,
                    "trigger snapshot synchronously out of StateMachine's callback methods"));
                throw new IllegalStateException(
                    "You can't trigger snapshot synchronously out of StateMachine's callback methods.");

            }
            if (this.downloadingSnapshot.get() != null) {
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EBUSY,
                    "Is loading another snapshot."));
                return;
            }

            if (this.savingSnapshot) {
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EBUSY,
                    "Is saving another snapshot."));
                return;
            }

            if (this.fsmCaller.getLastAppliedIndex() == this.lastSnapshotIndex) {
                // There might be false positive as the getLastAppliedIndex() is being
                // updated. But it's fine since we will do next snapshot saving in a
                // predictable time.
                doUnlock = false;
                this.lock.unlock();
                this.logManager.clearBufferedLogs();
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done);
                return;
            }

            final long distance = this.fsmCaller.getLastAppliedIndex() - this.lastSnapshotIndex;
            if (distance < this.node.getOptions().getSnapshotLogIndexMargin()) {
                // If state machine's lastAppliedIndex value minus lastSnapshotIndex value is
                // less than snapshotLogIndexMargin value, then directly return.
                if (this.node != null) {
                    LOG.debug(
                        "Node {} snapshotLogIndexMargin={}, distance={}, so ignore this time of snapshot by snapshotLogIndexMargin setting.",
                        this.node.getNodeId(), distance, this.node.getOptions().getSnapshotLogIndexMargin());
                }
                doUnlock = false;
                this.lock.unlock();
                ThreadPoolsFactory
                    .runClosureInThread(
                        getNode().getGroupId(),
                        done,
                        new Status(RaftError.ECANCELED,
                            "The snapshot index distance since last snapshot is less than NodeOptions#snapshotLogIndexMargin, canceled this task."));
                return;
            }

            final SnapshotWriter writer = this.snapshotStorage.create();
            if (writer == null) {
                ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EIO,
                    "Fail to create writer."));
                reportError(RaftError.EIO.getNumber(), "Fail to create snapshot writer.");
                return;
            }
            this.savingSnapshot = true;
            final SaveSnapshotDone saveSnapshotDone = new SaveSnapshotDone(writer, done, null);
            if (sync) {
                this.fsmCaller.onSnapshotSaveSync(saveSnapshotDone);
            } else {
                if (!this.fsmCaller.onSnapshotSave(saveSnapshotDone)) {
                    ThreadPoolsFactory.runClosureInThread(getNode().getGroupId(), done, new Status(RaftError.EHOSTDOWN,
                        "The raft node is down."));
                    return;
                }
            }
            this.runningJobs.incrementAndGet();
        } finally {
            if (doUnlock) {
                this.lock.unlock();
            }
        }

    }
Load snapshot at first time closure
@author boyan (boyan@alibaba-inc.com)

2018-Apr-16 2:57:46 PM
jraft-core/src/main/java/com/alipay/sofa/jraft/storage/snapshot/SnapshotExecutorImpl.java