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; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HConstants; 025import org.apache.hadoop.hbase.TableName; 026import org.apache.yetus.audience.InterfaceAudience; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029import org.apache.hadoop.hbase.client.TableDescriptor; 030import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 031import org.apache.hadoop.hbase.procedure2.util.StringUtils; 032 033/** 034 * Split size is the number of regions that are on this server that all are 035 * of the same table, cubed, times 2x the region flush size OR the maximum 036 * region split size, whichever is smaller. 037 * <p> 038 * For example, if the flush size is 128MB, then after two flushes (256MB) we 039 * will split which will make two regions that will split when their size is 040 * {@code 2^3 * 128MB*2 = 2048MB}. 041 * <p> 042 * If one of these regions splits, then there are three regions and now the 043 * split size is {@code 3^3 * 128MB*2 = 6912MB}, and so on until we reach the configured 044 * maximum file size and then from there on out, we'll use that. 045 */ 046@InterfaceAudience.Private 047public class IncreasingToUpperBoundRegionSplitPolicy extends ConstantSizeRegionSplitPolicy { 048 private static final Logger LOG = 049 LoggerFactory.getLogger(IncreasingToUpperBoundRegionSplitPolicy.class); 050 051 protected long initialSize; 052 053 @Override 054 protected void configureForRegion(HRegion region) { 055 super.configureForRegion(region); 056 Configuration conf = getConf(); 057 initialSize = conf.getLong("hbase.increasing.policy.initial.size", -1); 058 if (initialSize > 0) { 059 return; 060 } 061 TableDescriptor desc = region.getTableDescriptor(); 062 if (desc != null) { 063 initialSize = 2 * desc.getMemStoreFlushSize(); 064 } 065 if (initialSize <= 0) { 066 initialSize = 2 * conf.getLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, 067 TableDescriptorBuilder.DEFAULT_MEMSTORE_FLUSH_SIZE); 068 } 069 } 070 071 @Override 072 protected boolean shouldSplit() { 073 boolean force = region.shouldForceSplit(); 074 boolean foundABigStore = false; 075 // Get count of regions that have the same common table as this.region 076 int tableRegionsCount = getCountOfCommonTableRegions(); 077 // Get size to check 078 long sizeToCheck = getSizeToCheck(tableRegionsCount); 079 080 for (HStore store : region.getStores()) { 081 // If any of the stores is unable to split (eg they contain reference files) 082 // then don't split 083 if (!store.canSplit()) { 084 return false; 085 } 086 087 // Mark if any store is big enough 088 long size = store.getSize(); 089 if (size > sizeToCheck) { 090 LOG.debug("ShouldSplit because " + store.getColumnFamilyName() + 091 " size=" + StringUtils.humanSize(size) + 092 ", sizeToCheck=" + StringUtils.humanSize(sizeToCheck) + 093 ", regionsWithCommonTable=" + tableRegionsCount); 094 foundABigStore = true; 095 } 096 } 097 098 return foundABigStore || force; 099 } 100 101 /** 102 * @return Count of regions on this server that share the table this.region 103 * belongs to 104 */ 105 private int getCountOfCommonTableRegions() { 106 RegionServerServices rss = region.getRegionServerServices(); 107 // Can be null in tests 108 if (rss == null) { 109 return 0; 110 } 111 TableName tablename = region.getTableDescriptor().getTableName(); 112 int tableRegionsCount = 0; 113 try { 114 List<? extends Region> hri = rss.getRegions(tablename); 115 tableRegionsCount = hri == null || hri.isEmpty() ? 0 : hri.size(); 116 } catch (IOException e) { 117 LOG.debug("Failed getOnlineRegions " + tablename, e); 118 } 119 return tableRegionsCount; 120 } 121 122 /** 123 * @return Region max size or {@code count of regions cubed * 2 * flushsize}, 124 * which ever is smaller; guard against there being zero regions on this server. 125 */ 126 protected long getSizeToCheck(final int tableRegionsCount) { 127 // safety check for 100 to avoid numerical overflow in extreme cases 128 return tableRegionsCount == 0 || tableRegionsCount > 100 129 ? getDesiredMaxFileSize() 130 : Math.min(getDesiredMaxFileSize(), 131 initialSize * tableRegionsCount * tableRegionsCount * tableRegionsCount); 132 } 133}