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