/**
  * Gets a stream to write data to a block. The stream can only be backed by Alluxio storage.
  *
  * @param blockId the block to write
  * @param blockSize the standard block size to write, or -1 if the block already exists (and this
  *     stream is just storing the block in Alluxio again)
  * @param address the address of the worker to write the block to, fails if the worker cannot
  *     serve the request
  * @return a {@link BufferedBlockOutStream} which can be used to write data to the block in a
  *     streaming fashion
  * @throws IOException if the block cannot be written
  */
 public BufferedBlockOutStream getOutStream(long blockId, long blockSize, WorkerNetAddress address)
     throws IOException {
   if (blockSize == -1) {
     try (CloseableResource<BlockMasterClient> blockMasterClientResource =
         mContext.acquireMasterClientResource()) {
       blockSize = blockMasterClientResource.get().getBlockInfo(blockId).getLength();
     } catch (AlluxioException e) {
       throw new IOException(e);
     }
   }
   // No specified location to write to.
   if (address == null) {
     throw new RuntimeException(ExceptionMessage.NO_WORKER_AVAILABLE.getMessage());
   }
   // Location is local.
   if (NetworkAddressUtils.getLocalHostName(ClientContext.getConf()).equals(address.getHost())) {
     if (mContext.hasLocalWorker()) {
       return new LocalBlockOutStream(blockId, blockSize);
     } else {
       throw new IOException(ExceptionMessage.NO_LOCAL_WORKER.getMessage("write"));
     }
   }
   // Location is specified and it is remote.
   return new RemoteBlockOutStream(blockId, blockSize, address);
 }
 /**
  * Obtains a client for a remote based on the given network address. Illegal argument exception is
  * thrown if the hostname is the local hostname. Runtime exception is thrown if the client cannot
  * be created with a connection to the hostname.
  *
  * @param address the address of the worker
  * @return a worker client with a connection to the specified hostname
  */
 private BlockWorkerClient acquireRemoteWorkerClient(WorkerNetAddress address) {
   // If we couldn't find a worker, crash.
   if (address == null) {
     // TODO(calvin): Better exception usage.
     throw new RuntimeException(ExceptionMessage.NO_WORKER_AVAILABLE.getMessage());
   }
   Preconditions.checkArgument(
       !address.getHost().equals(NetworkAddressUtils.getLocalHostName()),
       PreconditionMessage.REMOTE_CLIENT_BUT_LOCAL_HOSTNAME);
   long clientId = IdUtils.getRandomNonNegativeLong();
   return new RetryHandlingBlockWorkerClient(
       address, ClientContext.getBlockClientExecutorService(), clientId, false);
 }
 /**
  * Obtains a client for a worker with the given address.
  *
  * @param address the address of the worker to get a client to
  * @return a {@link BlockWorkerClient} connected to the worker with the given hostname
  * @throws IOException if no Alluxio worker is available for the given hostname
  */
 public BlockWorkerClient acquireWorkerClient(WorkerNetAddress address) throws IOException {
   BlockWorkerClient client;
   if (address == null) {
     throw new RuntimeException(ExceptionMessage.NO_WORKER_AVAILABLE.getMessage());
   }
   if (address.getHost().equals(NetworkAddressUtils.getLocalHostName())) {
     client = acquireLocalWorkerClient(address);
     if (client == null) {
       throw new IOException(ExceptionMessage.NO_WORKER_AVAILABLE_ON_ADDRESS.getMessage(address));
     }
   } else {
     client = acquireRemoteWorkerClient(address);
   }
   return client;
 }