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.util.concurrent.ThreadLocalRandom; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.hbase.HBaseInterfaceAudience; 023import org.apache.hadoop.hbase.HConstants; 024import org.apache.hadoop.hbase.client.TableDescriptor; 025import org.apache.hadoop.hbase.conf.ConfigKey; 026import org.apache.hadoop.hbase.procedure2.util.StringUtils; 027import org.apache.yetus.audience.InterfaceAudience; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * A {@link RegionSplitPolicy} implementation which splits a region as soon as any of its store 033 * files exceeds a maximum configurable size. 034 * <p> 035 * This is the default split policy. From 0.94.0 on the default split policy has changed to 036 * {@link IncreasingToUpperBoundRegionSplitPolicy} 037 * </p> 038 */ 039@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) 040public class ConstantSizeRegionSplitPolicy extends RegionSplitPolicy { 041 private static final Logger LOG = LoggerFactory.getLogger(ConstantSizeRegionSplitPolicy.class); 042 private long desiredMaxFileSize; 043 private double jitterRate; 044 protected boolean overallHRegionFiles; 045 046 public static final String MAX_FILESIZE_JITTER_KEY = 047 ConfigKey.DOUBLE("hbase.hregion.max.filesize.jitter"); 048 049 @Override 050 public String toString() { 051 return "ConstantSizeRegionSplitPolicy{" + "desiredMaxFileSize=" + desiredMaxFileSize 052 + ", jitterRate=" + jitterRate + '}'; 053 } 054 055 @Override 056 protected void configureForRegion(HRegion region) { 057 super.configureForRegion(region); 058 Configuration conf = getConf(); 059 TableDescriptor desc = region.getTableDescriptor(); 060 if (desc != null) { 061 this.desiredMaxFileSize = desc.getMaxFileSize(); 062 } 063 if (this.desiredMaxFileSize <= 0) { 064 this.desiredMaxFileSize = 065 conf.getLong(HConstants.HREGION_MAX_FILESIZE, HConstants.DEFAULT_MAX_FILE_SIZE); 066 } 067 this.overallHRegionFiles = 068 conf.getBoolean(HConstants.OVERALL_HREGION_FILES, HConstants.DEFAULT_OVERALL_HREGION_FILES); 069 double jitter = conf.getDouble(MAX_FILESIZE_JITTER_KEY, 0.25D); 070 this.jitterRate = (ThreadLocalRandom.current().nextFloat() - 0.5D) * jitter; 071 long jitterValue = (long) (this.desiredMaxFileSize * this.jitterRate); 072 // Default jitter is ~12% +/-. Make sure the long value won't overflow with jitter 073 if (this.jitterRate > 0 && jitterValue > (Long.MAX_VALUE - this.desiredMaxFileSize)) { 074 this.desiredMaxFileSize = Long.MAX_VALUE; 075 } else { 076 this.desiredMaxFileSize += jitterValue; 077 } 078 } 079 080 @Override 081 protected boolean shouldSplit() { 082 if (!canSplit()) { 083 return false; 084 } 085 return isExceedSize(desiredMaxFileSize); 086 } 087 088 long getDesiredMaxFileSize() { 089 return desiredMaxFileSize; 090 } 091 092 @InterfaceAudience.Private 093 public boolean positiveJitterRate() { 094 return this.jitterRate > 0; 095 } 096 097 /** Returns true if region size exceed the sizeToCheck */ 098 protected final boolean isExceedSize(long sizeToCheck) { 099 if (overallHRegionFiles) { 100 long sumSize = 0; 101 for (HStore store : region.getStores()) { 102 sumSize += store.getSize(); 103 } 104 if (sumSize > sizeToCheck) { 105 LOG.debug("Should split because region size is big enough " + "sumSize={}, sizeToCheck={}", 106 StringUtils.humanSize(sumSize), StringUtils.humanSize(sizeToCheck)); 107 return true; 108 } 109 } else { 110 for (HStore store : region.getStores()) { 111 long size = store.getSize(); 112 if (size > sizeToCheck) { 113 LOG.debug("Should split because {} size={}, sizeToCheck={}", store.getColumnFamilyName(), 114 StringUtils.humanSize(size), StringUtils.humanSize(sizeToCheck)); 115 return true; 116 } 117 } 118 } 119 return false; 120 } 121}