commit d6dd44c90d6106c6565bcd0f7417040e404e3703 Author: stack Date: Sat Jan 10 12:00:59 2015 -0800 writing diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 4a33bcd..ea443e5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -1915,6 +1915,21 @@ public class HMaster extends HRegionServer implements MasterServices, Server { } /** + * Used in tests to stop the processing of dead servers a while so we can have the state of + * dead regionservers stick around longer. + * @param b + * @return State of the serverShutdownHandlerEnabled flag. + * @throws InterruptedException + * @throws IOException + */ + @VisibleForTesting + public boolean serverShutdownHandlerEnabled(boolean b) throws IOException, InterruptedException { + if (b) enableServerShutdownHandler(true); + else this.serverShutdownHandlerEnabled = b; + return b; + } + + /** * Report whether this master has started initialization and is about to do meta region assignment * @return true if master is in initialization & about to assign hbase:meta regions */ diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcessAccounting.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcessAccounting.java new file mode 100644 index 0000000..b820743 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncProcessAccounting.java @@ -0,0 +1,157 @@ +/** + * 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.client; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.List; +import java.util.Random; + +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.HTableDescriptor; +import org.apache.hadoop.hbase.MiniHBaseCluster; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; +import org.apache.hadoop.hbase.util.RegionSplitter; +import org.apache.hadoop.hbase.util.Threads; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({LargeTests.class}) +public class TestAsyncProcessAccounting { + final Log LOG = LogFactory.getLog(getClass()); + private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + // Do 100k not 1M. Takes too long. + private static final byte[][] ROWS = new byte[100000][]; + private final int SERVERS = 5; + private static final int ROWKEY_LENGTH = 16; + private final byte [] FAMILY = Bytes.toBytes("f"); + private static final TableName TABLENAME = TableName.valueOf("t"); + + + @Before + public void setUp() throws Exception { + TEST_UTIL.startMiniCluster(SERVERS); + byte[][] splits = new RegionSplitter.UniformSplit().split(SERVERS * 2); + HTableDescriptor htd = new HTableDescriptor(TABLENAME); + // Disable splitting! + htd.setMaxFileSize(10 * 1024 * 1024 * 1024); + htd.addFamily(new HColumnDescriptor(FAMILY)); + try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { + admin.createTable(htd, splits); + } + Random random = new Random(); + for (int i = 0; i < ROWS.length; i++) { + byte[] bytes = new byte[ROWKEY_LENGTH]; + random.nextBytes(bytes); + ROWS[i] = bytes; + } + } + + private void persist(Table t, int start, int stop, long count, byte[][] prev, + byte[][] current, byte[] id) + throws IOException { + for (int i = start; i < stop; i++) { + Put put = new Put(current[i]); + put.add(FAMILY, Bytes.toBytes("previous"), prev[i]); + if (count >= 0) { + put.add(FAMILY, Bytes.toBytes("count"), Bytes.toBytes(count + i)); + } + if (id != null) { + put.add(FAMILY, Bytes.toBytes("client"), id); + } + t.put(put); + if (i % 10000 == 0) LOG.info("PutCount=" + i); + } + t.flushCommits(); + } + + @After + public void tearDown() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + /** + * @return The non-meta server we killed. + * @throws IOException + */ + private ServerName killNonMetaRegionServer() throws IOException { + ServerName metaServer = TEST_UTIL.getHBaseCluster().getServerHoldingMeta(); + List rss = TEST_UTIL.getHBaseCluster().getRegionServerThreads(); + for (RegionServerThread t: rss) { + ServerName sn = t.getRegionServer().getServerName(); + if (sn.equals(metaServer)) continue; + if (t.getRegionServer().isStopped()) continue; + LOG.info("Killing " + sn); + ((MiniHBaseCluster.MiniHBaseClusterRegionServer)t.getRegionServer()).kill(); + // We killed one. Return. + return sn; + } + return null; + } + + private void killAndHang() { + try { + LOG.info("Stopped processing of dead servers"); + TEST_UTIL.getHBaseCluster().getMaster().serverShutdownHandlerEnabled(false); + killNonMetaRegionServer(); + Threads.sleep(60000); + LOG.info("Starting processing of dead servers"); + TEST_UTIL.getHBaseCluster().getMaster().serverShutdownHandlerEnabled(true); + } catch (IOException e) { + LOG.error(e); + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Test + public void testAccounting() throws IOException { + try (Table t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME)) { + t.setAutoFlushTo(false); + t.setWriteBufferSize(4 * 1024 * 1024); + Thread backgroundTask = new Thread("background killer") { + @Override + public void run() { + killAndHang(); + killAndHang(); + } + }; + backgroundTask.start(); + persist(t, 0, ROWS.length, 0, ROWS, ROWS, Bytes.toBytes("client")); + // Ensure all are there. + try (ResultScanner scanner = t.getScanner(new Scan())) { + int count = 0; + while (scanner.next() != null) { + if (count % 10000 == 0) LOG.info("RowCount=" + count); + count++; + } + assertEquals(ROWS.length, count); + } + } + } +} \ No newline at end of file diff --git a/hbase-server/src/test/resources/log4j.properties b/hbase-server/src/test/resources/log4j.properties index 6ee91ef..45a0854 100644 --- a/hbase-server/src/test/resources/log4j.properties +++ b/hbase-server/src/test/resources/log4j.properties @@ -57,6 +57,7 @@ log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %C{2}(%L): log4j.logger.org.apache.hadoop=WARN log4j.logger.org.apache.zookeeper=ERROR log4j.logger.org.apache.hadoop.hbase=DEBUG +log4j.logger.org.apache.hadoop.hbase.ipc.AbstractRpcClient=INFO #These two settings are workarounds against spurious logs from the minicluster. #See HBASE-4709