HBASE-4217 HRS.closeRegion should be able to close regions with only the encoded name

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1161658 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2011-08-25 17:29:54 +00:00
parent 7ede7e9b39
commit 581af1b086
7 changed files with 278 additions and 12 deletions

View File

@ -478,6 +478,8 @@ Release 0.90.5 - Unreleased
Campbell)
HBASE-4095 Hlog may not be rolled in a long time if checkLowReplication's
request of LogRoll is blocked (Jieshan Bean)
HBASE-4217 HRS.closeRegion should be able to close regions with only
the encoded name (ramkrishna.s.vasudevan)
IMPROVEMENT
HBASE-4205 Enhance HTable javadoc (Eric Charles)

View File

@ -1009,6 +1009,45 @@ public class HBaseAdmin implements Abortable, Closeable {
}
}
/**
* For expert-admins. Runs close on the regionserver. Closes a region based on
* the encoded region name. The region server name is mandatory. If the
* servername is provided then based on the online regions in the specified
* regionserver the specified region will be closed. The master will not be
* informed of the close. Note that the regionname is the encoded regionname.
*
* @param encodedRegionName
* The encoded region name; i.e. the hash that makes up the region
* name suffix: e.g. if regionname is
* <code>TestTable,0094429456,1289497600452.527db22f95c8a9e0116f0cc13c680396.</code>
* , then the encoded region name is:
* <code>527db22f95c8a9e0116f0cc13c680396</code>.
* @param serverName
* The servername of the regionserver. A server name is made of host,
* port and startcode. This is mandatory. Here is an example:
* <code> host187.example.com,60020,1289493121758</code>
* @return true if the region was closed, false if not.
* @throws IOException
* if a remote or network exception occurs
*/
public boolean closeRegionWithEncodedRegionName(final String encodedRegionName,
final String serverName) throws IOException {
byte[] encodedRegionNameInBytes = Bytes.toBytes(encodedRegionName);
if (null == serverName || ("").equals(serverName.trim())) {
throw new IllegalArgumentException(
"The servername cannot be null or empty.");
}
ServerName sn = new ServerName(serverName);
HRegionInterface rs = this.connection.getHRegionConnection(
sn.getHostname(), sn.getPort());
// Close the region without updating zk state.
boolean isRegionClosed = rs.closeRegion(encodedRegionNameInBytes, false);
if (false == isRegionClosed) {
LOG.error("Not able to close the region " + encodedRegionName + ".");
}
return isRegionClosed;
}
/**
* Close a region. For expert-admins Runs close on the regionserver. The
* master will not be informed of the close.

View File

@ -366,6 +366,21 @@ public interface HRegionInterface extends VersionedProtocol, Stoppable, Abortabl
*/
public boolean closeRegion(final HRegionInfo region, final boolean zk)
throws IOException;
/**
* Closes the region in the RS with the specified encoded regionName and will
* use or not use ZK during the close according to the specified flag. Note
* that the encoded region name is in byte format.
*
* @param encodedRegionName
* in bytes
* @param zk
* true if to use zookeeper, false if need not.
* @return true if region is closed, false if not.
* @throws IOException
*/
public boolean closeRegion(byte[] encodedRegionName, final boolean zk)
throws IOException;
// Region administrative methods

View File

@ -2361,6 +2361,12 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
}
return closeRegion(region, false, zk);
}
@Override
@QosPriority(priority=HIGH_QOS)
public boolean closeRegion(byte[] encodedRegionName, boolean zk) throws IOException {
return closeRegion(encodedRegionName, false, zk);
}
/**
* @param region Region to close
@ -2389,6 +2395,29 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
this.service.submit(crh);
return true;
}
/**
* @param encodedRegionName
* encodedregionName to close
* @param abort
* True if we are aborting
* @param zk
* True if we are to update zk about the region close; if the close
* was orchestrated by master, then update zk. If the close is being
* run by the regionserver because its going down, don't update zk.
* @return True if closed a region.
*/
protected boolean closeRegion(byte[] encodedRegionName, final boolean abort,
final boolean zk) throws IOException {
String encodedRegionNameStr = Bytes.toString(encodedRegionName);
HRegion region = this.getFromOnlineRegions(encodedRegionNameStr);
if (null != region) {
return closeRegion(region.getRegionInfo(), abort, zk);
}
LOG.error("The specified region name" + encodedRegionNameStr
+ " does not exist to close the region.");
return false;
}
// Manual remote region administration RPCs
@ -3031,4 +3060,6 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler,
return c.getBlockCacheColumnFamilySummaries(this.conf);
}
}

View File

@ -209,13 +209,18 @@ module Hbase
@admin.createTable(htd, splits)
end
end
#----------------------------------------------------------------------------------------------
# Closes a region
def close_region(region_name, server = nil)
@admin.closeRegion(region_name, server)
# Closes a region.
# If server name is nil, we presume region_name is full region name (HRegionInfo.getRegionName).
# If server name is not nil, we presume it is the region's encoded name (HRegionInfo.getEncodedName)
def close_region(region_name, server)
if (server == nil || !closeEncodedRegion?(region_name, server))
@admin.closeRegion(region_name, server)
end
end
#----------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------
# Assign a region
def assign(region_name, force)
@ -389,6 +394,12 @@ module Hbase
@admin.isTableEnabled(table_name)
end
#----------------------------------------------------------------------------------------------
#Is supplied region name is encoded region name
def closeEncodedRegion?(region_name, server)
@admin.closeRegionWithEncodedRegionName(region_name, server)
end
#----------------------------------------------------------------------------------------------
# Return a new HColumnDescriptor made of passed args
def hcd(arg, htd)

