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)
HBASE-3836 Add facility to track currently progressing actions and
workflows. (todd)
HBASE-3837 Show regions in transition on the master web page (todd)
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) %>
<& regionServers &>
</%if>
<& AssignmentManagerStatusTmpl; assignmentManager=master.getAssignmentManager()&>
</body>
</html>

View File

@ -332,20 +332,23 @@ public class AssignmentManager extends ZooKeeperListener {
// Just insert region into RIT.
// If this never updates the timeout will trigger new assignment
regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.CLOSING, data.getStamp()));
regionInfo, RegionState.State.CLOSING,
data.getStamp(), data.getOrigin()));
break;
case RS_ZK_REGION_CLOSED:
// Region is closed, insert into RIT and handle it
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();
break;
case M_ZK_REGION_OFFLINE:
// Region is offline, insert into RIT and handle it like a closed
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();
break;
@ -353,13 +356,15 @@ public class AssignmentManager extends ZooKeeperListener {
// Just insert region into RIT
// If this never updates the timeout will trigger new assignment
regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.OPENING, data.getStamp()));
regionInfo, RegionState.State.OPENING,
data.getStamp(), data.getOrigin()));
break;
case RS_ZK_REGION_OPENED:
// Region is opened, insert into RIT and handle it
regionsInTransition.put(encodedRegionName, new RegionState(
regionInfo, RegionState.State.OPENING, data.getStamp()));
regionInfo, RegionState.State.OPENING,
data.getStamp(), data.getOrigin()));
ServerName sn =
data.getOrigin() == null? null: data.getOrigin();
// 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:
if (!isInStateForSplitting(regionState)) break;
addSplittingToRIT(sn.toString(), encodedName);
addSplittingToRIT(sn, encodedName);
break;
case RS_ZK_REGION_SPLIT:
@ -433,7 +438,7 @@ public class AssignmentManager extends ZooKeeperListener {
LOG.info("Received SPLIT for region " + prettyPrintedRegionName +
" from server " + sn +
" but region was not first in SPLITTING state; continuing");
addSplittingToRIT(sn.toString(), encodedName);
addSplittingToRIT(sn, encodedName);
}
// Check it has daughters.
byte [] payload = data.getPayload();
@ -468,7 +473,8 @@ public class AssignmentManager extends ZooKeeperListener {
return;
}
// 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;
case RS_ZK_REGION_CLOSED:
@ -484,7 +490,8 @@ public class AssignmentManager extends ZooKeeperListener {
// Handle CLOSED by assigning elsewhere or stopping if a disable
// If we got here all is good. Need to update RegionState -- else
// 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, regionState.getRegion()));
break;
@ -502,7 +509,8 @@ public class AssignmentManager extends ZooKeeperListener {
return;
}
// 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;
case RS_ZK_REGION_OPENED:
@ -517,7 +525,8 @@ public class AssignmentManager extends ZooKeeperListener {
return;
}
// 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(
new OpenedRegionHandler(master, this, regionState.getRegion(),
data.getOrigin()));
@ -564,12 +573,13 @@ public class AssignmentManager extends ZooKeeperListener {
* @return The SPLITTING RegionState we added to RIT for the passed region
* <code>encodedName</code>
*/
private RegionState addSplittingToRIT(final String serverName,
private RegionState addSplittingToRIT(final ServerName serverName,
final String encodedName) {
RegionState regionState = null;
synchronized (this.regions) {
regionState = findHRegionInfoThenAddToRIT(serverName, encodedName);
regionState.update(RegionState.State.SPLITTING);
regionState.update(RegionState.State.SPLITTING,
System.currentTimeMillis(), serverName);
}
return regionState;
}
@ -580,7 +590,7 @@ public class AssignmentManager extends ZooKeeperListener {
* @param encodedName
* @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) {
HRegionInfo hri = findHRegionInfo(serverName, encodedName);
if (hri == null) {
@ -598,9 +608,8 @@ public class AssignmentManager extends ZooKeeperListener {
* @param encodedName
* @return Found HRegionInfo or null.
*/
private HRegionInfo findHRegionInfo(final String serverName,
private HRegionInfo findHRegionInfo(final ServerName sn,
final String encodedName) {
ServerName sn = new ServerName(serverName);
if (!this.serverManager.isServerOnline(sn)) return null;
List<HRegionInfo> hris = this.servers.get(sn);
HRegionInfo foundHri = null;
@ -824,7 +833,7 @@ public class AssignmentManager extends ZooKeeperListener {
}
if (rs == null) continue;
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
// unassigned node changes.
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 {
private final Log LOG = LogFactory.getLog(ExistsUnassignedAsyncCallback.class);
private final AtomicInteger counter;
private ServerName destination;
ExistsUnassignedAsyncCallback(final AtomicInteger counter) {
ExistsUnassignedAsyncCallback(final AtomicInteger counter, ServerName destination) {
this.counter = counter;
this.destination = destination;
}
@Override
@ -1059,7 +1070,7 @@ public class AssignmentManager extends ZooKeeperListener {
// 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
// to OPENING by the regionserver.
state.update(RegionState.State.PENDING_OPEN);
state.update(RegionState.State.PENDING_OPEN, System.currentTimeMillis(), destination);
this.counter.addAndGet(1);
}
}
@ -1113,7 +1124,8 @@ public class AssignmentManager extends ZooKeeperListener {
LOG.debug("Assigning region " + state.getRegion().getRegionNameAsString() +
" to " + plan.getDestination().toString());
// 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.
serverManager.sendRegionOpen(plan.getDestination(), state.getRegion());
break;
@ -2151,27 +2163,35 @@ public class AssignmentManager extends ZooKeeperListener {
private State state;
private long stamp;
private ServerName serverName;
public RegionState() {}
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.state = state;
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.stamp = stamp;
this.serverName = serverName;
}
public void update(State state) {
this.state = state;
this.stamp = System.currentTimeMillis();
this.serverName = null;
}
public void updateTimestampToNow() {
this.stamp = System.currentTimeMillis();
}
public State getState() {
@ -2224,8 +2244,10 @@ public class AssignmentManager extends ZooKeeperListener {
@Override
public String toString() {
return region.getRegionNameAsString() + " state=" + state +
", ts=" + stamp;
return region.getRegionNameAsString()
+ " state=" + state
+ ", ts=" + stamp
+ ", server=" + serverName;
}
@Override

View File

@ -808,13 +808,13 @@ public class TestMasterFailover {
region = enabledRegions.remove(0);
regionsThatShouldBeOnline.add(region);
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());
// PENDING_OPEN and disabled
region = disabledRegions.remove(0);
regionsThatShouldBeOffline.add(region);
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());
// 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

View File

@ -22,14 +22,18 @@ package org.apache.hadoop.hbase.master;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.NavigableMap;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.ServerName;
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.ServerManager;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.hbase.tmpl.master.MasterStatusTmpl;
import org.junit.Before;
@ -37,6 +41,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Tests for the master status page and its template.
@ -47,13 +52,19 @@ public class TestMasterStatusServlet {
private Configuration conf;
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
public void setupBasicMocks() {
conf = HBaseConfiguration.create();
master = Mockito.mock(HMaster.class);
Mockito.doReturn(new ServerName("fakehost", 12345, 1234567890))
.when(master).getServerName();
Mockito.doReturn(FAKE_HOST).when(master).getServerName();
Mockito.doReturn(conf).when(master).getConfiguration();
// Fake serverManager
@ -61,6 +72,15 @@ public class TestMasterStatusServlet {
Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
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
ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class);
Mockito.doReturn("fakequorum").when(zkw).getQuorum();