From 8aeb3acaf959e2905191fd6c92fa56300f7d3597 Mon Sep 17 00:00:00 2001 From: tedyu Date: Wed, 4 Feb 2015 14:53:55 -0800 Subject: [PATCH] HBASE-12966 NPE in HMaster while recovering tables in Enabling state (Andrey Stepachev) --- .../master/handler/EnableTableHandler.java | 35 +++--- .../handler/TestEnableTableHandler.java | 101 ++++++++++++++++++ 2 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/master/handler/TestEnableTableHandler.java diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java index 280e3e406c7..c4969be9065 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java @@ -26,14 +26,14 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.hadoop.hbase.classification.InterfaceAudience; -import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; -import org.apache.hadoop.hbase.MetaTableAccessor; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.executor.EventType; @@ -207,19 +207,26 @@ public class EnableTableHandler extends EventHandler { List onlineServers = serverManager.createDestinationServersList(); Map> bulkPlan = this.assignmentManager.getBalancer().retainAssignment(regionsToAssign, onlineServers); - LOG.info("Bulk assigning " + regionsCount + " region(s) across " + bulkPlan.size() - + " server(s), retainAssignment=true"); + if (bulkPlan != null) { + LOG.info("Bulk assigning " + regionsCount + " region(s) across " + bulkPlan.size() + + " server(s), retainAssignment=true"); - BulkAssigner ba = new GeneralBulkAssigner(this.server, bulkPlan, this.assignmentManager, true); - try { - if (ba.bulkAssign()) { - done = true; + BulkAssigner ba = + new GeneralBulkAssigner(this.server, bulkPlan, this.assignmentManager, true); + try { + if (ba.bulkAssign()) { + done = true; + } + } catch (InterruptedException e) { + LOG.warn("Enable operation was interrupted when enabling table '" + + this.tableName + "'"); + // Preserve the interrupt. + Thread.currentThread().interrupt(); } - } catch (InterruptedException e) { - LOG.warn("Enable operation was interrupted when enabling table '" - + this.tableName + "'"); - // Preserve the interrupt. - Thread.currentThread().interrupt(); + } else { + LOG.info("Balancer was unable to find suitable servers for table " + tableName + + ", leaving unassigned"); + done = true; } if (done) { // Flip the table to enabled. diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/handler/TestEnableTableHandler.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/handler/TestEnableTableHandler.java new file mode 100644 index 00000000000..f5f2cd056df --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/handler/TestEnableTableHandler.java @@ -0,0 +1,101 @@ +/** + * + * 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.master.handler; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.master.HMaster; +import org.apache.hadoop.hbase.testclassification.MasterTests; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.JVMClusterUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@Category({ MasterTests.class, MediumTests.class }) +public class TestEnableTableHandler { + private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static final Log LOG = LogFactory.getLog(TestEnableTableHandler.class); + private static final byte[] FAMILYNAME = Bytes.toBytes("fam"); + + @Before + public void setUp() throws Exception { + TEST_UTIL.startMiniCluster(1); + } + + @After + public void tearDown() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test(timeout = 300000) + public void testEnableTableWithNoRegionServers() throws Exception { + final TableName tableName = TableName.valueOf("testEnableTableWithNoRegionServers"); + final MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); + final HMaster m = cluster.getMaster(); + final HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + final HTableDescriptor desc = new HTableDescriptor(tableName); + desc.addFamily(new HColumnDescriptor(FAMILYNAME)); + admin.createTable(desc); + admin.disableTable(tableName); + TEST_UTIL.waitTableDisabled(tableName.getName()); + + admin.enableTable(tableName); + TEST_UTIL.waitTableEnabled(tableName); + + // disable once more + admin.disableTable(tableName); + + // now stop region servers + JVMClusterUtil.RegionServerThread rs = cluster.getRegionServerThreads().get(0); + rs.getRegionServer().stop("stop"); + cluster.waitForRegionServerToStop(rs.getRegionServer().getServerName(), 10000); + + EnableTableHandler handler = + new EnableTableHandler(m, tableName, m.getAssignmentManager(), m.getTableLockManager(), + true); + handler.prepare(); + handler.process(); + + assertTrue(admin.isTableEnabled(tableName)); + + JVMClusterUtil.RegionServerThread rs2 = cluster.startRegionServer(); + m.getAssignmentManager().assign(admin.getTableRegions(tableName)); + TEST_UTIL.waitUntilAllRegionsAssigned(tableName); + List onlineRegions = admin.getOnlineRegions( + rs2.getRegionServer().getServerName()); + assertEquals(1, onlineRegions.size()); + assertEquals(tableName, onlineRegions.get(0).getTable()); + } + +}