public VAdminProto.AsyncOperationStatusResponse handleRebalanceNode(
      VAdminProto.InitiateRebalanceNodeRequest request) {
    VAdminProto.AsyncOperationStatusResponse.Builder response =
        VAdminProto.AsyncOperationStatusResponse.newBuilder();
    try {
      if (!voldemortConfig.isEnableRebalanceService())
        throw new VoldemortException(
            "Rebalance service is not enabled for node:" + metadataStore.getNodeId());

      RebalancePartitionsInfo rebalanceStealInfo =
          new RebalancePartitionsInfo(
              request.getStealerId(),
              request.getDonorId(),
              request.getPartitionsList(),
              request.getDeletePartitionsList(),
              request.getUnbalancedStoreList(),
              request.getAttempt());

      int requestId = rebalancer.rebalanceLocalNode(rebalanceStealInfo);

      response
          .setRequestId(requestId)
          .setDescription(rebalanceStealInfo.toString())
          .setStatus("started")
          .setComplete(false);
    } catch (VoldemortException e) {
      response.setError(ProtoUtils.encodeError(errorCodeMapper, e));
      logger.error("handleRebalanceNode failed for request(" + request.toString() + ")", e);
    }

    return response.build();
  }
  public VAdminProto.AsyncOperationStatusResponse handleAsyncStatus(
      VAdminProto.AsyncOperationStatusRequest request) {
    VAdminProto.AsyncOperationStatusResponse.Builder response =
        VAdminProto.AsyncOperationStatusResponse.newBuilder();
    try {
      int requestId = request.getRequestId();
      AsyncOperationStatus operationStatus = asyncService.getOperationStatus(requestId);
      boolean requestComplete = asyncService.isComplete(requestId);
      response.setDescription(operationStatus.getDescription());
      response.setComplete(requestComplete);
      response.setStatus(operationStatus.getStatus());
      response.setRequestId(requestId);
      if (operationStatus.hasException())
        throw new VoldemortException(operationStatus.getException());
    } catch (VoldemortException e) {
      response.setError(ProtoUtils.encodeError(errorCodeMapper, e));
      logger.error("handleAsyncStatus failed for request(" + request.toString().trim() + ")", e);
    }

    return response.build();
  }
  public VAdminProto.AsyncOperationStatusResponse handleFetchAndUpdate(
      VAdminProto.InitiateFetchAndUpdateRequest request) {
    final int nodeId = request.getNodeId();
    final List<Integer> partitions = request.getPartitionsList();
    final VoldemortFilter filter =
        request.hasFilter()
            ? getFilterFromRequest(request.getFilter(), voldemortConfig, networkClassLoader)
            : new DefaultVoldemortFilter();
    final String storeName = request.getStore();

    int requestId = asyncService.getUniqueRequestId();
    VAdminProto.AsyncOperationStatusResponse.Builder response =
        VAdminProto.AsyncOperationStatusResponse.newBuilder()
            .setRequestId(requestId)
            .setComplete(false)
            .setDescription("Fetch and update")
            .setStatus("started");

    try {
      asyncService.submitOperation(
          requestId,
          new AsyncOperation(requestId, "Fetch and Update") {

            private final AtomicBoolean running = new AtomicBoolean(true);

            @Override
            public void stop() {
              running.set(false);
            }

            @Override
            public void operate() {
              AdminClient adminClient =
                  RebalanceUtils.createTempAdminClient(
                      voldemortConfig, metadataStore.getCluster(), 4, 2);
              try {
                StorageEngine<ByteArray, byte[]> storageEngine =
                    getStorageEngine(storeRepository, storeName);
                Iterator<Pair<ByteArray, Versioned<byte[]>>> entriesIterator =
                    adminClient.fetchEntries(nodeId, storeName, partitions, filter, false);
                updateStatus("Initated fetchPartitionEntries");
                EventThrottler throttler =
                    new EventThrottler(voldemortConfig.getStreamMaxWriteBytesPerSec());
                for (long i = 0; running.get() && entriesIterator.hasNext(); i++) {
                  Pair<ByteArray, Versioned<byte[]>> entry = entriesIterator.next();

                  ByteArray key = entry.getFirst();
                  Versioned<byte[]> value = entry.getSecond();
                  try {
                    storageEngine.put(key, value);
                  } catch (ObsoleteVersionException e) {
                    // log and ignore
                    logger.debug("migratePartition threw ObsoleteVersionException, Ignoring.");
                  }

                  throttler.maybeThrottle(key.length() + valueSize(value));
                  if ((i % 1000) == 0) {
                    updateStatus(i + " entries processed");
                  }
                }
              } finally {
                adminClient.stop();
              }
            }
          });

    } catch (VoldemortException e) {
      response.setError(ProtoUtils.encodeError(errorCodeMapper, e));
      logger.error("handleFetchAndUpdate failed for request(" + request.toString() + ")", e);
    }

    return response.build();
  }