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 org.apache.hadoop.conf.Configuration;
022import org.apache.hadoop.hbase.client.TableDescriptor;
023import org.apache.yetus.audience.InterfaceAudience;
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027/**
028 * A split restriction that restricts the pattern of the split point.
029 * <p>
030 * The difference between {@link RegionSplitPolicy} and RegionSplitRestriction is that
031 * RegionSplitRestriction defines how to split while {@link RegionSplitPolicy} defines when we need
032 * to split.
033 * <p>
034 * We can specify a split restriction, "KeyPrefix" or "DelimitedKeyPrefix", to a table with the
035 * "hbase.regionserver.region.split_restriction.type" property. The "KeyPrefix" split restriction
036 * groups rows by a prefix of the row-key. And the "DelimitedKeyPrefix" split restriction groups
037 * rows by a prefix of the row-key with a delimiter. For example:
038 *
039 * <pre>
040 * <code>
041 * # Create a table with a "KeyPrefix" split restriction, where the prefix length is 2 bytes
042 * hbase> create 'tbl1', 'fam',
043 *   {CONFIGURATION => {'hbase.regionserver.region.split_restriction.type' => 'KeyPrefix',
044 *                      'hbase.regionserver.region.split_restriction.prefix_length' => '2'}}
045 *
046 * # Create a table with a "DelimitedKeyPrefix" split restriction, where the delimiter is a comma
047 * hbase> create 'tbl2', 'fam',
048 *   {CONFIGURATION => {'hbase.regionserver.region.split_restriction.type' => 'DelimitedKeyPrefix',
049 *                      'hbase.regionserver.region.split_restriction.delimiter' => ','}}
050 * </code>
051 * </pre>
052 *
053 * Instead of specifying a split restriction to a table directly, we can also set the properties in
054 * hbase-site.xml. In this case, the specified split restriction is applied for all the tables.
055 * <p>
056 * Note that the split restriction is also applied to a user-specified split point so that we don't
057 * allow users to break the restriction.
058 * @see NoRegionSplitRestriction
059 * @see KeyPrefixRegionSplitRestriction
060 * @see DelimitedKeyPrefixRegionSplitRestriction
061 */
062@InterfaceAudience.Private
063public abstract class RegionSplitRestriction {
064  private static final Logger LOG = LoggerFactory.getLogger(RegionSplitRestriction.class);
065
066  public static final String RESTRICTION_TYPE_KEY =
067    "hbase.regionserver.region.split_restriction.type";
068
069  public static final String RESTRICTION_TYPE_NONE = "None";
070  public static final String RESTRICTION_TYPE_KEY_PREFIX = "KeyPrefix";
071  public static final String RESTRICTION_TYPE_DELIMITED_KEY_PREFIX = "DelimitedKeyPrefix";
072
073  /**
074   * Create the RegionSplitRestriction configured for the given table.
075   * @param tableDescriptor the table descriptor
076   * @param conf            the configuration
077   * @return a RegionSplitRestriction instance
078   * @throws IOException if an error occurs
079   */
080  public static RegionSplitRestriction create(TableDescriptor tableDescriptor, Configuration conf)
081    throws IOException {
082    String type = tableDescriptor.getValue(RESTRICTION_TYPE_KEY);
083    if (type == null) {
084      type = conf.get(RESTRICTION_TYPE_KEY, RESTRICTION_TYPE_NONE);
085    }
086
087    RegionSplitRestriction ret;
088    switch (type) {
089      case RESTRICTION_TYPE_NONE:
090        ret = new NoRegionSplitRestriction();
091        break;
092      case RESTRICTION_TYPE_KEY_PREFIX:
093        ret = new KeyPrefixRegionSplitRestriction();
094        break;
095      case RESTRICTION_TYPE_DELIMITED_KEY_PREFIX:
096        ret = new DelimitedKeyPrefixRegionSplitRestriction();
097        break;
098      default:
099        LOG.warn("Invalid RegionSplitRestriction type specified: {}. "
100          + "Using the default RegionSplitRestriction", type);
101        ret = new NoRegionSplitRestriction();
102        break;
103    }
104    ret.initialize(tableDescriptor, conf);
105    return ret;
106  }
107
108  /**
109   * Initialize the RegionSplitRestriction instance
110   * @param tableDescriptor the table descriptor
111   * @param conf            the configuration
112   * @throws IOException if an error occurs
113   */
114  public abstract void initialize(TableDescriptor tableDescriptor, Configuration conf)
115    throws IOException;
116
117  /**
118   * Returns a restricted split point.
119   * @param splitPoint the split point determined by {@link RegionSplitPolicy} or specified by a
120   *                   user manually
121   * @return the restricted split point
122   */
123  public abstract byte[] getRestrictedSplitPoint(byte[] splitPoint);
124}