HBASE-3837 Show regions in transition on the master web page

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1099199 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Todd Lipcon 2011-05-03 19:07:54 +00:00
parent 46d64afcd9
commit 7d5d1fe752
6 changed files with 118 additions and 30 deletions

View File

@ -236,6 +236,7 @@ Release 0.91.0 - Unreleased
(Prakash Khemani) (Prakash Khemani)
HBASE-3836 Add facility to track currently progressing actions and HBASE-3836 Add facility to track currently progressing actions and
workflows. (todd) workflows. (todd)
HBASE-3837 Show regions in transition on the master web page (todd)
Release 0.90.3 - Unreleased Release 0.90.3 - Unreleased

View File

@ -0,0 +1,42 @@
<%doc>
Copyright 2011 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.
</%doc>
<%import>
org.apache.hadoop.hbase.master.AssignmentManager;
org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
java.util.Map;
</%import>
<%args>
AssignmentManager assignmentManager;
</%args>
<%java>
Map<String, RegionState> rit = assignmentManager.getRegionsInTransition();
</%java>
<h2>Regions in Transition</h2>
<%if rit.isEmpty() %>
No regions in transition.
<%else>
<table>
<tr><th>Region</th><th>State</th></tr>
<%for Map.Entry<String, RegionState> entry : rit.entrySet() %>
<tr><td><% entry.getKey() %></td><td><% entry.getValue() %></td>
</%for>
</table>
</%if>

View File

@ -97,6 +97,9 @@ org.apache.hadoop.hbase.HTableDescriptor;
<%if (servers != null) %> <%if (servers != null) %>
<& regionServers &> <& regionServers &>
</%if> </%if>
<& AssignmentManagerStatusTmpl; assignmentManager=master.getAssignmentManager()&>
</body> </body>
</html> </html>

View File

