@InterfaceAudience.Private
  protected CompletableFuture<Collection<LoadQueueItem>> tryAtomicRegionLoad(
    final AsyncClusterConnection conn, final TableName tableName, boolean copyFiles,
    final byte[] first, Collection<LoadQueueItem> lqis) {
    List<Pair<byte[], String>> familyPaths =
      lqis.stream().map(lqi -> Pair.newPair(lqi.getFamily(), lqi.getFilePath().toString()))
        .collect(Collectors.toList());
    CompletableFuture<Collection<LoadQueueItem>> future = new CompletableFuture<>();
    FutureUtils.addListener(conn.bulkLoad(tableName, familyPaths, first, assignSeqIds,
      fsDelegationToken.getUserToken(), bulkToken, copyFiles, clusterIds, replicate),
      (loaded, error) -> {
        if (error != null) {
          LOG.error("Encountered unrecoverable error from region server", error);
          if (
            getConf().getBoolean(RETRY_ON_IO_EXCEPTION, false)
              && numRetries.get() < getConf().getInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER,
                HConstants.DEFAULT_HBASE_CLIENT_RETRIES_NUMBER)
          ) {
            LOG.warn("Will attempt to retry loading failed HFiles. Retry #"
              + numRetries.incrementAndGet());
            // return lqi's to retry
            future.complete(lqis);
          } else {
            LOG.error(RETRY_ON_IO_EXCEPTION
              + " is disabled or we have reached retry limit. Unable to recover");
            future.completeExceptionally(error);
          }
        } else {
          if (loaded) {
            future.complete(Collections.emptyList());
          } else {
            LOG.warn("Attempt to bulk load region containing " + Bytes.toStringBinary(first)
              + " into table " + tableName + " with files " + lqis
              + " failed.  This is recoverable and they will be retried.");
            // return lqi's to retry
            future.complete(lqis);
          }
        }
      });
    return future;
  }
Attempts to do an atomic load of many hfiles into a region. If it fails, it returns a list of
hfiles that need to be retried. If it is successful it will return an empty list. NOTE: To
maintain row atomicity guarantees, region server side should succeed atomically and fails
atomically.
@param conn      Connection to use
@param tableName Table to which these hfiles should be loaded to
@param copyFiles whether replicate to peer cluster while bulkloading
@param first     the start key of region
@param lqis      hfiles should be loaded
@return empty list if success, list of items to retry on recoverable failure
hbase-server/src/main/java/org/apache/hadoop/hbase/tool/BulkLoadHFilesTool.java