diff --git a/CHANGES.txt b/CHANGES.txt index 7d94e783507..9d883540e2e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -90,6 +90,8 @@ Release 0.91.0 - Unreleased TASK HBASE-3559 Move report of split to master OFF the heartbeat channel + HBASE-3573 Move shutdown messaging OFF hearbeat; prereq for fix of + hbase-1502 NEW FEATURES diff --git a/src/main/java/org/apache/hadoop/hbase/HMsg.java b/src/main/java/org/apache/hadoop/hbase/HMsg.java index a07bef26e9d..87beb008dab 100644 --- a/src/main/java/org/apache/hadoop/hbase/HMsg.java +++ b/src/main/java/org/apache/hadoop/hbase/HMsg.java @@ -38,15 +38,9 @@ import org.apache.hadoop.io.Writable; * design, these are to go via zk from here on out. */ public class HMsg implements Writable { - public static final HMsg [] STOP_REGIONSERVER_ARRAY = - new HMsg [] {new HMsg(Type.STOP_REGIONSERVER)}; public static final HMsg [] EMPTY_HMSG_ARRAY = new HMsg[0]; public static enum Type { - /** Master tells region server to stop. - */ - STOP_REGIONSERVER, - /** * When RegionServer receives this message, it goes into a sleep that only * an exit will cure. This message is sent by unit tests simulating diff --git a/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java b/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java index 2e601e1af4d..9502b1d34a0 100644 --- a/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java +++ b/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java @@ -504,7 +504,9 @@ public class HRegionInfo extends VersionedWritable implements WritableComparable return this.tableDesc.isRootRegion(); } - /** @return true if this is the meta table */ + /** @return true if this region is from a table that is a meta table, + * either .META. or -ROOT- + */ public boolean isMetaTable() { return this.tableDesc.isMetaTable(); } diff --git a/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java b/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java index 2d27a981942..5c8c2ff9086 100644 --- a/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java +++ b/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java @@ -249,7 +249,9 @@ public class HTableDescriptor implements WritableComparable { values.put(IS_META_KEY, isMeta? TRUE: FALSE); } - /** @return true if table is the meta table */ + /** @return true if table is a meta table, either .META. or + * -ROOT- + */ public boolean isMetaTable() { return isMetaRegion() && !isRootRegion(); } diff --git a/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java b/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 5b7ebff7d09..3aed9c95568 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ b/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -1963,6 +1963,40 @@ public class AssignmentManager extends ZooKeeperListener { unassign(plan.getRegionInfo()); } + /** + * @param hsi + * @return True if this server is carrying a catalog region, a region from + * -ROOT- or .META. table. + */ + boolean isMetaRegionServer(final HServerInfo hsi) { + synchronized (this.regions) { + List regions = this.servers.get(hsi); + if (regions == null || regions.isEmpty()) return false; + for (HRegionInfo hri: regions) { + if (hri.isMetaRegion()) return true; + } + } + return false; + } + + /** + * Run through remaining regionservers and unassign all catalog regions. + */ + void unassignCatalogRegions() { + this.servers.entrySet(); + synchronized (this.regions) { + for (Map.Entry> e: this.servers.entrySet()) { + List regions = e.getValue(); + if (regions == null || regions.isEmpty()) continue; + for (HRegionInfo hri: regions) { + if (hri.isMetaRegion()) { + unassign(hri); + } + } + } + } + } + /** * State of a Region while undergoing transitions. */ @@ -2079,4 +2113,4 @@ public class AssignmentManager extends ZooKeeperListener { public void stop() { this.timeoutMonitor.interrupt(); } -} +} \ No newline at end of file diff --git a/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java b/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java index 42c8bda33c9..4dd082bbc4f 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java +++ b/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java @@ -269,11 +269,6 @@ public class ServerManager { "ready next on next report"); } - // Check startcodes - if (raceThatShouldNotHappenAnymore(storedInfo, info)) { - return HMsg.STOP_REGIONSERVER_ARRAY; - } - for (HMsg msg: msgs) { LOG.info("Received " + msg + " from " + serverInfo.getServerName()); switch (msg.getType()) { @@ -283,38 +278,32 @@ public class ServerManager { } HMsg [] reply = null; - int numservers = countOfRegionServers(); if (this.clusterShutdown) { - if (numservers <= 2) { + if (isOnlyMetaRegionServersOnline()) { + LOG.info("Only catalog regions remaining; running unassign"); + // The only remaining regions are catalog regions. // Shutdown needs to be staggered; the meta regions need to close last - // in case they need to be updated during the close melee. If <= 2 - // servers left, then these are the two that were carrying root and meta - // most likely (TODO: This presumes unsplittable meta -- FIX). Tell - // these servers can shutdown now too. - reply = HMsg.STOP_REGIONSERVER_ARRAY; + // in case they need to be updated during the close melee. If only + // catalog reigons remaining, tell them they can go down now too. On + // close of region, the regionservers should then shut themselves down. + this.services.getAssignmentManager().unassignCatalogRegions(); } } return processRegionServerAllsWell(info, mostLoadedRegions, reply); } - private boolean raceThatShouldNotHappenAnymore(final HServerInfo storedInfo, - final HServerInfo reportedInfo) { - if (storedInfo.getStartCode() != reportedInfo.getStartCode()) { - // TODO: I don't think this possible any more. We check startcodes when - // server comes in on regionServerStartup -- St.Ack - // This state is reachable if: - // 1) RegionServer A started - // 2) RegionServer B started on the same machine, then clobbered A in regionServerStartup. - // 3) RegionServer A returns, expecting to work as usual. - // The answer is to ask A to shut down for good. - LOG.warn("Race condition detected: " + reportedInfo.getServerName()); - synchronized (this.onlineServers) { - removeServerInfo(reportedInfo.getServerName()); - notifyOnlineServers(); + /** + * @return True if all online servers are carrying one or more catalog + * regions, there are no servers online carrying user regions only + */ + private boolean isOnlyMetaRegionServersOnline() { + List onlineServers = getOnlineServersList(); + for (HServerInfo hsi: onlineServers) { + if (!this.services.getAssignmentManager().isMetaRegionServer(hsi)) { + return false; } - return true; } - return false; + return true; } /** diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 3ba02df4245..edd14baceb6 100644 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -741,16 +741,6 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, } updateOutboundMsgs(outboundMessages); outboundMessages.clear(); - - for (int i = 0; !this.stopped && msgs != null && i < msgs.length; i++) { - LOG.info(msgs[i].toString()); - // Intercept stop regionserver messages - if (msgs[i].getType().equals(HMsg.Type.STOP_REGIONSERVER)) { - stop("Received " + msgs[i]); - continue; - } - LOG.warn("NOT PROCESSING " + msgs[i] + " -- WHY IS MASTER SENDING IT TO US?"); - } return outboundMessages; } diff --git a/src/test/java/org/apache/hadoop/hbase/TestHMsg.java b/src/test/java/org/apache/hadoop/hbase/TestHMsg.java deleted file mode 100644 index b26cee45c69..00000000000 --- a/src/test/java/org/apache/hadoop/hbase/TestHMsg.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2009 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; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Writables; - -public class TestHMsg extends TestCase { - public void testList() { - List msgs = new ArrayList(); - HMsg hmsg = null; - final int size = 10; - for (int i = 0; i < size; i++) { - byte [] b = Bytes.toBytes(i); - hmsg = new HMsg(HMsg.Type.STOP_REGIONSERVER, - new HRegionInfo(new HTableDescriptor(Bytes.toBytes("test")), b, b)); - msgs.add(hmsg); - } - assertEquals(size, msgs.size()); - int index = msgs.indexOf(hmsg); - assertNotSame(-1, index); - msgs.remove(index); - assertEquals(size - 1, msgs.size()); - byte [] other = Bytes.toBytes("other"); - hmsg = new HMsg(HMsg.Type.STOP_REGIONSERVER, - new HRegionInfo(new HTableDescriptor(Bytes.toBytes("test")), other, other)); - assertEquals(-1, msgs.indexOf(hmsg)); - // Assert that two HMsgs are same if same content. - byte [] b = Bytes.toBytes(1); - hmsg = new HMsg(HMsg.Type.STOP_REGIONSERVER, - new HRegionInfo(new HTableDescriptor(Bytes.toBytes("test")), b, b)); - assertNotSame(-1, msgs.indexOf(hmsg)); - } - - public void testSerialization() throws IOException { - byte [] parentbytes = Bytes.toBytes("parent"); - HRegionInfo parent = - new HRegionInfo(new HTableDescriptor(Bytes.toBytes("parent")), - parentbytes, parentbytes); - // Assert simple HMsg serializes - HMsg hmsg = new HMsg(HMsg.Type.STOP_REGIONSERVER, parent); - byte [] bytes = Writables.getBytes(hmsg); - HMsg close = (HMsg)Writables.getWritable(bytes, new HMsg()); - assertTrue(close.equals(hmsg)); - } -} \ No newline at end of file diff --git a/src/test/java/org/apache/hadoop/hbase/TestSerialization.java b/src/test/java/org/apache/hadoop/hbase/TestSerialization.java index 8c39c352d7e..88a743f5ae8 100644 --- a/src/test/java/org/apache/hadoop/hbase/TestSerialization.java +++ b/src/test/java/org/apache/hadoop/hbase/TestSerialization.java @@ -84,21 +84,6 @@ public class TestSerialization { assertTrue(Bytes.equals("value".getBytes(), hmw.get("key".getBytes()))); } - @Test public void testHMsg() throws Exception { - final String name = "testHMsg"; - HMsg m = new HMsg(HMsg.Type.STOP_REGIONSERVER); - byte [] mb = Writables.getBytes(m); - HMsg deserializedHMsg = (HMsg)Writables.getWritable(mb, new HMsg()); - assertTrue(m.equals(deserializedHMsg)); - m = new HMsg(HMsg.Type.STOP_REGIONSERVER, - new HRegionInfo(new HTableDescriptor(name), - HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY), - "Some message".getBytes()); - mb = Writables.getBytes(m); - deserializedHMsg = (HMsg)Writables.getWritable(mb, new HMsg()); - assertTrue(m.equals(deserializedHMsg)); - } - @Test public void testTableDescriptor() throws Exception { final String name = "testTableDescriptor"; HTableDescriptor htd = createTableDescriptor(name);