001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.apache.hadoop.hbase.util.FutureUtils.addListener;
021
022import java.io.IOException;
023import java.util.Map;
024import java.util.Optional;
025import java.util.concurrent.CompletableFuture;
026import org.apache.hadoop.hbase.HRegionLocation;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.ipc.HBaseRpcController;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.apache.yetus.audience.InterfaceAudience;
031
032import org.apache.hbase.thirdparty.io.netty.util.Timer;
033
034import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService;
035
036/**
037 * Retry caller for a single request, such as get, put, delete, etc.
038 */
039@InterfaceAudience.Private
040class AsyncSingleRequestRpcRetryingCaller<T> extends AsyncRpcRetryingCaller<T> {
041
042  @FunctionalInterface
043  public interface Callable<T> {
044    CompletableFuture<T> call(HBaseRpcController controller, HRegionLocation loc,
045      ClientService.Interface stub);
046  }
047
048  private final TableName tableName;
049
050  private final byte[] row;
051
052  private final int replicaId;
053
054  private final RegionLocateType locateType;
055
056  private final Callable<T> callable;
057
058  public AsyncSingleRequestRpcRetryingCaller(Timer retryTimer, AsyncConnectionImpl conn,
059    TableName tableName, byte[] row, int replicaId, RegionLocateType locateType,
060    Callable<T> callable, int priority, long pauseNs, long pauseNsForServerOverloaded,
061    int maxAttempts, long operationTimeoutNs, long rpcTimeoutNs, int startLogErrorsCnt,
062    Map<String, byte[]> requestAttributes) {
063    super(retryTimer, conn, priority, pauseNs, pauseNsForServerOverloaded, maxAttempts,
064      operationTimeoutNs, rpcTimeoutNs, startLogErrorsCnt, requestAttributes);
065    this.tableName = tableName;
066    this.row = row;
067    this.replicaId = replicaId;
068    this.locateType = locateType;
069    this.callable = callable;
070  }
071
072  private void call(HRegionLocation loc) {
073    ClientService.Interface stub;
074    try {
075      stub = conn.getRegionServerStub(loc.getServerName());
076    } catch (IOException e) {
077      onError(e,
078        () -> "Get async stub to " + loc.getServerName() + " for '" + Bytes.toStringBinary(row)
079          + "' in " + loc.getRegion().getEncodedName() + " of " + tableName + " failed",
080        err -> conn.getLocator().updateCachedLocationOnError(loc, err));
081      return;
082    }
083    resetCallTimeout();
084    addListener(callable.call(controller, loc, stub), (result, error) -> {
085      if (error != null) {
086        onError(error,
087          () -> "Call to " + loc.getServerName() + " for '" + Bytes.toStringBinary(row) + "' in "
088            + loc.getRegion().getEncodedName() + " of " + tableName + " failed",
089          err -> conn.getLocator().updateCachedLocationOnError(loc, err));
090        return;
091      }
092      future.complete(result);
093    });
094  }
095
096  @Override
097  protected void doCall() {
098    long locateTimeoutNs;
099    if (operationTimeoutNs > 0) {
100      locateTimeoutNs = remainingTimeNs();
101      if (locateTimeoutNs <= 0) {
102        completeExceptionally();
103        return;
104      }
105    } else {
106      locateTimeoutNs = -1L;
107    }
108    addListener(
109      conn.getLocator().getRegionLocation(tableName, row, replicaId, locateType, locateTimeoutNs),
110      (loc, error) -> {
111        if (error != null) {
112          onError(error,
113            () -> "Locate '" + Bytes.toStringBinary(row) + "' in " + tableName + " failed", err -> {
114            });
115          return;
116        }
117        call(loc);
118      });
119  }
120
121  @Override
122  protected Optional<TableName> getTableName() {
123    return Optional.of(tableName);
124  }
125}