public void applySplit(final Long regionId, final Long newRegionId, final KVStoreClosure closure) {
        Requires.requireNonNull(regionId, "regionId");
        Requires.requireNonNull(newRegionId, "newRegionId");
        if (this.regionEngineTable.containsKey(newRegionId)) {
            closure.setError(Errors.CONFLICT_REGION_ID);
            closure.run(new Status(-1, "Conflict region id %d", newRegionId));
            return;
        }
        if (!this.splitting.compareAndSet(false, true)) {
            closure.setError(Errors.SERVER_BUSY);
            closure.run(new Status(-1, "Server is busy now"));
            return;
        }
        final RegionEngine parentEngine = getRegionEngine(regionId);
        if (parentEngine == null) {
            closure.setError(Errors.NO_REGION_FOUND);
            closure.run(new Status(-1, "RegionEngine[%s] not found", regionId));
            this.splitting.set(false);
            return;
        }
        if (!parentEngine.isLeader()) {
            closure.setError(Errors.NOT_LEADER);
            closure.run(new Status(-1, "RegionEngine[%s] not leader", regionId));
            this.splitting.set(false);
            return;
        }
        final Region parentRegion = parentEngine.getRegion();
        final byte[] startKey = BytesUtil.nullToEmpty(parentRegion.getStartKey());
        final byte[] endKey = parentRegion.getEndKey();
        final long approximateKeys = this.rawKVStore.getApproximateKeysInRange(startKey, endKey);
        final long leastKeysOnSplit = this.storeOpts.getLeastKeysOnSplit();
        if (approximateKeys < leastKeysOnSplit) {
            closure.setError(Errors.TOO_SMALL_TO_SPLIT);
            closure.run(new Status(-1, "RegionEngine[%s]'s keys less than %d", regionId, leastKeysOnSplit));
            this.splitting.set(false);
            return;
        }
        final byte[] splitKey = this.rawKVStore.jumpOver(startKey, approximateKeys >> 1);
        if (splitKey == null) {
            closure.setError(Errors.STORAGE_ERROR);
            closure.run(new Status(-1, "Fail to scan split key"));
            this.splitting.set(false);
            return;
        }
        final KVOperation op = KVOperation.createRangeSplit(splitKey, regionId, newRegionId);
        final Task task = new Task();
        task.setData(ByteBuffer.wrap(Serializers.getDefault().writeObject(op)));
        task.setDone(new KVClosureAdapter(closure, op));
        parentEngine.getNode().apply(task);
    }
Storage engine, there is only one instance in a node,
containing one or more {@link RegionEngine}.

@author jiachun.fjc
jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/StoreEngine.java