@ -332,20 +332,23 @@ public class AssignmentManager extends ZooKeeperListener {
// Just insert region into RIT. // Just insert region into RIT.
// If this never updates the timeout will trigger new assignment // If this never updates the timeout will trigger new assignment
regionsInTransition.put(encodedRegionName, new RegionState( regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.CLOSING, data.getStamp())); regionInfo, RegionState.State.CLOSING,
data.getStamp(), data.getOrigin()));
break; break;
case RS_ZK_REGION_CLOSED: case RS_ZK_REGION_CLOSED:
// Region is closed, insert into RIT and handle it // Region is closed, insert into RIT and handle it
regionsInTransition.put(encodedRegionName, new RegionState( regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.CLOSED, data.getStamp())); regionInfo, RegionState.State.CLOSED,
data.getStamp(), data.getOrigin()));
new ClosedRegionHandler(master, this, regionInfo).process(); new ClosedRegionHandler(master, this, regionInfo).process();
break; break;
case M_ZK_REGION_OFFLINE: case M_ZK_REGION_OFFLINE:
// Region is offline, insert into RIT and handle it like a closed // Region is offline, insert into RIT and handle it like a closed
regionsInTransition.put(encodedRegionName, new RegionState( regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.OFFLINE, data.getStamp())); regionInfo, RegionState.State.OFFLINE,
data.getStamp(), data.getOrigin()));
new ClosedRegionHandler(master, this, regionInfo).process(); new ClosedRegionHandler(master, this, regionInfo).process();
break; break;
@ -353,13 +356,15 @@ public class AssignmentManager extends ZooKeeperListener {
// Just insert region into RIT // Just insert region into RIT
// If this never updates the timeout will trigger new assignment // If this never updates the timeout will trigger new assignment
regionsInTransition.put(encodedRegionName, new RegionState( regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.OPENING, data.getStamp())); regionInfo, RegionState.State.OPENING,
data.getStamp(), data.getOrigin()));
break; break;
case RS_ZK_REGION_OPENED: case RS_ZK_REGION_OPENED:
// Region is opened, insert into RIT and handle it // Region is opened, insert into RIT and handle it
regionsInTransition.put(encodedRegionName, new RegionState( regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.OPENING, data.getStamp())); regionInfo, RegionState.State.OPENING,
data.getStamp(), data.getOrigin()));
ServerName sn = ServerName sn =
data.getOrigin() == null? null: data.getOrigin(); data.getOrigin() == null? null: data.getOrigin();
// hsi could be null if this server is no longer online. If // hsi could be null if this server is no longer online. If
@ -422,7 +427,7 @@ public class AssignmentManager extends ZooKeeperListener {
case RS_ZK_REGION_SPLITTING: case RS_ZK_REGION_SPLITTING:
if (!isInStateForSplitting(regionState)) break; if (!isInStateForSplitting(regionState)) break;
addSplittingToRIT(sn.toString(), encodedName); addSplittingToRIT(sn, encodedName);
break; break;
case RS_ZK_REGION_SPLIT: case RS_ZK_REGION_SPLIT:
@ -433,7 +438,7 @@ public class AssignmentManager extends ZooKeeperListener {
LOG.info("Received SPLIT for region " + prettyPrintedRegionName + LOG.info("Received SPLIT for region " + prettyPrintedRegionName +
" from server " + sn + " from server " + sn +
" but region was not first in SPLITTING state; continuing"); " but region was not first in SPLITTING state; continuing");
addSplittingToRIT(sn.toString(), encodedName); addSplittingToRIT(sn, encodedName);
} }
// Check it has daughters. // Check it has daughters.
byte [] payload = data.getPayload(); byte [] payload = data.getPayload();
@ -468,7 +473,8 @@ public class AssignmentManager extends ZooKeeperListener {
return; return;
} }
// Transition to CLOSING (or update stamp if already CLOSING) // Transition to CLOSING (or update stamp if already CLOSING)
regionState.update(RegionState.State.CLOSING, data.getStamp()); regionState.update(RegionState.State.CLOSING,
data.getStamp(), data.getOrigin());
break; break;
case RS_ZK_REGION_CLOSED: case RS_ZK_REGION_CLOSED:
@ -484,7 +490,8 @@ public class AssignmentManager extends ZooKeeperListener {
// Handle CLOSED by assigning elsewhere or stopping if a disable // Handle CLOSED by assigning elsewhere or stopping if a disable
// If we got here all is good. Need to update RegionState -- else // If we got here all is good. Need to update RegionState -- else
// what follows will fail because not in expected state. // what follows will fail because not in expected state.
regionState.update(RegionState.State.CLOSED, data.getStamp()); regionState.update(RegionState.State.CLOSED,
data.getStamp(), data.getOrigin());
this.executorService.submit(new ClosedRegionHandler(master, this.executorService.submit(new ClosedRegionHandler(master,
this, regionState.getRegion())); this, regionState.getRegion()));
break; break;
@ -502,7 +509,8 @@ public class AssignmentManager extends ZooKeeperListener {
return; return;
} }
// Transition to OPENING (or update stamp if already OPENING) // Transition to OPENING (or update stamp if already OPENING)
regionState.update(RegionState.State.OPENING, data.getStamp()); regionState.update(RegionState.State.OPENING,
data.getStamp(), data.getOrigin());
break; break;
case RS_ZK_REGION_OPENED: case RS_ZK_REGION_OPENED:
@ -517,7 +525,8 @@ public class AssignmentManager extends ZooKeeperListener {
return; return;
} }
// Handle OPENED by removing from transition and deleted zk node // Handle OPENED by removing from transition and deleted zk node
regionState.update(RegionState.State.OPEN, data.getStamp()); regionState.update(RegionState.State.OPEN,
data.getStamp(), data.getOrigin());
this.executorService.submit( this.executorService.submit(
new OpenedRegionHandler(master, this, regionState.getRegion(), new OpenedRegionHandler(master, this, regionState.getRegion(),
data.getOrigin())); data.getOrigin()));
@ -564,12 +573,13 @@ public class AssignmentManager extends ZooKeeperListener {
* @return The SPLITTING RegionState we added to RIT for the passed region * @return The SPLITTING RegionState we added to RIT for the passed region
* <code>encodedName</code> * <code>encodedName</code>
*/ */
private RegionState addSplittingToRIT(final String serverName, private RegionState addSplittingToRIT(final ServerName serverName,
final String encodedName) { final String encodedName) {
RegionState regionState = null; RegionState regionState = null;
synchronized (this.regions) { synchronized (this.regions) {
regionState = findHRegionInfoThenAddToRIT(serverName, encodedName); regionState = findHRegionInfoThenAddToRIT(serverName, encodedName);
regionState.update(RegionState.State.SPLITTING); regionState.update(RegionState.State.SPLITTING,
System.currentTimeMillis(), serverName);
} }
return regionState; return regionState;
} }
@ -580,7 +590,7 @@ public class AssignmentManager extends ZooKeeperListener {
* @param encodedName * @param encodedName
* @return The instance of RegionState that was added to RIT or null if error. * @return The instance of RegionState that was added to RIT or null if error.
*/ */
private RegionState findHRegionInfoThenAddToRIT(final String serverName, private RegionState findHRegionInfoThenAddToRIT(final ServerName serverName,
final String encodedName) { final String encodedName) {
HRegionInfo hri = findHRegionInfo(serverName, encodedName); HRegionInfo hri = findHRegionInfo(serverName, encodedName);
if (hri == null) { if (hri == null) {
@ -598,9 +608,8 @@ public class AssignmentManager extends ZooKeeperListener {
* @param encodedName * @param encodedName
* @return Found HRegionInfo or null. * @return Found HRegionInfo or null.
*/ */
private HRegionInfo findHRegionInfo(final String serverName, private HRegionInfo findHRegionInfo(final ServerName sn,
final String encodedName) { final String encodedName) {
ServerName sn = new ServerName(serverName);
if (!this.serverManager.isServerOnline(sn)) return null; if (!this.serverManager.isServerOnline(sn)) return null;
List<HRegionInfo> hris = this.servers.get(sn); List<HRegionInfo> hris = this.servers.get(sn);
HRegionInfo foundHri = null; HRegionInfo foundHri = null;
@ -824,7 +833,7 @@ public class AssignmentManager extends ZooKeeperListener {
} }
if (rs == null) continue; if (rs == null) continue;
synchronized (rs) { synchronized (rs) {
rs.update(rs.getState()); rs.updateTimestampToNow();
} }
} }
} }
@ -1028,7 +1037,7 @@ public class AssignmentManager extends ZooKeeperListener {
// Async exists to set a watcher so we'll get triggered when // Async exists to set a watcher so we'll get triggered when
// unassigned node changes. // unassigned node changes.
this.zkw.getZooKeeper().exists(path, this.zkw, this.zkw.getZooKeeper().exists(path, this.zkw,
new ExistsUnassignedAsyncCallback(this.counter), ctx); new ExistsUnassignedAsyncCallback(this.counter, destination), ctx);
} }
} }
@ -1039,9 +1048,11 @@ public class AssignmentManager extends ZooKeeperListener {
static class ExistsUnassignedAsyncCallback implements AsyncCallback.StatCallback { static class ExistsUnassignedAsyncCallback implements AsyncCallback.StatCallback {
private final Log LOG = LogFactory.getLog(ExistsUnassignedAsyncCallback.class); private final Log LOG = LogFactory.getLog(ExistsUnassignedAsyncCallback.class);
private final AtomicInteger counter; private final AtomicInteger counter;
private ServerName destination;
ExistsUnassignedAsyncCallback(final AtomicInteger counter) { ExistsUnassignedAsyncCallback(final AtomicInteger counter, ServerName destination) {
this.counter = counter; this.counter = counter;
this.destination = destination;
} }
@Override @Override
@ -1059,7 +1070,7 @@ public class AssignmentManager extends ZooKeeperListener {
// yet sent out the actual open but putting this state change after the // yet sent out the actual open but putting this state change after the
// call to open risks our writing PENDING_OPEN after state has been moved // call to open risks our writing PENDING_OPEN after state has been moved
// to OPENING by the regionserver. // to OPENING by the regionserver.
state.update(RegionState.State.PENDING_OPEN); state.update(RegionState.State.PENDING_OPEN, System.currentTimeMillis(), destination);
this.counter.addAndGet(1); this.counter.addAndGet(1);
} }
} }
@ -1113,7 +1124,8 @@ public class AssignmentManager extends ZooKeeperListener {
LOG.debug("Assigning region " + state.getRegion().getRegionNameAsString() + LOG.debug("Assigning region " + state.getRegion().getRegionNameAsString() +
" to " + plan.getDestination().toString()); " to " + plan.getDestination().toString());
// Transition RegionState to PENDING_OPEN // Transition RegionState to PENDING_OPEN
state.update(RegionState.State.PENDING_OPEN); state.update(RegionState.State.PENDING_OPEN, System.currentTimeMillis(),
plan.getDestination());
// Send OPEN RPC. This can fail if the server on other end is is not up. // Send OPEN RPC. This can fail if the server on other end is is not up.
serverManager.sendRegionOpen(plan.getDestination(), state.getRegion()); serverManager.sendRegionOpen(plan.getDestination(), state.getRegion());
break; break;
@ -2151,27 +2163,35 @@ public class AssignmentManager extends ZooKeeperListener {
private State state; private State state;
private long stamp; private long stamp;
private ServerName serverName;
public RegionState() {} public RegionState() {}
RegionState(HRegionInfo region, State state) { RegionState(HRegionInfo region, State state) {
this(region, state, System.currentTimeMillis()); this(region, state, System.currentTimeMillis(), null);
} }
RegionState(HRegionInfo region, State state, long stamp) { RegionState(HRegionInfo region, State state, long stamp, ServerName serverName) {
this.region = region; this.region = region;
this.state = state; this.state = state;
this.stamp = stamp; this.stamp = stamp;
this.serverName = serverName;
} }
public void update(State state, long stamp) { public void update(State state, long stamp, ServerName serverName) {
this.state = state; this.state = state;
this.stamp = stamp; this.stamp = stamp;
this.serverName = serverName;
} }
public void update(State state) { public void update(State state) {
this.state = state; this.state = state;
this.stamp = System.currentTimeMillis(); this.stamp = System.currentTimeMillis();
this.serverName = null;
}
public void updateTimestampToNow() {
this.stamp = System.currentTimeMillis();
} }
public State getState() { public State getState() {
@ -2224,8 +2244,10 @@ public class AssignmentManager extends ZooKeeperListener {
@Override @Override
public String toString() { public String toString() {
return region.getRegionNameAsString() + " state=" + state + return region.getRegionNameAsString()
", ts=" + stamp; + " state=" + state
+ ", ts=" + stamp
+ ", server=" + serverName;
} }
@Override @Override

View File

@ -808,13 +808,13 @@ public class TestMasterFailover {
region = enabledRegions.remove(0); region = enabledRegions.remove(0);
regionsThatShouldBeOnline.add(region); regionsThatShouldBeOnline.add(region);
master.assignmentManager.regionsInTransition.put(region.getEncodedName(), master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
new RegionState(region, RegionState.State.PENDING_OPEN, 0)); new RegionState(region, RegionState.State.PENDING_OPEN, 0, null));
ZKAssign.createNodeOffline(zkw, region, master.getServerName()); ZKAssign.createNodeOffline(zkw, region, master.getServerName());
// PENDING_OPEN and disabled // PENDING_OPEN and disabled
region = disabledRegions.remove(0); region = disabledRegions.remove(0);
regionsThatShouldBeOffline.add(region); regionsThatShouldBeOffline.add(region);
master.assignmentManager.regionsInTransition.put(region.getEncodedName(), master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
new RegionState(region, RegionState.State.PENDING_OPEN, 0)); new RegionState(region, RegionState.State.PENDING_OPEN, 0, null));
ZKAssign.createNodeOffline(zkw, region, master.getServerName()); ZKAssign.createNodeOffline(zkw, region, master.getServerName());
// This test is bad. It puts up a PENDING_CLOSE but doesn't say what // This test is bad. It puts up a PENDING_CLOSE but doesn't say what
// server we were PENDING_CLOSE against -- i.e. an entry in // server we were PENDING_CLOSE against -- i.e. an entry in

View File

@ -22,14 +22,18 @@ package org.apache.hadoop.hbase.master;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.List; import java.util.List;
import java.util.NavigableMap;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.master.ServerManager; import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.hbase.tmpl.master.MasterStatusTmpl; import org.apache.hbase.tmpl.master.MasterStatusTmpl;
import org.junit.Before; import org.junit.Before;
@ -37,6 +41,7 @@ import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/** /**
* Tests for the master status page and its template. * Tests for the master status page and its template.
@ -47,13 +52,19 @@ public class TestMasterStatusServlet {
private Configuration conf; private Configuration conf;
private HBaseAdmin admin; private HBaseAdmin admin;
static final ServerName FAKE_HOST =
new ServerName("fakehost", 12345, 1234567890);
static final HTableDescriptor FAKE_TABLE =
new HTableDescriptor("mytable");
static final HRegionInfo FAKE_REGION =
new HRegionInfo(FAKE_TABLE, Bytes.toBytes("a"), Bytes.toBytes("b"));
@Before @Before
public void setupBasicMocks() { public void setupBasicMocks() {
conf = HBaseConfiguration.create(); conf = HBaseConfiguration.create();
master = Mockito.mock(HMaster.class); master = Mockito.mock(HMaster.class);
Mockito.doReturn(new ServerName("fakehost", 12345, 1234567890)) Mockito.doReturn(FAKE_HOST).when(master).getServerName();
.when(master).getServerName();
Mockito.doReturn(conf).when(master).getConfiguration(); Mockito.doReturn(conf).when(master).getConfiguration();
// Fake serverManager // Fake serverManager
@ -61,6 +72,15 @@ public class TestMasterStatusServlet {
Mockito.doReturn(1.0).when(serverManager).getAverageLoad(); Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
Mockito.doReturn(serverManager).when(master).getServerManager(); Mockito.doReturn(serverManager).when(master).getServerManager();
// Fake AssignmentManager and RIT
AssignmentManager am = Mockito.mock(AssignmentManager.class);
NavigableMap<String, RegionState> regionsInTransition =
Maps.newTreeMap();
regionsInTransition.put("r1",
new RegionState(FAKE_REGION, RegionState.State.CLOSING, 12345L, FAKE_HOST));
Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
Mockito.doReturn(am).when(master).getAssignmentManager();
// Fake ZKW // Fake ZKW
ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class); ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class);
Mockito.doReturn("fakequorum").when(zkw).getQuorum(); Mockito.doReturn("fakequorum").when(zkw).getQuorum();