001/**
002*
003* Licensed to the Apache Software Foundation (ASF) under one
004* or more contributor license agreements.  See the NOTICE file
005* distributed with this work for additional information
006* regarding copyright ownership.  The ASF licenses this file
007* to you under the Apache License, Version 2.0 (the
008* "License"); you may not use this file except in compliance
009* with the License.  You may obtain a copy of the License at
010*
011*     http://www.apache.org/licenses/LICENSE-2.0
012*
013* Unless required by applicable law or agreed to in writing, software
014* distributed under the License is distributed on an "AS IS" BASIS,
015* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016* See the License for the specific language governing permissions and
017* limitations under the License.
018*/
019package org.apache.hadoop.hbase.client;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.List;
024
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.HRegionInfo;
027import org.apache.hadoop.hbase.HRegionLocation;
028import org.apache.hadoop.hbase.MetaTableAccessor;
029import org.apache.hadoop.hbase.RegionLocations;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.util.Pair;
032import org.apache.yetus.audience.InterfaceAudience;
033import org.apache.yetus.audience.InterfaceStability;
034
035import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
036
037/**
038 * An implementation of {@link RegionLocator}. Used to view region location information for a single
039 * HBase table. Lightweight. Get as needed and just close when done. Instances of this class SHOULD
040 * NOT be constructed directly. Obtain an instance via {@link Connection}. See
041 * {@link ConnectionFactory} class comment for an example of how.
042 *
043 * <p> This class is thread safe
044 */
045@InterfaceAudience.Private
046@InterfaceStability.Stable
047public class HRegionLocator implements RegionLocator {
048
049  private final TableName tableName;
050  private final ClusterConnection connection;
051
052  public HRegionLocator(TableName tableName, ClusterConnection connection) {
053    this.connection = connection;
054    this.tableName = tableName;
055  }
056
057  /**
058   * {@inheritDoc}
059   */
060  @Override
061  public void close() throws IOException {
062    // This method is required by the RegionLocator interface. This implementation does not have any
063    // persistent state, so there is no need to do anything here.
064  }
065
066  /**
067   * {@inheritDoc}
068   */
069  @Override
070  public HRegionLocation getRegionLocation(final byte [] row)
071  throws IOException {
072    return connection.getRegionLocation(tableName, row, false);
073  }
074
075  /**
076   * {@inheritDoc}
077   */
078  @Override
079  public HRegionLocation getRegionLocation(final byte [] row, boolean reload)
080  throws IOException {
081    return connection.getRegionLocation(tableName, row, reload);
082  }
083
084  @Override
085  public List<HRegionLocation> getAllRegionLocations() throws IOException {
086    TableName tableName = getName();
087    ArrayList<HRegionLocation> regions = new ArrayList<>();
088    for (RegionLocations locations : listRegionLocations()) {
089      for (HRegionLocation location : locations.getRegionLocations()) {
090        regions.add(location);
091      }
092      connection.cacheLocation(tableName, locations);
093    }
094    return regions;
095  }
096
097  /**
098   * {@inheritDoc}
099   */
100  @Override
101  public byte[][] getStartKeys() throws IOException {
102    return getStartEndKeys().getFirst();
103  }
104
105  /**
106   * {@inheritDoc}
107   */
108  @Override
109  public byte[][] getEndKeys() throws IOException {
110    return getStartEndKeys().getSecond();
111  }
112
113  /**
114   * {@inheritDoc}
115   */
116  @Override
117  public Pair<byte[][], byte[][]> getStartEndKeys() throws IOException {
118    return getStartEndKeys(listRegionLocations());
119  }
120
121  @VisibleForTesting
122  Pair<byte[][], byte[][]> getStartEndKeys(List<RegionLocations> regions) {
123    final byte[][] startKeyList = new byte[regions.size()][];
124    final byte[][] endKeyList = new byte[regions.size()][];
125
126    for (int i = 0; i < regions.size(); i++) {
127      HRegionInfo region = regions.get(i).getRegionLocation().getRegionInfo();
128      startKeyList[i] = region.getStartKey();
129      endKeyList[i] = region.getEndKey();
130    }
131
132    return new Pair<>(startKeyList, endKeyList);
133  }
134
135  @Override
136  public TableName getName() {
137    return this.tableName;
138  }
139
140  @VisibleForTesting
141  List<RegionLocations> listRegionLocations() throws IOException {
142    final List<RegionLocations> regions = new ArrayList<>();
143    MetaTableAccessor.Visitor visitor = new MetaTableAccessor.TableVisitorBase(tableName) {
144      @Override
145      public boolean visitInternal(Result result) throws IOException {
146        RegionLocations locations = MetaTableAccessor.getRegionLocations(result);
147        if (locations == null) return true;
148        regions.add(locations);
149        return true;
150      }
151    };
152    MetaTableAccessor.scanMetaForTableRegions(connection, visitor, tableName);
153    return regions;
154  }
155
156  public Configuration getConfiguration() {
157    return connection.getConfiguration();
158  }
159}