private <S, R> CompletableFuture<R> coprocessorService(Function<RpcChannel, S> stubMaker,
    ServiceCaller<S, R> callable, RegionInfo region, byte[] row) {
    RegionCoprocessorRpcChannelImpl channel = new RegionCoprocessorRpcChannelImpl(conn, tableName,
      region, row, rpcTimeoutNs, operationTimeoutNs);
    final Span span = Span.current();
    S stub = stubMaker.apply(channel);
    CompletableFuture<R> future = new CompletableFuture<>();
    ClientCoprocessorRpcController controller = new ClientCoprocessorRpcController();
    callable.call(stub, controller, resp -> {
      try (Scope ignored = span.makeCurrent()) {
        if (controller.failed()) {
          final Throwable failure = controller.getFailed();
          future.completeExceptionally(failure);
          TraceUtil.setError(span, failure);
        } else {
          future.complete(resp);
          span.setStatus(StatusCode.OK);
        }
      } finally {
        span.end();
      }
    });
    return future;
  }
The implementation of RawAsyncTable.
<p/>
The word 'Raw' means that this is a low level class. The returned {@link CompletableFuture} will
be finished inside the rpc framework thread, which means that the callbacks registered to the
{@link CompletableFuture} will also be executed inside the rpc framework thread. So users who use
this class should not try to do time consuming tasks in the callbacks.
@since 2.0.0
@see AsyncTableImpl
hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncTableImpl.java