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 java.util.List;
021import java.util.concurrent.CompletableFuture;
022import java.util.stream.Collectors;
023import org.apache.hadoop.hbase.HConstants;
024import org.apache.hadoop.hbase.HRegionLocation;
025import org.apache.hadoop.hbase.TableName;
026import org.apache.hadoop.hbase.util.Pair;
027import org.apache.yetus.audience.InterfaceAudience;
028
029/**
030 * The asynchronous version of RegionLocator.
031 * <p>
032 * Usually the implementations will not throw any exception directly, you need to get the exception
033 * from the returned {@link CompletableFuture}.
034 * @since 2.0.0
035 */
036@InterfaceAudience.Public
037public interface AsyncTableRegionLocator {
038
039  /**
040   * Gets the fully qualified table name instance of the table whose region we want to locate.
041   */
042  TableName getName();
043
044  /**
045   * Finds the region on which the given row is being served. Does not reload the cache.
046   * <p/>
047   * Returns the location of the region to which the row belongs.
048   * @param row Row to find.
049   */
050  default CompletableFuture<HRegionLocation> getRegionLocation(byte[] row) {
051    return getRegionLocation(row, false);
052  }
053
054  /**
055   * Finds the region on which the given row is being served.
056   * <p/>
057   * Returns the location of the region to which the row belongs.
058   * @param row    Row to find.
059   * @param reload true to reload information or false to use cached information
060   */
061  default CompletableFuture<HRegionLocation> getRegionLocation(byte[] row, boolean reload) {
062    return getRegionLocation(row, RegionInfo.DEFAULT_REPLICA_ID, reload);
063  }
064
065  /**
066   * Finds the region with the given <code>replicaId</code> on which the given row is being served.
067   * <p/>
068   * Returns the location of the region with the given <code>replicaId</code> to which the row
069   * belongs.
070   * @param row       Row to find.
071   * @param replicaId the replica id of the region
072   */
073  default CompletableFuture<HRegionLocation> getRegionLocation(byte[] row, int replicaId) {
074    return getRegionLocation(row, replicaId, false);
075  }
076
077  /**
078   * Finds the region with the given <code>replicaId</code> on which the given row is being served.
079   * <p/>
080   * Returns the location of the region with the given <code>replicaId</code> to which the row
081   * belongs.
082   * @param row       Row to find.
083   * @param replicaId the replica id of the region
084   * @param reload    true to reload information or false to use cached information
085   */
086  CompletableFuture<HRegionLocation> getRegionLocation(byte[] row, int replicaId, boolean reload);
087
088  /**
089   * Find all the replicas for the region on which the given row is being served.
090   * @param row Row to find.
091   * @return Locations for all the replicas of the row.
092   */
093  default CompletableFuture<List<HRegionLocation>> getRegionLocations(byte[] row) {
094    return getRegionLocations(row, false);
095  }
096
097  /**
098   * Find all the replicas for the region on which the given row is being served.
099   * @param row    Row to find.
100   * @param reload true to reload information or false to use cached information
101   * @return Locations for all the replicas of the row.
102   */
103  CompletableFuture<List<HRegionLocation>> getRegionLocations(byte[] row, boolean reload);
104
105  /**
106   * Retrieves all of the regions associated with this table.
107   * <p/>
108   * Usually we will go to meta table directly in this method so there is no {@code reload}
109   * parameter.
110   * <p/>
111   * Notice that the location for region replicas other than the default replica are also returned.
112   * @return a {@link List} of all regions associated with this table.
113   */
114  CompletableFuture<List<HRegionLocation>> getAllRegionLocations();
115
116  /**
117   * Bulk lookup of region locations from {@code hbase:meta} in a single RPC, starting at
118   * {@code startKey} (region start-key boundary, inclusive) and returning at most {@code limit}
119   * regions in start-key order.
120   * <p/>
121   * The returned list includes all replicas of each region (matching
122   * {@link #getAllRegionLocations()}), and the result is also written to the connection's region
123   * location cache.
124   * <p/>
125   * Ordering: regions are returned in ascending region start-key order (the natural order of
126   * {@code hbase:meta} rows for a single table). Within each region, replicas are returned in
127   * ascending replica-id order (replica 0, then 1, then 2, ...). Split parents are filtered out,
128   * which may cause a page to contain fewer than {@code limit} regions but never disturbs ordering
129   * of the survivors.
130   * <p/>
131   * To page through all regions of a table, call repeatedly passing
132   * {@code last.getRegion().getEndKey()} as the next {@code startKey}, where {@code last} is the
133   * final element of the previous response. All replicas of a region share the same
134   * {@link RegionInfo}, so the last entry's end key is the correct cursor regardless of which
135   * replica it is. Pass {@code null} for the first call. Stop paging when the returned list is
136   * empty or when the last region's end key is {@link HConstants#EMPTY_END_ROW} (zero-length) -
137   * that signals the end of the table; passing it back in would re-scan from the beginning since by
138   * convention an empty start key means "from the first region".
139   * <p/>
140   * Unlike {@link #getAllRegionLocations()}, this method performs at most one RPC against
141   * {@code hbase:meta} per invocation, so its latency is bounded by {@code limit} rather than table
142   * size. The single-RPC behavior is best-effort: if the response would exceed
143   * {@code hbase.client.scanner.max.result.size} (default 2 MB), the server may split the slice
144   * across multiple {@code ScannerNext} RPCs. For typical meta row sizes and default caching this
145   * rarely fires, but callers passing large {@code limit} values against clusters with replicas or
146   * heavy meta rows should treat single-RPC as a soft guarantee, not absolute. Note that this
147   * method does not coordinate with other in-flight meta lookups on the connection - aggregate
148   * pacing across concurrent callers is the caller's responsibility.
149   * <p/>
150   * This method is optional. Implementations that cannot support paginated lookups will return a
151   * future that completes exceptionally with {@link UnsupportedOperationException} (the default
152   * behavior); callers should fall back to {@link #getAllRegionLocations()} in that case.
153   * @param startKey region start-key to begin scanning from (inclusive); {@code null} or empty
154   *                 starts from the first region
155   * @param limit    maximum number of regions to return. If &lt;= 0, falls back to
156   *                 {@code hbase.meta.scanner.caching} - this is a SOFT cap on a single page, NOT
157   *                 "all regions"; tables larger than the cap still require the caller to keep
158   *                 paging via {@code last.getRegion().getEndKey()}.
159   * @return up to {@code limit} {@link HRegionLocation}s in start-key order, possibly empty when no
160   *         more regions exist; errors are reported via the returned future
161   */
162  default CompletableFuture<List<HRegionLocation>> getRegionLocationsPage(byte[] startKey,
163    int limit) {
164    CompletableFuture<List<HRegionLocation>> failed = new CompletableFuture<>();
165    failed.completeExceptionally(new UnsupportedOperationException(
166      "getRegionLocationsPage(byte[], int) is not supported by this AsyncTableRegionLocator;"
167        + " fall back to getAllRegionLocations()"));
168    return failed;
169  }
170
171  /**
172   * Gets the starting row key for every region in the currently open table.
173   * <p>
174   * This is mainly useful for the MapReduce integration.
175   * @return Array of region starting row keys
176   */
177  default CompletableFuture<List<byte[]>> getStartKeys() {
178    return getStartEndKeys().thenApply(
179      startEndKeys -> startEndKeys.stream().map(Pair::getFirst).collect(Collectors.toList()));
180  }
181
182  /**
183   * Gets the ending row key for every region in the currently open table.
184   * <p>
185   * This is mainly useful for the MapReduce integration.
186   * @return Array of region ending row keys
187   */
188  default CompletableFuture<List<byte[]>> getEndKeys() {
189    return getStartEndKeys().thenApply(
190      startEndKeys -> startEndKeys.stream().map(Pair::getSecond).collect(Collectors.toList()));
191  }
192
193  /**
194   * Gets the starting and ending row keys for every region in the currently open table.
195   * <p>
196   * This is mainly useful for the MapReduce integration.
197   * @return Pair of arrays of region starting and ending row keys
198   */
199  default CompletableFuture<List<Pair<byte[], byte[]>>> getStartEndKeys() {
200    return getAllRegionLocations().thenApply(
201      locs -> locs.stream().filter(loc -> RegionReplicaUtil.isDefaultReplica(loc.getRegion()))
202        .map(HRegionLocation::getRegion).map(r -> Pair.newPair(r.getStartKey(), r.getEndKey()))
203        .collect(Collectors.toList()));
204  }
205
206  /**
207   * Clear all the entries in the region location cache.
208   * <p/>
209   * This may cause performance issue so use it with caution.
210   */
211  void clearRegionLocationCache();
212}