001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.io.IOException; 021import java.util.List; 022import java.util.Optional; 023 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.conf.Configured; 026import org.apache.hadoop.hbase.HBaseInterfaceAudience; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.client.TableDescriptor; 030import org.apache.hadoop.util.ReflectionUtils; 031import org.apache.yetus.audience.InterfaceAudience; 032import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 033 034 035/** 036 * A split policy determines when a Region should be split. 037 * 038 * @see SteppingSplitPolicy Default split policy since 2.0.0 039 * @see IncreasingToUpperBoundRegionSplitPolicy Default split policy since 040 * 0.94.0 041 * @see ConstantSizeRegionSplitPolicy Default split policy before 0.94.0 042 */ 043@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) 044public abstract class RegionSplitPolicy extends Configured { 045 private static final Class<? extends RegionSplitPolicy> 046 DEFAULT_SPLIT_POLICY_CLASS = SteppingSplitPolicy.class; 047 048 /** 049 * The region configured for this split policy. 050 * As of hbase-2.0.0, RegionSplitPolicy can be instantiated on the Master-side so the 051 * Phoenix local-indexer can block default hbase behavior. This is an exotic usage. Should not 052 * trouble any other users of RegionSplitPolicy. 053 */ 054 protected HRegion region; 055 056 /** 057 * Upon construction, this method will be called with the region 058 * to be governed. It will be called once and only once. 059 */ 060 protected void configureForRegion(HRegion region) { 061 Preconditions.checkState( 062 this.region == null, 063 "Policy already configured for region {}", 064 this.region); 065 066 this.region = region; 067 } 068 069 /** 070 * @return true if the specified region should be split. 071 */ 072 protected abstract boolean shouldSplit(); 073 074 /** 075 * @return {@code true} if the specified region can be split. 076 */ 077 protected boolean canSplit() { 078 return !region.getRegionInfo().isMetaRegion() && region.isAvailable() && 079 !TableName.NAMESPACE_TABLE_NAME.equals(region.getRegionInfo().getTable()) && 080 region.getStores().stream().allMatch(HStore::canSplit); 081 } 082 083 /** 084 * @return the key at which the region should be split, or null 085 * if it cannot be split. This will only be called if shouldSplit 086 * previously returned true. 087 */ 088 protected byte[] getSplitPoint() { 089 List<HStore> stores = region.getStores(); 090 091 byte[] splitPointFromLargestStore = null; 092 long largestStoreSize = 0; 093 for (HStore s : stores) { 094 Optional<byte[]> splitPoint = s.getSplitPoint(); 095 // Store also returns null if it has references as way of indicating it is not splittable 096 long storeSize = s.getSize(); 097 if (splitPoint.isPresent() && largestStoreSize < storeSize) { 098 splitPointFromLargestStore = splitPoint.get(); 099 largestStoreSize = storeSize; 100 } 101 } 102 103 return splitPointFromLargestStore; 104 } 105 106 /** 107 * Create the RegionSplitPolicy configured for the given table. 108 * @param region 109 * @param conf 110 * @return a RegionSplitPolicy 111 * @throws IOException 112 */ 113 public static RegionSplitPolicy create(HRegion region, 114 Configuration conf) throws IOException { 115 Preconditions.checkNotNull(region, "Region should not be null."); 116 Class<? extends RegionSplitPolicy> clazz = getSplitPolicyClass( 117 region.getTableDescriptor(), conf); 118 RegionSplitPolicy policy = ReflectionUtils.newInstance(clazz, conf); 119 policy.configureForRegion(region); 120 return policy; 121 } 122 123 public static Class<? extends RegionSplitPolicy> getSplitPolicyClass( 124 TableDescriptor htd, Configuration conf) throws IOException { 125 String className = htd.getRegionSplitPolicyClassName(); 126 if (className == null) { 127 className = conf.get(HConstants.HBASE_REGION_SPLIT_POLICY_KEY, 128 DEFAULT_SPLIT_POLICY_CLASS.getName()); 129 } 130 131 try { 132 Class<? extends RegionSplitPolicy> clazz = 133 Class.forName(className).asSubclass(RegionSplitPolicy.class); 134 return clazz; 135 } catch (Exception e) { 136 throw new IOException( 137 "Unable to load configured region split policy '" + 138 className + "' for table '" + htd.getTableName() + "'", 139 e); 140 } 141 } 142 143 /** 144 * In {@link HRegionFileSystem#splitStoreFile(org.apache.hadoop.hbase.client.RegionInfo, String, 145 * HStoreFile, byte[], boolean, RegionSplitPolicy)} we are not creating the split reference 146 * if split row does not lie inside the StoreFile range. But in some use cases we may need to 147 * create the split reference even when the split row does not lie inside the StoreFile range. 148 * This method can be used to decide, whether to skip the the StoreFile range check or not. 149 * 150 * <p>This method is not for general use. It is a mechanism put in place by Phoenix 151 * local indexing to defeat standard hbase behaviors. Phoenix local indices are very likely 152 * the only folks who would make use of this method. On the Master-side, we will instantiate 153 * a RegionSplitPolicy instance and run this method ONLY... none of the others make sense 154 * on the Master-side.</p> 155 * 156 * TODO: Shutdown this phoenix specialization or do it via some other means. 157 * @return whether to skip the StoreFile range check or not 158 */ 159 protected boolean skipStoreFileRangeCheck(String familyName) { 160 return false; 161 } 162}