You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by jd...@apache.org on 2011/04/27 23:46:59 UTC
svn commit: r1097255 - in /hbase/branches/0.90: ./
src/main/java/org/apache/hadoop/hbase/regionserver/
src/main/java/org/apache/hadoop/hbase/regionserver/handler/
src/test/java/org/apache/hadoop/hbase/master/
src/test/java/org/apache/hadoop/hbase/regio...
Author: jdcryans
Date: Wed Apr 27 21:46:58 2011
New Revision: 1097255
URL: http://svn.apache.org/viewvc?rev=1097255&view=rev
Log:
HBASE-3741 Make HRegionServer aware of the regions it's opening/closing
Added:
hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionAlreadyInTransitionException.java
Modified:
hbase/branches/0.90/CHANGES.txt
hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRegionHandler.java
hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRegionHandler.java
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/master/TestZKBasedOpenCloseRegion.java
hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/handler/TestOpenRegionHandler.java
Modified: hbase/branches/0.90/CHANGES.txt
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/CHANGES.txt?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/CHANGES.txt (original)
+++ hbase/branches/0.90/CHANGES.txt Wed Apr 27 21:46:58 2011
@@ -35,6 +35,7 @@ Release 0.90.3 - Unreleased
(Harsh J Chouraria)
HBASE-3749 Master can't exit when open port failed (gaojinchao)
HBASE-3794 TestRpcMetrics fails on machine where region server is running
+ HBASE-3741 Make HRegionServer aware of the regions it's opening/closing
IMPROVEMENT
HBASE-3717 deprecate HTable isTableEnabled() methods in favor of HBaseAdmin
Modified: hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (original)
+++ hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java Wed Apr 27 21:46:58 2011
@@ -44,7 +44,7 @@ import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -77,7 +77,6 @@ import org.apache.hadoop.hbase.Stoppable
import org.apache.hadoop.hbase.UnknownRowLockException;
import org.apache.hadoop.hbase.UnknownScannerException;
import org.apache.hadoop.hbase.YouAreDeadException;
-import org.apache.hadoop.hbase.HConstants.OperationStatusCode;
import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.catalog.MetaEditor;
import org.apache.hadoop.hbase.catalog.RootLocationEditor;
@@ -270,6 +269,9 @@ public class HRegionServer implements HR
// Replication services. If no replication, this handler will be null.
private Replication replicationHandler;
+ private final Set<byte[]> regionsInTransitionInRS =
+ new ConcurrentSkipListSet<byte[]>(Bytes.BYTES_COMPARATOR);
+
/**
* Starts a HRegionServer at the default location
*
@@ -2060,7 +2062,10 @@ public class HRegionServer implements HR
@Override
@QosPriority(priority=HIGH_QOS)
public void openRegion(HRegionInfo region)
- throws RegionServerStoppedException {
+ throws IOException {
+ if (this.regionsInTransitionInRS.contains(region.getEncodedNameAsBytes())) {
+ throw new RegionAlreadyInTransitionException("open", region.getEncodedName());
+ }
LOG.info("Received request to open region: " +
region.getRegionNameAsString());
if (this.stopped) throw new RegionServerStoppedException();
@@ -2076,7 +2081,7 @@ public class HRegionServer implements HR
@Override
@QosPriority(priority=HIGH_QOS)
public void openRegions(List<HRegionInfo> regions)
- throws RegionServerStoppedException {
+ throws IOException {
LOG.info("Received request to open " + regions.size() + " region(s)");
for (HRegionInfo region: regions) openRegion(region);
}
@@ -2084,14 +2089,14 @@ public class HRegionServer implements HR
@Override
@QosPriority(priority=HIGH_QOS)
public boolean closeRegion(HRegionInfo region)
- throws NotServingRegionException {
+ throws IOException {
return closeRegion(region, true);
}
@Override
@QosPriority(priority=HIGH_QOS)
public boolean closeRegion(HRegionInfo region, final boolean zk)
- throws NotServingRegionException {
+ throws IOException {
LOG.info("Received close region: " + region.getRegionNameAsString());
boolean hasit = this.onlineRegions.containsKey(region.getEncodedName());
if (!hasit) {
@@ -2100,6 +2105,9 @@ public class HRegionServer implements HR
throw new NotServingRegionException("Received close for "
+ region.getRegionNameAsString() + " but we are not serving it");
}
+ if (this.regionsInTransitionInRS.contains(region.getEncodedNameAsBytes())) {
+ throw new RegionAlreadyInTransitionException("close", region.getEncodedName());
+ }
return closeRegion(region, false, zk);
}
@@ -2113,6 +2121,11 @@ public class HRegionServer implements HR
*/
protected boolean closeRegion(HRegionInfo region, final boolean abort,
final boolean zk) {
+ if (this.regionsInTransitionInRS.contains(region.getEncodedNameAsBytes())) {
+ LOG.warn("Received close for region we are already opening or closing; " +
+ region.getEncodedName());
+ return false;
+ }
CloseRegionHandler crh = null;
if (region.isRootRegion()) {
crh = new CloseRootHandler(this, this, region, abort, zk);
@@ -2604,6 +2617,10 @@ public class HRegionServer implements HR
return this.compactSplitThread;
}
+ public Set<byte[]> getRegionsInTransitionInRS() {
+ return this.regionsInTransitionInRS;
+ }
+
//
// Main program and support routines
//
Added: hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionAlreadyInTransitionException.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionAlreadyInTransitionException.java?rev=1097255&view=auto
==============================================================================
--- hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionAlreadyInTransitionException.java (added)
+++ hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionAlreadyInTransitionException.java Wed Apr 27 21:46:58 2011
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.io.IOException;
+
+/**
+ * This exception is thrown when a region server is asked to open or close
+ * a region but it's already processing it
+ */
+public class RegionAlreadyInTransitionException extends IOException {
+
+ public RegionAlreadyInTransitionException(String action, String region) {
+ super("Received " + action + " for region we are" +
+ " already opening or closing; " + region);
+ }
+}
Modified: hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java (original)
+++ hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java Wed Apr 27 21:46:58 2011
@@ -26,6 +26,7 @@ import org.apache.hadoop.hbase.catalog.C
import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
import org.apache.hadoop.hbase.regionserver.wal.HLog;
import org.apache.zookeeper.KeeperException;
+import java.util.Set;
/**
* Services provided by {@link HRegionServer}
@@ -72,4 +73,10 @@ public interface RegionServerServices ex
* Returns a reference to the RPC server metrics.
*/
public HBaseRpcMetrics getRpcMetrics();
+
+ /**
+ * Get the regions that are currently being opened or closed in the RS
+ * @return set of regions in transition in this RS
+ */
+ public Set<byte[]> getRegionsInTransitionInRS();
}
\ No newline at end of file
Modified: hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRegionHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRegionHandler.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRegionHandler.java (original)
+++ hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRegionHandler.java Wed Apr 27 21:46:58 2011
@@ -95,45 +95,51 @@ public class CloseRegionHandler extends
@Override
public void process() {
- String name = regionInfo.getRegionNameAsString();
- LOG.debug("Processing close of " + name);
- String encodedRegionName = regionInfo.getEncodedName();
- // Check that this region is being served here
- HRegion region = this.rsServices.getFromOnlineRegions(encodedRegionName);
- if (region == null) {
- LOG.warn("Received CLOSE for region " + name + " but currently not serving");
- return;
- }
-
- int expectedVersion = FAILED;
- if (this.zk) {
- expectedVersion = setClosingState();
- if (expectedVersion == FAILED) return;
- }
-
- // Close the region
try {
- // TODO: If we need to keep updating CLOSING stamp to prevent against
- // a timeout if this is long-running, need to spin up a thread?
- if (region.close(abort) == null) {
- // This region got closed. Most likely due to a split. So instead
- // of doing the setClosedState() below, let's just ignore and continue.
- // The split message will clean up the master state.
- LOG.warn("Can't close region: was already closed during close(): " +
- regionInfo.getRegionNameAsString());
+ String name = regionInfo.getRegionNameAsString();
+ LOG.debug("Processing close of " + name);
+ String encodedRegionName = regionInfo.getEncodedName();
+ // Check that this region is being served here
+ HRegion region = this.rsServices.getFromOnlineRegions(encodedRegionName);
+ if (region == null) {
+ LOG.warn("Received CLOSE for region " + name +
+ " but currently not serving");
return;
}
- } catch (IOException e) {
- LOG.error("Unrecoverable exception while closing region " +
- regionInfo.getRegionNameAsString() + ", still finishing close", e);
- }
- this.rsServices.removeFromOnlineRegions(regionInfo.getEncodedName());
+ int expectedVersion = FAILED;
+ if (this.zk) {
+ expectedVersion = setClosingState();
+ if (expectedVersion == FAILED) return;
+ }
- if (this.zk) setClosedState(expectedVersion, region);
+ // Close the region
+ try {
+ // TODO: If we need to keep updating CLOSING stamp to prevent against
+ // a timeout if this is long-running, need to spin up a thread?
+ if (region.close(abort) == null) {
+ // This region got closed. Most likely due to a split. So instead
+ // of doing the setClosedState() below, let's just ignore cont
+ // The split message will clean up the master state.
+ LOG.warn("Can't close region: was already closed during close(): " +
+ regionInfo.getRegionNameAsString());
+ return;
+ }
+ } catch (IOException e) {
+ LOG.error("Unrecoverable exception while closing region " +
+ regionInfo.getRegionNameAsString() + ", still finishing close", e);
+ }
- // Done! Region is closed on this RS
- LOG.debug("Closed region " + region.getRegionNameAsString());
+ this.rsServices.removeFromOnlineRegions(regionInfo.getEncodedName());
+
+ if (this.zk) setClosedState(expectedVersion, region);
+
+ // Done! Region is closed on this RS
+ LOG.debug("Closed region " + region.getRegionNameAsString());
+ } finally {
+ this.rsServices.getRegionsInTransitionInRS().
+ remove(this.regionInfo.getEncodedNameAsBytes());
+ }
}
/**
Modified: hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRegionHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRegionHandler.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRegionHandler.java (original)
+++ hbase/branches/0.90/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRegionHandler.java Wed Apr 27 21:46:58 2011
@@ -69,51 +69,57 @@ public class OpenRegionHandler extends E
@Override
public void process() throws IOException {
- final String name = regionInfo.getRegionNameAsString();
- LOG.debug("Processing open of " + name);
- if (this.server.isStopped() || this.rsServices.isStopping()) {
- LOG.info("Server stopping or stopped, skipping open of " + name);
- return;
- }
- final String encodedName = regionInfo.getEncodedName();
+ try {
+ final String name = regionInfo.getRegionNameAsString();
+ LOG.debug("Processing open of " + name);
+ if (this.server.isStopped() || this.rsServices.isStopping()) {
+ LOG.info("Server stopping or stopped, skipping open of " + name);
+ return;
+ }
+ final String encodedName = regionInfo.getEncodedName();
- // Check that this region is not already online
- HRegion region = this.rsServices.getFromOnlineRegions(encodedName);
- if (region != null) {
- LOG.warn("Attempted open of " + name +
- " but already online on this server");
- return;
- }
-
- // If fails, just return. Someone stole the region from under us.
- // Calling transitionZookeeperOfflineToOpening initalizes this.version.
- if (!transitionZookeeperOfflineToOpening(encodedName)) {
- LOG.warn("Region was hijacked? It no longer exists, encodedName=" +
- encodedName);
- return;
- }
+ // Check that this region is not already online
+ HRegion region = this.rsServices.getFromOnlineRegions(encodedName);
+ if (region != null) {
+ LOG.warn("Attempted open of " + name +
+ " but already online on this server");
+ return;
+ }
- // Open region. After a successful open, failures in subsequent processing
- // needs to do a close as part of cleanup.
- region = openRegion();
- if (region == null) return;
- boolean failed = true;
- if (tickleOpening("post_region_open")) {
- if (updateMeta(region)) failed = false;
- }
+ // If fails, just return. Someone stole the region from under us.
+ // Calling transitionZookeeperOfflineToOpening initalizes this.version.
+ if (!transitionZookeeperOfflineToOpening(encodedName)) {
+ LOG.warn("Region was hijacked? It no longer exists, encodedName=" +
+ encodedName);
+ return;
+ }
- if (failed || this.server.isStopped() || this.rsServices.isStopping()) {
- cleanupFailedOpen(region);
- return;
- }
+ // Open region. After a successful open, failures in subsequent
+ // processing needs to do a close as part of cleanup.
+ region = openRegion();
+ if (region == null) return;
+ boolean failed = true;
+ if (tickleOpening("post_region_open")) {
+ if (updateMeta(region)) failed = false;
+ }
- if (!transitionToOpened(region)) {
- cleanupFailedOpen(region);
- return;
- }
+ if (failed || this.server.isStopped() ||
+ this.rsServices.isStopping()) {
+ cleanupFailedOpen(region);
+ return;
+ }
+
+ if (!transitionToOpened(region)) {
+ cleanupFailedOpen(region);
+ return;
+ }
- // Done! Successful region open
- LOG.debug("Opened " + name);
+ // Done! Successful region open
+ LOG.debug("Opened " + name);
+ } finally {
+ this.rsServices.getRegionsInTransitionInRS().
+ remove(this.regionInfo.getEncodedNameAsBytes());
+ }
}
/**
Modified: hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/master/TestZKBasedOpenCloseRegion.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/master/TestZKBasedOpenCloseRegion.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/master/TestZKBasedOpenCloseRegion.java (original)
+++ hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/master/TestZKBasedOpenCloseRegion.java Wed Apr 27 21:46:58 2011
@@ -49,6 +49,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import static org.junit.Assert.assertTrue;
/**
* Test open and close of regions using zk.
@@ -244,6 +245,59 @@ public class TestZKBasedOpenCloseRegion
}
}
+ /**
+ * This test shows how a region won't be able to be assigned to a RS
+ * if it's already "processing" it.
+ * @throws Exception
+ */
+ @Test
+ public void testRSAlreadyProcessingRegion() throws Exception {
+ MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
+
+ HRegionServer hr0 =
+ cluster.getLiveRegionServerThreads().get(0).getRegionServer();
+ HRegionServer hr1 =
+ cluster.getLiveRegionServerThreads().get(1).getRegionServer();
+ HRegionInfo hri = getNonMetaRegion(hr0.getOnlineRegions());
+
+ // fake that hr1 is processing the region
+ hr1.getRegionsInTransitionInRS().add(hri.getEncodedNameAsBytes());
+
+ AtomicBoolean reopenEventProcessed = new AtomicBoolean(false);
+ EventHandlerListener openListener =
+ new ReopenEventListener(hri.getRegionNameAsString(),
+ reopenEventProcessed, EventType.RS_ZK_REGION_OPENED);
+ cluster.getMaster().executorService.
+ registerListener(EventType.RS_ZK_REGION_OPENED, openListener);
+
+ // now ask the master to move the region to hr1, will fail
+ TEST_UTIL.getHBaseAdmin().move(hri.getEncodedNameAsBytes(),
+ Bytes.toBytes(hr1.getServerName()));
+
+ while (!reopenEventProcessed.get()) {
+ Threads.sleep(100);
+ }
+
+ // make sure the region came back
+ assertTrue(hr1.getOnlineRegion(hri.getEncodedNameAsBytes()) == null);
+
+ // remove the block and reset the boolean
+ hr1.getRegionsInTransitionInRS().remove(hri.getEncodedNameAsBytes());
+ reopenEventProcessed.set(false);
+
+ // move the region again, but this time it will work
+ TEST_UTIL.getHBaseAdmin().move(hri.getEncodedNameAsBytes(),
+ Bytes.toBytes(hr1.getServerName()));
+
+ while (!reopenEventProcessed.get()) {
+ Threads.sleep(100);
+ }
+
+ // make sure the region has moved from the original RS
+ assertTrue(hr0.getOnlineRegion(hri.getEncodedNameAsBytes()) == null);
+
+ }
+
private static void waitUntilAllRegionsAssigned(final int countOfRegions)
throws IOException {
HTable meta = new HTable(TEST_UTIL.getConfiguration(),
Modified: hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/handler/TestOpenRegionHandler.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/handler/TestOpenRegionHandler.java?rev=1097255&r1=1097254&r2=1097255&view=diff
==============================================================================
--- hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/handler/TestOpenRegionHandler.java (original)
+++ hbase/branches/0.90/src/test/java/org/apache/hadoop/hbase/regionserver/handler/TestOpenRegionHandler.java Wed Apr 27 21:46:58 2011
@@ -21,7 +21,9 @@ package org.apache.hadoop.hbase.regionse
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -121,6 +123,7 @@ public class TestOpenRegionHandler {
static class MockRegionServerServices implements RegionServerServices {
final Map<String, HRegion> regions = new HashMap<String, HRegion>();
boolean stopping = false;
+ Set<byte[]> rit = new HashSet<byte[]>();
@Override
public boolean removeFromOnlineRegions(String encodedRegionName) {
@@ -161,7 +164,12 @@ public class TestOpenRegionHandler {
public HBaseRpcMetrics getRpcMetrics() {
return null;
}
-
+
+ @Override
+ public Set<byte[]> getRegionsInTransitionInRS() {
+ return rit;
+ }
+
@Override
public FlushRequester getFlushRequester() {
return null;
@@ -171,6 +179,7 @@ public class TestOpenRegionHandler {
public CompactionRequestor getCompactionRequester() {
return null;
}
+
};
/**