View File

@ -23,14 +23,25 @@ module Shell
class CloseRegion < Command
def help
return <<-EOF
Close a single region. Optionally specify regionserver 'servername' where
A server name is its host, port plus startcode. For example:
host187.example.com,60020,1289493121758 (find servername in master ui or
when you do detailed status in shell). Connects to the regionserver and
runs close on hosting regionserver. The close is done without the master's
involvement (It will not know of the close). Once closed, region will stay
closed. Use assign to reopen/reassign. Use unassign or move to assign the
region elsewhere on cluster. Use with caution. For experts only. Examples:
Close a single region. Ask the master to close a region out on the cluster
or if 'SERVER_NAME' is supplied, ask the designated hosting regionserver to
close the region directly. Closing a region, the master expects 'REGIONNAME'
to be a fully qualified region name. When asking the hosting regionserver to
directly close a region, you pass the regions' encoded name only. A region
name looks like this:
TestTable,0094429456,1289497600452.527db22f95c8a9e0116f0cc13c680396.
The trailing period is part of the regionserver name. A region's encoded name
is the hash at the end of a region name; e.g. 527db22f95c8a9e0116f0cc13c680396
(without the period). A 'SERVER_NAME' is its host, port plus startcode. For
example: host187.example.com,60020,1289493121758 (find servername in master ui
or when you do detailed status in shell). This command will end up running
close on the region hosting regionserver. The close is done without the
master's involvement (It will not know of the close). Once closed, region will
stay closed. Use assign to reopen/reassign. Use unassign or move to assign
the region elsewhere on cluster. Use with caution. For experts only.
Examples:
hbase> close_region 'REGIONNAME'
hbase> close_region 'REGIONNAME', 'SERVER_NAME'

View File

@ -23,6 +23,7 @@ package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.ArrayList;
@ -35,6 +36,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
@ -49,7 +51,11 @@ import org.apache.hadoop.hbase.executor.EventHandler;
import org.apache.hadoop.hbase.executor.EventHandler.EventType;
import org.apache.hadoop.hbase.executor.ExecutorService;
import org.apache.hadoop.hbase.master.MasterServices;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.zookeeper.KeeperException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -904,6 +910,157 @@ public class TestAdmin {
new HTable(TEST_UTIL.getConfiguration(),
"testTableNotFoundExceptionWithoutAnyTables");
}
@Test
public void testShouldCloseTheRegionBasedOnTheEncodedRegionName()
throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion");
HBaseAdmin admin = createTable(TABLENAME);
HRegionInfo info = null;
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
info = regionInfo;
admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(), rs
.getServerName().getServerName());
}
}
Thread.sleep(1000);
onlineRegions = rs.getOnlineRegions();
assertFalse("The region should not be present in online regions list.",
onlineRegions.contains(info));
}
@Test
public void testCloseRegionIfInvalidRegionNameIsPassed() throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion1");
HBaseAdmin admin = createTable(TABLENAME);
HRegionInfo info = null;
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion1")) {
info = regionInfo;
admin.closeRegionWithEncodedRegionName("sample", rs.getServerName()
.getServerName());
}
}
}
onlineRegions = rs.getOnlineRegions();
assertTrue("The region should be present in online regions list.",
onlineRegions.contains(info));
}
@Test
public void testCloseRegionThatFetchesTheHRIFromMeta() throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion2");
HBaseAdmin admin = createTable(TABLENAME);
HRegionInfo info = null;
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion2")) {
info = regionInfo;
admin.closeRegion(regionInfo.getRegionNameAsString(), rs
.getServerName().getServerName());
}
}
}
Thread.sleep(1000);
onlineRegions = rs.getOnlineRegions();
assertFalse("The region should not be present in online regions list.",
onlineRegions.contains(info));
}
@Test
public void testCloseRegionWhenServerNameIsNull() throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion3");
HBaseAdmin admin = createTable(TABLENAME);
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
try {
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
if (regionInfo.getRegionNameAsString()
.contains("TestHBACloseRegion3")) {
admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(),
null);
}
}
}
fail("The test should throw exception if the servername passed is null.");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testCloseRegionWhenServerNameIsEmpty() throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion3");
HBaseAdmin admin = createTable(TABLENAME);
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
try {
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
if (regionInfo.getRegionNameAsString()
.contains("TestHBACloseRegion3")) {
admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(),
" ");
}
}
}
fail("The test should throw exception if the servername passed is empty.");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testCloseRegionWhenEncodedRegionNameIsNotGiven() throws Exception {
byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion4");
HBaseAdmin admin = createTable(TABLENAME);
HRegionInfo info = null;
HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
for (HRegionInfo regionInfo : onlineRegions) {
if (!regionInfo.isMetaRegion() && !regionInfo.isRootRegion()) {
if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion4")) {
info = regionInfo;
admin.closeRegionWithEncodedRegionName(regionInfo
.getRegionNameAsString(), rs.getServerName().getServerName());
}
}
}
onlineRegions = rs.getOnlineRegions();
assertTrue("The region should be present in online regions list.",
onlineRegions.contains(info));
}
private HBaseAdmin createTable(byte[] TABLENAME) throws IOException {
Configuration config = TEST_UTIL.getConfiguration();
HBaseAdmin admin = new HBaseAdmin(config);
HTableDescriptor htd = new HTableDescriptor(TABLENAME);
HColumnDescriptor hcd = new HColumnDescriptor("value");
htd.addFamily(hcd);
admin.createTable(htd, null);
return admin;
}
@Test
public void testHundredsOfTable() throws IOException{