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.Arrays;
024import java.util.Collections;
025import java.util.List;
026import org.apache.hadoop.hbase.HConstants;
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.yetus.audience.InterfaceAudience;
032
033/**
034 * An implementation of {@link RegionLocator}. Used to view region location information for a single
035 * HBase table. Lightweight. Get as needed and just close when done. Instances of this class SHOULD
036 * NOT be constructed directly. Obtain an instance via {@link Connection}. See
037 * {@link ConnectionFactory} class comment for an example of how.
038 * <p/>
039 * This class is thread safe
040 */
041@InterfaceAudience.Private
042public class HRegionLocator implements RegionLocator {
043
044  private final TableName tableName;
045  private final ConnectionImplementation connection;
046
047  public HRegionLocator(TableName tableName, ConnectionImplementation connection) {
048    this.connection = connection;
049    this.tableName = tableName;
050  }
051
052  /**
053   * {@inheritDoc}
054   */
055  @Override
056  public void close() throws IOException {
057    // This method is required by the RegionLocator interface. This implementation does not have any
058    // persistent state, so there is no need to do anything here.
059  }
060
061  @Override
062  public HRegionLocation getRegionLocation(byte[] row, int replicaId, boolean reload)
063      throws IOException {
064    return connection.locateRegion(tableName, row, !reload, true, replicaId)
065      .getRegionLocation(replicaId);
066  }
067
068  @Override
069  public List<HRegionLocation> getRegionLocations(byte[] row, boolean reload) throws IOException {
070    RegionLocations locs =
071      connection.locateRegion(tableName, row, !reload, true, RegionInfo.DEFAULT_REPLICA_ID);
072    return Arrays.asList(locs.getRegionLocations());
073  }
074
075  @Override
076  public List<HRegionLocation> getAllRegionLocations() throws IOException {
077    ArrayList<HRegionLocation> regions = new ArrayList<>();
078    for (RegionLocations locations : listRegionLocations()) {
079      for (HRegionLocation location : locations.getRegionLocations()) {
080        regions.add(location);
081      }
082      connection.cacheLocation(tableName, locations);
083    }
084    return regions;
085  }
086
087  @Override
088  public void clearRegionLocationCache() {
089    connection.clearRegionCache(tableName);
090  }
091
092  @Override
093  public TableName getName() {
094    return this.tableName;
095  }
096
097  private List<RegionLocations> listRegionLocations() throws IOException {
098    if (TableName.isMetaTableName(tableName)) {
099      return Collections
100        .singletonList(connection.locateRegion(tableName, HConstants.EMPTY_START_ROW, false, true));
101    }
102    final List<RegionLocations> regions = new ArrayList<>();
103    MetaTableAccessor.Visitor visitor = new MetaTableAccessor.TableVisitorBase(tableName) {
104      @Override
105      public boolean visitInternal(Result result) throws IOException {
106        RegionLocations locations = MetaTableAccessor.getRegionLocations(result);
107        if (locations == null) {
108          return true;
109        }
110        regions.add(locations);
111        return true;
112      }
113    };
114    MetaTableAccessor.scanMetaForTableRegions(connection, visitor, tableName);
115    return regions;
116  }
117}