HBASE-5304 Pluggable split key policy
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1239909 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4b4904a77c
commit
df4a9d4ad3
|
@ -2002,6 +2002,18 @@ rs.close();
|
||||||
the parent's hosting RegionServer and then reports the split to the
|
the parent's hosting RegionServer and then reports the split to the
|
||||||
Master. See <xref linkend="disable.splitting" /> for how to manually manage
|
Master. See <xref linkend="disable.splitting" /> for how to manually manage
|
||||||
splits (and for why you might do this)</para>
|
splits (and for why you might do this)</para>
|
||||||
|
<section>
|
||||||
|
<title>Custom Split Policies</title>
|
||||||
|
<para>The default split policy can be overwritten using a custom <link xlink:href="http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/regionserver/RegionSplitPolicy.html">RegionSplitPolicy</link> (HBase 0.94+).
|
||||||
|
Typically a custom split policy should extend HBase's default split policy: <link xlink:href="http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/regionserver/ConstantSizeRegionSplitPolicy.html">ConstantSizeRegionSplitPolicy</link>.
|
||||||
|
</para>
|
||||||
|
<para>The policy can set globally through the HBaseConfiguration used or on a per table basis:
|
||||||
|
<programlisting>
|
||||||
|
HTableDescriptor myHtd = ...;
|
||||||
|
myHtd.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName());
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section xml:id="store">
|
<section xml:id="store">
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
|
||||||
|
|
||||||
private static final String FAMILIES = "FAMILIES";
|
private static final String FAMILIES = "FAMILIES";
|
||||||
|
|
||||||
private static final String SPLIT_POLICY = "SPLIT_POLICY";
|
public static final String SPLIT_POLICY = "SPLIT_POLICY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>INTERNAL</em> Used by HBase Shell interface to access this metadata
|
* <em>INTERNAL</em> Used by HBase Shell interface to access this metadata
|
||||||
|
|
|
@ -23,12 +23,13 @@ import org.apache.hadoop.hbase.HConstants;
|
||||||
* A {@link RegionSplitPolicy} implementation which splits a region
|
* A {@link RegionSplitPolicy} implementation which splits a region
|
||||||
* as soon as any of its store files exceeds a maximum configurable
|
* as soon as any of its store files exceeds a maximum configurable
|
||||||
* size.
|
* size.
|
||||||
|
* <p>This is the default split policy.</p>
|
||||||
*/
|
*/
|
||||||
class ConstantSizeRegionSplitPolicy extends RegionSplitPolicy {
|
public class ConstantSizeRegionSplitPolicy extends RegionSplitPolicy {
|
||||||
private long desiredMaxFileSize;
|
private long desiredMaxFileSize;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void configureForRegion(HRegion region) {
|
protected void configureForRegion(HRegion region) {
|
||||||
super.configureForRegion(region);
|
super.configureForRegion(region);
|
||||||
long maxFileSize = region.getTableDesc().getMaxFileSize();
|
long maxFileSize = region.getTableDesc().getMaxFileSize();
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class ConstantSizeRegionSplitPolicy extends RegionSplitPolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean shouldSplit() {
|
protected boolean shouldSplit() {
|
||||||
boolean force = region.shouldForceSplit();
|
boolean force = region.shouldForceSplit();
|
||||||
boolean foundABigStore = false;
|
boolean foundABigStore = false;
|
||||||
|
|
||||||
|
|
|
@ -4863,10 +4863,6 @@ public class HRegion implements HeapSize { // , Writable{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.explicitSplitPoint != null) {
|
|
||||||
return this.explicitSplitPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!splitPolicy.shouldSplit()) {
|
if (!splitPolicy.shouldSplit()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import com.google.common.base.Preconditions;
|
||||||
* A split policy determines when a region should be split.
|
* A split policy determines when a region should be split.
|
||||||
* {@see ConstantSizeRegionSplitPolicy}
|
* {@see ConstantSizeRegionSplitPolicy}
|
||||||
*/
|
*/
|
||||||
abstract class RegionSplitPolicy extends Configured {
|
public abstract class RegionSplitPolicy extends Configured {
|
||||||
private static final Class<ConstantSizeRegionSplitPolicy>
|
private static final Class<ConstantSizeRegionSplitPolicy>
|
||||||
DEFAULT_SPLIT_POLICY_CLASS = ConstantSizeRegionSplitPolicy.class;
|
DEFAULT_SPLIT_POLICY_CLASS = ConstantSizeRegionSplitPolicy.class;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ abstract class RegionSplitPolicy extends Configured {
|
||||||
* Upon construction, this method will be called with the region
|
* Upon construction, this method will be called with the region
|
||||||
* to be governed. It will be called once and only once.
|
* to be governed. It will be called once and only once.
|
||||||
*/
|
*/
|
||||||
void configureForRegion(HRegion region) {
|
protected void configureForRegion(HRegion region) {
|
||||||
Preconditions.checkState(
|
Preconditions.checkState(
|
||||||
this.region == null,
|
this.region == null,
|
||||||
"Policy already configured for region {}",
|
"Policy already configured for region {}",
|
||||||
|
@ -57,14 +57,18 @@ abstract class RegionSplitPolicy extends Configured {
|
||||||
/**
|
/**
|
||||||
* @return true if the specified region should be split.
|
* @return true if the specified region should be split.
|
||||||
*/
|
*/
|
||||||
abstract boolean shouldSplit();
|
protected abstract boolean shouldSplit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the key at which the region should be split, or null
|
* @return the key at which the region should be split, or null
|
||||||
* if it cannot be split. This will only be called if shouldSplit
|
* if it cannot be split. This will only be called if shouldSplit
|
||||||
* previously returned true.
|
* previously returned true.
|
||||||
*/
|
*/
|
||||||
byte[] getSplitPoint() {
|
protected byte[] getSplitPoint() {
|
||||||
|
byte[] explicitSplitPoint = this.region.getExplicitSplitPoint();
|
||||||
|
if (explicitSplitPoint != null) {
|
||||||
|
return explicitSplitPoint;
|
||||||
|
}
|
||||||
Map<byte[], Store> stores = region.getStores();
|
Map<byte[], Store> stores = region.getStores();
|
||||||
|
|
||||||
byte[] splitPointFromLargestStore = null;
|
byte[] splitPointFromLargestStore = null;
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.regionserver;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom RegionSplitPolicy for testing.
|
||||||
|
* This class also demonstrates how to implement a SplitPolicy that groups
|
||||||
|
* rows by a prefix of the row-key
|
||||||
|
*
|
||||||
|
* This ensures that a region is not split "inside"
|
||||||
|
* a prefix of a row key. I.e. rows can be co-located by
|
||||||
|
* their prefix.
|
||||||
|
*/
|
||||||
|
public class PrefixSplitKeyPolicy extends ConstantSizeRegionSplitPolicy {
|
||||||
|
public static String PREFIX_LENGTH_KEY = "prefix_split_key_policy.prefix_length";
|
||||||
|
|
||||||
|
private int prefix_length;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureForRegion(HRegion region) {
|
||||||
|
super.configureForRegion(region);
|
||||||
|
|
||||||
|
if (region != null) {
|
||||||
|
// this demonstrates how a RegionSplitPolicy can be configured
|
||||||
|
// through HTableDescriptor values
|
||||||
|
prefix_length = Integer.parseInt(region.getTableDesc().getValue(
|
||||||
|
PREFIX_LENGTH_KEY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] getSplitPoint() {
|
||||||
|
byte[] splitPoint = super.getSplitPoint();
|
||||||
|
if (splitPoint != null && splitPoint.length > 0) {
|
||||||
|
// group split keys by a prefix
|
||||||
|
return Arrays.copyOf(splitPoint,
|
||||||
|
Math.min(prefix_length, splitPoint.length));
|
||||||
|
} else {
|
||||||
|
return splitPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.regionserver;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -71,6 +72,41 @@ public class TestRegionSplitPolicy {
|
||||||
assertEquals(9999L, policy.getDesiredMaxFileSize());
|
assertEquals(9999L, policy.getDesiredMaxFileSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test setting up a customized split policy
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCustomPolicy() throws IOException {
|
||||||
|
HTableDescriptor myHtd = new HTableDescriptor();
|
||||||
|
myHtd.setValue(HTableDescriptor.SPLIT_POLICY,
|
||||||
|
PrefixSplitKeyPolicy.class.getName());
|
||||||
|
myHtd.setValue(PrefixSplitKeyPolicy.PREFIX_LENGTH_KEY, String.valueOf(2));
|
||||||
|
|
||||||
|
HRegion myMockRegion = Mockito.mock(HRegion.class);
|
||||||
|
Mockito.doReturn(myHtd).when(myMockRegion).getTableDesc();
|
||||||
|
Mockito.doReturn(stores).when(myMockRegion).getStores();
|
||||||
|
|
||||||
|
Store mockStore = Mockito.mock(Store.class);
|
||||||
|
Mockito.doReturn(2000L).when(mockStore).getSize();
|
||||||
|
Mockito.doReturn(true).when(mockStore).canSplit();
|
||||||
|
Mockito.doReturn(Bytes.toBytes("abcd")).when(mockStore).getSplitPoint();
|
||||||
|
stores.put(new byte[] { 1 }, mockStore);
|
||||||
|
|
||||||
|
PrefixSplitKeyPolicy policy = (PrefixSplitKeyPolicy) RegionSplitPolicy
|
||||||
|
.create(myMockRegion, conf);
|
||||||
|
|
||||||
|
assertEquals("ab", Bytes.toString(policy.getSplitPoint()));
|
||||||
|
|
||||||
|
Mockito.doReturn(true).when(myMockRegion).shouldForceSplit();
|
||||||
|
Mockito.doReturn(Bytes.toBytes("efgh")).when(myMockRegion)
|
||||||
|
.getExplicitSplitPoint();
|
||||||
|
|
||||||
|
policy = (PrefixSplitKeyPolicy) RegionSplitPolicy
|
||||||
|
.create(myMockRegion, conf);
|
||||||
|
|
||||||
|
assertEquals("ef", Bytes.toString(policy.getSplitPoint()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstantSizePolicy() throws IOException {
|
public void testConstantSizePolicy() throws IOException {
|
||||||
htd.setMaxFileSize(1024L);
|
htd.setMaxFileSize(1024L);
|
||||||
|
|
Loading…
Reference in New Issue