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.regionserver;
19  
20  import java.io.IOException;
21  import java.util.List;
22  
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.conf.Configured;
26  import org.apache.hadoop.hbase.HBaseInterfaceAudience;
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.HTableDescriptor;
29  import org.apache.hadoop.util.ReflectionUtils;
30  
31  import com.google.common.base.Preconditions;
32  
33  /**
34   * A split policy determines when a region should be split.
35   * @see IncreasingToUpperBoundRegionSplitPolicy Default split policy since
36   *      0.94.0
37   * @see ConstantSizeRegionSplitPolicy Default split policy before 0.94.0
38   */
39  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
40  public abstract class RegionSplitPolicy extends Configured {
41    private static final Class<? extends RegionSplitPolicy>
42      DEFAULT_SPLIT_POLICY_CLASS = IncreasingToUpperBoundRegionSplitPolicy.class;
43  
44    /**
45     * The region configured for this split policy.
46     */
47    protected HRegion region;
48  
49    /**
50     * Upon construction, this method will be called with the region
51     * to be governed. It will be called once and only once.
52     */
53    protected void configureForRegion(HRegion region) {
54      Preconditions.checkState(
55          this.region == null,
56          "Policy already configured for region {}",
57          this.region);
58  
59      this.region = region;
60    }
61  
62    /**
63     * @return true if the specified region should be split.
64     */
65    protected abstract boolean shouldSplit();
66  
67    /**
68     * @return the key at which the region should be split, or null
69     * if it cannot be split. This will only be called if shouldSplit
70     * previously returned true.
71     */
72    protected byte[] getSplitPoint() {
73      byte[] explicitSplitPoint = this.region.getExplicitSplitPoint();
74      if (explicitSplitPoint != null) {
75        return explicitSplitPoint;
76      }
77      List<Store> stores = region.getStores();
78  
79      byte[] splitPointFromLargestStore = null;
80      long largestStoreSize = 0;
81      for (Store s : stores) {
82        byte[] splitPoint = s.getSplitPoint();
83        // Store also returns null if it has references as way of indicating it is not splittable
84        long storeSize = s.getSize();
85        if (splitPoint != null && largestStoreSize < storeSize) {
86          splitPointFromLargestStore = splitPoint;
87          largestStoreSize = storeSize;
88        }
89      }
90  
91      return splitPointFromLargestStore;
92    }
93  
94    /**
95     * Create the RegionSplitPolicy configured for the given table.
96     * @param region
97     * @param conf
98     * @return a RegionSplitPolicy
99     * @throws IOException
100    */
101   public static RegionSplitPolicy create(HRegion region,
102       Configuration conf) throws IOException {
103     Class<? extends RegionSplitPolicy> clazz = getSplitPolicyClass(
104         region.getTableDesc(), conf);
105     RegionSplitPolicy policy = ReflectionUtils.newInstance(clazz, conf);
106     policy.configureForRegion(region);
107     return policy;
108   }
109 
110   public static Class<? extends RegionSplitPolicy> getSplitPolicyClass(
111       HTableDescriptor htd, Configuration conf) throws IOException {
112     String className = htd.getRegionSplitPolicyClassName();
113     if (className == null) {
114       className = conf.get(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
115           DEFAULT_SPLIT_POLICY_CLASS.getName());
116     }
117 
118     try {
119       Class<? extends RegionSplitPolicy> clazz =
120         Class.forName(className).asSubclass(RegionSplitPolicy.class);
121       return clazz;
122     } catch (Exception  e) {
123       throw new IOException(
124           "Unable to load configured region split policy '" +
125           className + "' for table '" + htd.getTableName() + "'",
126           e);
127     }
128   }
129 
130   /**
131    * In {@link HRegionFileSystem#splitStoreFile(org.apache.hadoop.hbase.HRegionInfo, String,
132    * StoreFile, byte[], boolean, RegionSplitPolicy)} we are not creating the split reference
133    * if split row not lies in the StoreFile range. But in some use cases we may need to create
134    * the split reference even when the split row not lies in the range. This method can be used
135    * to decide, whether to skip the the StoreFile range check or not.
136    * @return whether to skip the StoreFile range check or not
137    * @param familyName
138    * @return whether to skip the StoreFile range check or not
139    */
140   protected boolean skipStoreFileRangeCheck(String familyName) {
141     return false;
142   }
143 }