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 org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.classification.InterfaceStability;
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.hbase.ClusterStatus;
26  import org.apache.hadoop.hbase.HRegionInfo;
27  import org.apache.hadoop.hbase.RegionLoad;
28  import org.apache.hadoop.hbase.ServerLoad;
29  import org.apache.hadoop.hbase.ServerName;
30  import org.apache.hadoop.hbase.client.HBaseAdmin;
31  import org.apache.hadoop.hbase.client.HTable;
32  
33  import java.io.IOException;
34  import java.text.MessageFormat;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.Collections;
38  import java.util.Map;
39  import java.util.Set;
40  import java.util.TreeMap;
41  import java.util.TreeSet;
42  
43  /**
44   * Computes size of each region for given table and given column families.
45   * The value is used by MapReduce for better scheduling.
46   * */
47  @InterfaceStability.Evolving
48  @InterfaceAudience.Private
49  public class RegionSizeCalculator {
50  
51    private static final Log LOG = LogFactory.getLog(RegionSizeCalculator.class);
52  
53    /**
54     * Maps each region to its size in bytes.
55     * */
56    private final Map<byte[], Long> sizeMap = new TreeMap<byte[], Long>(Bytes.BYTES_COMPARATOR);
57  
58    static final String ENABLE_REGIONSIZECALCULATOR = "hbase.regionsizecalculator.enable";
59  
60    /**
61     * Computes size of each region for table and given column families.
62     * */
63    public RegionSizeCalculator(HTable table) throws IOException {
64      this(table, new HBaseAdmin(table.getConfiguration()));
65    }
66  
67    /** ctor for unit testing */
68    RegionSizeCalculator (HTable table, HBaseAdmin admin) throws IOException {
69  
70      try {
71        if (!enabled(table.getConfiguration())) {
72          LOG.info("Region size calculation disabled.");
73          return;
74        }
75  
76        LOG.info("Calculating region sizes for table \"" + new String(table.getTableName()) + "\".");
77  
78        //get regions for table
79        Set<HRegionInfo> tableRegionInfos = table.getRegionLocations().keySet();
80        Set<byte[]> tableRegions = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
81        for (HRegionInfo regionInfo : tableRegionInfos) {
82          tableRegions.add(regionInfo.getRegionName());
83        }
84  
85        ClusterStatus clusterStatus = admin.getClusterStatus();
86        Collection<ServerName> servers = clusterStatus.getServers();
87        final long megaByte = 1024L * 1024L;
88  
89        //iterate all cluster regions, filter regions from our table and compute their size
90        for (ServerName serverName: servers) {
91          ServerLoad serverLoad = clusterStatus.getLoad(serverName);
92  
93          for (RegionLoad regionLoad: serverLoad.getRegionsLoad().values()) {
94            byte[] regionId = regionLoad.getName();
95  
96            if (tableRegions.contains(regionId)) {
97  
98              long regionSizeBytes = regionLoad.getStorefileSizeMB() * megaByte;
99              sizeMap.put(regionId, regionSizeBytes);
100 
101             if (LOG.isDebugEnabled()) {
102               LOG.debug("Region " + regionLoad.getNameAsString() + " has size " + regionSizeBytes);
103             }
104           }
105         }
106       }
107       LOG.debug("Region sizes calculated");
108 
109     } finally {
110       admin.close();
111     }
112 
113   }
114 
115   boolean enabled(Configuration configuration) {
116     return configuration.getBoolean(ENABLE_REGIONSIZECALCULATOR, true);
117   }
118 
119   /**
120    * Returns size of given region in bytes. Returns 0 if region was not found.
121    * */
122   public long getRegionSize(byte[] regionId) {
123     Long size = sizeMap.get(regionId);
124     if (size == null) {
125       LOG.debug("Unknown region:" + Arrays.toString(regionId));
126       return 0;
127     } else {
128       return size;
129     }
130   }
131 
132   public Map<byte[], Long> getRegionSizeMap() {
133     return Collections.unmodifiableMap(sizeMap);
134   }
135 }