commit 18e7b59731f586bff438986eb7fece56bf16c21a Author: Todd Lipcon Date: Mon May 17 18:29:06 2010 -0700 HBASE-2560. Don't throw IAE in getTableRegions if split is under way diff --git src/main/java/org/apache/hadoop/hbase/master/HMaster.java src/main/java/org/apache/hadoop/hbase/master/HMaster.java index c713245..27e28cb 100644 --- src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -808,7 +808,7 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, } // TODO: Redo so this method does not duplicate code with subsequent methods. - private List> getTableRegions( + List> getTableRegions( final byte [] tableName) throws IOException { List> result = @@ -834,7 +834,7 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, data.getValue(CATALOG_FAMILY, REGIONINFO_QUALIFIER)); if (Bytes.equals(info.getTableDesc().getName(), tableName)) { byte [] value = data.getValue(CATALOG_FAMILY, SERVER_QUALIFIER); - if (value != null) { + if (value != null && value.length > 0) { HServerAddress server = new HServerAddress(Bytes.toString(value)); result.add(new Pair(info, server)); } @@ -849,7 +849,7 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, return result; } - private Pair getTableRegionClosest( + Pair getTableRegionClosest( final byte [] tableName, final byte [] rowKey) throws IOException { Set regions = @@ -869,11 +869,12 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, break; HRegionInfo info = Writables.getHRegionInfo( data.getValue(CATALOG_FAMILY, REGIONINFO_QUALIFIER)); + System.err.println("gTRC: " + info); if (Bytes.compareTo(info.getTableDesc().getName(), tableName) == 0) { if ((Bytes.compareTo(info.getStartKey(), rowKey) >= 0) && (Bytes.compareTo(info.getEndKey(), rowKey) < 0)) { byte [] value = data.getValue(CATALOG_FAMILY, SERVER_QUALIFIER); - if (value != null) { + if (value != null && value.length > 0) { HServerAddress server = new HServerAddress(Bytes.toString(value)); return new Pair(info, server); @@ -890,7 +891,7 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, return null; } - private Pair getTableRegionFromName( + Pair getTableRegionFromName( final byte [] regionName) throws IOException { byte [] tableName = HRegionInfo.parseRegionName(regionName)[0]; @@ -906,7 +907,7 @@ public class HMaster extends Thread implements HConstants, HMasterInterface, HRegionInfo info = Writables.getHRegionInfo( data.getValue(CATALOG_FAMILY, REGIONINFO_QUALIFIER)); byte [] value = data.getValue(CATALOG_FAMILY, SERVER_QUALIFIER); - if(value != null) { + if(value != null && value.length > 0) { HServerAddress server = new HServerAddress(Bytes.toString(value)); return new Pair(info, server); diff --git src/test/java/org/apache/hadoop/hbase/master/TestMaster.java src/test/java/org/apache/hadoop/hbase/master/TestMaster.java new file mode 100644 index 0000000..47f020b --- /dev/null +++ src/test/java/org/apache/hadoop/hbase/master/TestMaster.java @@ -0,0 +1,128 @@ +/** + * 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.master; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.HMsg; +import org.apache.hadoop.hbase.HServerInfo; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HServerAddress; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Pair; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +public class TestMaster { + private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static final Log LOG = LogFactory.getLog(TestMasterWithDisabling.class); + private static final byte[] TABLENAME = Bytes.toBytes("TestMaster"); + private static final byte[] FAMILYNAME = Bytes.toBytes("fam"); + + @BeforeClass + public static void beforeAllTests() throws Exception { + // Start a cluster of two regionservers. + TEST_UTIL.startMiniCluster(1); + } + + @AfterClass + public static void afterAllTests() throws IOException { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testMasterOpsWhileSplitting() throws Exception { + MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster(); + HMaster m = cluster.getMaster(); + HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + + TEST_UTIL.createTable(TABLENAME, FAMILYNAME); + TEST_UTIL.loadTable(new HTable(TABLENAME), FAMILYNAME); + + CountDownLatch aboutToOpen = new CountDownLatch(1); + CountDownLatch proceed = new CountDownLatch(1); + RegionOpenListener list = new RegionOpenListener(aboutToOpen, proceed); + m.getRegionServerOperationQueue().registerRegionServerOperationListener(list); + + admin.split(TABLENAME); + aboutToOpen.await(); + + try { + m.getTableRegions(TABLENAME); + Pair pair = + m.getTableRegionClosest(TABLENAME, Bytes.toBytes("cde")); + assertNull(pair); + /** + * TODO: these methods return null when the regions are not deployed. + * It seems like instead they should return a pair where .second is null + *. If they did that, we could do the following: + assertNotNull(pair); + m.getTableRegionFromName(pair.getFirst().getRegionName()); + */ + } finally { + proceed.countDown(); + } + } + + static class RegionOpenListener implements RegionServerOperationListener { + CountDownLatch aboutToOpen, proceed; + + public RegionOpenListener( + CountDownLatch aboutToOpen, CountDownLatch proceed) + { + this.aboutToOpen = aboutToOpen; + this.proceed = proceed; + } + + @Override + public boolean process(HServerInfo serverInfo, HMsg incomingMsg) { + if (!incomingMsg.isType(HMsg.Type.MSG_REPORT_OPEN)) { + return true; + } + try { + aboutToOpen.countDown(); + proceed.await(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + return true; + } + + @Override + public boolean process(RegionServerOperation op) throws IOException { + return true; + } + + @Override + public void processed(RegionServerOperation op) { + } + } + +} \ No newline at end of file