private void unsafeRegisterConfChange(final Configuration oldConf, final Configuration newConf, final Closure done) {

        Requires.requireTrue(newConf.isValid(), "Invalid new conf: %s", newConf);
        // The new conf entry(will be stored in log manager) should be valid
        Requires.requireTrue(new ConfigurationEntry(null, newConf, oldConf).isValid(), "Invalid conf entry: %s",
            newConf);

        if (this.state != State.STATE_LEADER) {
            LOG.warn("Node {} refused configuration changing as the state={}.", getNodeId(), this.state);
            if (done != null) {
                final Status status = new Status();
                if (this.state == State.STATE_TRANSFERRING) {
                    status.setError(RaftError.EBUSY, "Is transferring leadership.");
                } else {
                    status.setError(RaftError.EPERM, "Not leader");
                }
                ThreadPoolsFactory.runClosureInThread(this.groupId, done, status);
            }
            return;
        }
        // check concurrent conf change
        if (this.confCtx.isBusy()) {
            LOG.warn("Node {} refused configuration concurrent changing.", getNodeId());
            if (done != null) {
                ThreadPoolsFactory.runClosureInThread(this.groupId, done, new Status(RaftError.EBUSY,
                    "Doing another configuration change."));
            }
            return;
        }
        // Return immediately when the new peers equals to current configuration
        if (this.conf.getConf().equals(newConf)) {
            ThreadPoolsFactory.runClosureInThread(this.groupId, done, Status.OK());
            return;
        }
        this.confCtx.start(oldConf, newConf, done);
    }
Configuration changed callback.

@author boyan (boyan@alibaba-inc.com)

2018-Apr-11 2:53:43 PM
jraft-core/src/main/java/com/alipay/sofa/jraft/core/NodeImpl.java