View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.util;
19  
20  import java.io.IOException;
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.TreeMap;
28  import java.util.TreeSet;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.ClusterStatus;
34  import org.apache.hadoop.hbase.HRegionLocation;
35  import org.apache.hadoop.hbase.RegionLoad;
36  import org.apache.hadoop.hbase.ServerLoad;
37  import org.apache.hadoop.hbase.ServerName;
38  import org.apache.hadoop.hbase.classification.InterfaceAudience;
39  import org.apache.hadoop.hbase.classification.InterfaceStability;
40  import org.apache.hadoop.hbase.client.Admin;
41  import org.apache.hadoop.hbase.client.HBaseAdmin;
42  import org.apache.hadoop.hbase.client.HTable;
43  import org.apache.hadoop.hbase.client.RegionLocator;
44  
45  /**
46   * Computes size of each region for given table and given column families.
47   * The value is used by MapReduce for better scheduling.
48   * */
49  @InterfaceStability.Evolving
50  @InterfaceAudience.Private
51  public class RegionSizeCalculator {
52  
53    private static final Log LOG = LogFactory.getLog(RegionSizeCalculator.class);
54  
55    /**
56     * Maps each region to its size in bytes.
57     * */
58    private final Map<byte[], Long> sizeMap = new TreeMap<byte[], Long>(Bytes.BYTES_COMPARATOR);
59  
60    static final String ENABLE_REGIONSIZECALCULATOR = "hbase.regionsizecalculator.enable";
61  
62    /**
63     * Computes size of each region for table and given column families.
64     * 
65     * @deprecated Use {@link #RegionSizeCalculator(RegionLocator, Admin)} instead.
66     */
67    @Deprecated
68    public RegionSizeCalculator(HTable table) throws IOException {
69      HBaseAdmin admin = new HBaseAdmin(table.getConfiguration());
70      try {
71        init(table.getRegionLocator(), admin);
72      } finally {
73        admin.close();
74      }
75    }
76  
77    /**
78     * Computes size of each region for table and given column families.
79     * */
80    public RegionSizeCalculator(RegionLocator regionLocator, Admin admin) throws IOException {
81      init(regionLocator, admin);
82    }
83  
84    private void init(RegionLocator regionLocator, Admin admin)
85        throws IOException {
86      if (!enabled(admin.getConfiguration())) {
87        LOG.info("Region size calculation disabled.");
88        return;
89      }
90  
91      LOG.info("Calculating region sizes for table \"" + regionLocator.getName() + "\".");
92  
93      //get regions for table
94      List<HRegionLocation> tableRegionInfos = regionLocator.getAllRegionLocations();
95      Set<byte[]> tableRegions = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
96      for (HRegionLocation regionInfo : tableRegionInfos) {
97        tableRegions.add(regionInfo.getRegionInfo().getRegionName());
98      }
99  
100     ClusterStatus clusterStatus = admin.getClusterStatus();
101     Collection<ServerName> servers = clusterStatus.getServers();
102     final long megaByte = 1024L * 1024L;
103 
104     //iterate all cluster regions, filter regions from our table and compute their size
105     for (ServerName serverName: servers) {
106       ServerLoad serverLoad = clusterStatus.getLoad(serverName);
107 
108       for (RegionLoad regionLoad: serverLoad.getRegionsLoad().values()) {
109         byte[] regionId = regionLoad.getName();
110 
111         if (tableRegions.contains(regionId)) {
112 
113           long regionSizeBytes = regionLoad.getStorefileSizeMB() * megaByte;
114           sizeMap.put(regionId, regionSizeBytes);
115 
116           if (LOG.isDebugEnabled()) {
117             LOG.debug("Region " + regionLoad.getNameAsString() + " has size " + regionSizeBytes);
118           }
119         }
120       }
121     }
122     LOG.debug("Region sizes calculated");
123   }
124 
125   boolean enabled(Configuration configuration) {
126     return configuration.getBoolean(ENABLE_REGIONSIZECALCULATOR, true);
127   }
128 
129   /**
130    * Returns size of given region in bytes. Returns 0 if region was not found.
131    * */
132   public long getRegionSize(byte[] regionId) {
133     Long size = sizeMap.get(regionId);
134     if (size == null) {
135       LOG.debug("Unknown region:" + Arrays.toString(regionId));
136       return 0;
137     } else {
138       return size;
139     }
140   }
141 
142   public Map<byte[], Long> getRegionSizeMap() {
143     return Collections.unmodifiableMap(sizeMap);
144   }
145 }