001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.regionserver;
020
021import org.apache.yetus.audience.InterfaceAudience;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration;
026
027/**
028 * Configuration class for stripe store and compactions.
029 * See {@link StripeStoreFileManager} for general documentation.
030 * See getters for the description of each setting.
031 */
032@InterfaceAudience.Private
033public class StripeStoreConfig {
034  private static final Logger LOG = LoggerFactory.getLogger(StripeStoreConfig.class);
035
036  /** The maximum number of files to compact within a stripe; same as for regular compaction. */
037  public static final String MAX_FILES_KEY = "hbase.store.stripe.compaction.maxFiles";
038  /** The minimum number of files to compact within a stripe; same as for regular compaction. */
039  public static final String MIN_FILES_KEY = "hbase.store.stripe.compaction.minFiles";
040
041  /**  The minimum number of files to compact when compacting L0; same as minFiles for regular
042   * compaction. Given that L0 causes unnecessary overwriting of the data, should be higher than
043   * regular minFiles. */
044  public static final String MIN_FILES_L0_KEY = "hbase.store.stripe.compaction.minFilesL0";
045
046  /** The size the stripe should achieve to be considered for splitting into multiple stripes.
047   Stripe will be split when it can be fully compacted, and it is above this size. */
048  public static final String SIZE_TO_SPLIT_KEY = "hbase.store.stripe.sizeToSplit";
049  /** The target count of new stripes to produce when splitting a stripe. A floating point
050   number, default is 2. Values less than 1 will be converted to 1/x. Non-whole numbers will
051   produce unbalanced splits, which may be good for some cases. In this case the "smaller" of
052   the new stripes will always be the rightmost one. If the stripe is bigger than sizeToSplit
053   when splitting, this will be adjusted by a whole increment. */
054  public static final String SPLIT_PARTS_KEY = "hbase.store.stripe.splitPartCount";
055  /** The initial stripe count to create. If the row distribution is roughly the same over time,
056   it's good to set this to a count of stripes that is expected to be achieved in most regions,
057   to get this count from the outset and prevent unnecessary splitting. */
058  public static final String INITIAL_STRIPE_COUNT_KEY = "hbase.store.stripe.initialStripeCount";
059
060  /** Whether to flush memstore to L0 files, or directly to stripes. */
061  public static final String FLUSH_TO_L0_KEY = "hbase.store.stripe.compaction.flushToL0";
062
063  /** When splitting region, the maximum size imbalance to allow in an attempt to split at a
064   stripe boundary, so that no files go to both regions. Most users won't need to change that. */
065  public static final String MAX_REGION_SPLIT_IMBALANCE_KEY =
066      "hbase.store.stripe.region.split.max.imbalance";
067
068
069  private final float maxRegionSplitImbalance;
070  private final int level0CompactMinFiles;
071  private final int stripeCompactMinFiles;
072  private final int stripeCompactMaxFiles;
073
074  private final int initialCount;
075  private final long sizeToSplitAt;
076  private final float splitPartCount;
077  private final boolean flushIntoL0;
078  private final long splitPartSize; // derived from sizeToSplitAt and splitPartCount
079
080  private static final double EPSILON = 0.001; // good enough for this, not a real epsilon.
081  public StripeStoreConfig(Configuration config, StoreConfigInformation sci) {
082    this.level0CompactMinFiles = config.getInt(MIN_FILES_L0_KEY, 4);
083    this.flushIntoL0 = config.getBoolean(FLUSH_TO_L0_KEY, false);
084    int minMinFiles = flushIntoL0 ? 3 : 4; // make sure not to compact tiny files too often.
085    int minFiles = config.getInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MIN_KEY, -1);
086    this.stripeCompactMinFiles = config.getInt(MIN_FILES_KEY, Math.max(minMinFiles, minFiles));
087    this.stripeCompactMaxFiles = config.getInt(MAX_FILES_KEY,
088        config.getInt(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MAX_KEY, 10));
089    this.maxRegionSplitImbalance = getFloat(config, MAX_REGION_SPLIT_IMBALANCE_KEY, 1.5f, true);
090
091    float splitPartCount = getFloat(config, SPLIT_PARTS_KEY, 2f, true);
092    if (Math.abs(splitPartCount - 1.0) < EPSILON) {
093      LOG.error("Split part count cannot be 1 (" + splitPartCount + "), using the default");
094      splitPartCount = 2f;
095    }
096    this.splitPartCount = splitPartCount;
097    // Arbitrary default split size - 4 times the size of one L0 compaction.
098    // If we flush into L0 there's no split compaction, but for default value it is ok.
099    double flushSize = sci.getMemStoreFlushSize();
100    if (flushSize == 0) {
101      flushSize = 128 * 1024 * 1024;
102    }
103    long defaultSplitSize = (long)(flushSize * getLevel0MinFiles() * 4 * splitPartCount);
104    this.sizeToSplitAt = config.getLong(SIZE_TO_SPLIT_KEY, defaultSplitSize);
105    int initialCount = config.getInt(INITIAL_STRIPE_COUNT_KEY, 1);
106    if (initialCount == 0) {
107      LOG.error("Initial stripe count is 0, using the default");
108      initialCount = 1;
109    }
110    this.initialCount = initialCount;
111    this.splitPartSize = (long)(this.sizeToSplitAt / this.splitPartCount);
112  }
113
114  private static float getFloat(
115      Configuration config, String key, float defaultValue, boolean moreThanOne) {
116    float value = config.getFloat(key, defaultValue);
117    if (value < EPSILON) {
118      LOG.warn(String.format(
119          "%s is set to 0 or negative; using default value of %f", key, defaultValue));
120      value = defaultValue;
121    } else if ((value > 1f) != moreThanOne) {
122      value = 1f / value;
123    }
124    return value;
125  }
126
127  public float getMaxSplitImbalance() {
128    return this.maxRegionSplitImbalance;
129  }
130
131  public int getLevel0MinFiles() {
132    return level0CompactMinFiles;
133  }
134
135  public int getStripeCompactMinFiles() {
136    return stripeCompactMinFiles;
137  }
138
139  public int getStripeCompactMaxFiles() {
140    return stripeCompactMaxFiles;
141  }
142
143  public boolean isUsingL0Flush() {
144    return flushIntoL0;
145  }
146
147  public long getSplitSize() {
148    return sizeToSplitAt;
149  }
150
151  public int getInitialCount() {
152    return initialCount;
153  }
154
155  public float getSplitCount() {
156    return splitPartCount;
157  }
158
159  /**
160   * @return the desired size of the target stripe when splitting, in bytes.
161   *         Derived from {@link #getSplitSize()} and {@link #getSplitCount()}.
162   */
163  public long getSplitPartSize() {
164    return splitPartSize;
165  }
166}