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 org.apache.hadoop.hbase.HBaseInterfaceAudience;
021import org.apache.hadoop.hbase.procedure2.util.StringUtils;
022import org.apache.yetus.audience.InterfaceAudience;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026/**
027 * A {@link FlushPolicy} that only flushes store larger a given threshold. If no store is large
028 * enough, then all stores will be flushed.
029 */
030@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
031public abstract class FlushLargeStoresPolicy extends FlushPolicy {
032
033  private static final Logger LOG = LoggerFactory.getLogger(FlushLargeStoresPolicy.class);
034
035  public static final String HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND =
036    "hbase.hregion.percolumnfamilyflush.size.lower.bound";
037
038  public static final String HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND_MIN =
039    "hbase.hregion.percolumnfamilyflush.size.lower.bound.min";
040
041  public static final long DEFAULT_HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND_MIN =
042    1024 * 1024 * 16L;
043
044  protected long flushSizeLowerBound = -1;
045
046  @Override
047  public String toString() {
048    return "FlushLargeStoresPolicy{" + "flushSizeLowerBound=" + flushSizeLowerBound + '}';
049  }
050
051  protected void setFlushSizeLowerBounds(HRegion region) {
052    int familyNumber = region.getTableDescriptor().getColumnFamilyCount();
053    // For multiple families, lower bound is the "average flush size" by default
054    // unless setting in configuration is larger.
055    flushSizeLowerBound = region.getMemStoreFlushSize() / familyNumber;
056    long minimumLowerBound = getConf().getLong(HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND_MIN,
057      DEFAULT_HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND_MIN);
058    if (minimumLowerBound > flushSizeLowerBound) {
059      flushSizeLowerBound = minimumLowerBound;
060    }
061    // use the setting in table description if any
062    String flushedSizeLowerBoundString =
063      region.getTableDescriptor().getValue(HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND);
064    if (flushedSizeLowerBoundString == null) {
065      LOG.debug(
066        "No {} set in table {} descriptor;"
067          + "using region.getMemStoreFlushHeapSize/# of families ({}) " + "instead.",
068        HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND, region.getTableDescriptor().getTableName(),
069        StringUtils.humanSize(flushSizeLowerBound) + ")");
070    } else {
071      try {
072        flushSizeLowerBound = Long.parseLong(flushedSizeLowerBoundString);
073      } catch (NumberFormatException nfe) {
074        // fall back for fault setting
075        LOG.warn(
076          "Number format exception parsing {} for table {}: {}, {}; "
077            + "using region.getMemStoreFlushHeapSize/# of families ({}) "
078            + "and region.getMemStoreFlushOffHeapSize/# of families ({}) " + "instead.",
079          HREGION_COLUMNFAMILY_FLUSH_SIZE_LOWER_BOUND, region.getTableDescriptor().getTableName(),
080          flushedSizeLowerBoundString, nfe, flushSizeLowerBound);
081
082      }
083    }
084  }
085
086  protected boolean shouldFlush(HStore store) {
087    if (
088      store.getMemStoreSize().getHeapSize() + store.getMemStoreSize().getOffHeapSize()
089          > this.flushSizeLowerBound
090    ) {
091      LOG.debug(
092        "Flush {} of {}; " + "heap memstoreSize={} +"
093          + "off heap memstoreSize={} > memstore lowerBound={}",
094        store.getColumnFamilyName(), region.getRegionInfo().getEncodedName(),
095        store.getMemStoreSize().getHeapSize(), store.getMemStoreSize().getOffHeapSize(),
096        this.flushSizeLowerBound);
097      return true;
098    }
099    return false;
100  }
101}