/** * Copyright 2007 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.regionserver; import java.io.IOException; import java.util.Collection; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.HBaseClusterTestCase; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.LocalHBaseCluster; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.JVMClusterUtil; /** * Tests region server failover when a region server exits both cleanly and * when it aborts. */ public class DisabledTestRegionServerExit extends HBaseClusterTestCase { final Log LOG = LogFactory.getLog(this.getClass().getName()); HTable table; /** constructor */ public DisabledTestRegionServerExit() { super(2); conf.setInt("ipc.client.connect.max.retries", 5); // reduce ipc retries conf.setInt("ipc.client.timeout", 10000); // and ipc timeout conf.setInt("hbase.client.pause", 10000); // increase client timeout conf.setInt("hbase.client.retries.number", 10); // increase HBase retries } /** * Test abort of region server. * @throws IOException */ public void testAbort() throws IOException { // When the META table can be opened, the region servers are running new HTable(conf, HConstants.META_TABLE_NAME); // Create table and add a row. final String tableName = getName(); byte [] row = createTableAndAddRow(tableName); // Start up a new region server to take over serving of root and meta // after we shut down the current meta/root host. this.cluster.startRegionServer(); // Now abort the meta region server and wait for it to go down and come back stopOrAbortMetaRegionServer(true); // Verify that everything is back up. LOG.info("Starting up the verification thread for " + getName()); Thread t = startVerificationThread(tableName, row); t.start(); threadDumpingJoin(t); } /** * Test abort of region server. * Test is flakey up on hudson. Needs work. * @throws IOException */ public void testCleanExit() throws IOException { // When the META table can be opened, the region servers are running new HTable(this.conf, HConstants.META_TABLE_NAME); // Create table and add a row. final String tableName = getName(); byte [] row = createTableAndAddRow(tableName); // Start up a new region server to take over serving of root and meta // after we shut down the current meta/root host. this.cluster.startRegionServer(); // Now abort the meta region server and wait for it to go down and come back stopOrAbortMetaRegionServer(false); // Verify that everything is back up. LOG.info("Starting up the verification thread for " + getName()); Thread t = startVerificationThread(tableName, row); t.start(); threadDumpingJoin(t); } private byte [] createTableAndAddRow(final String tableName) throws IOException { HTableDescriptor desc = new HTableDescriptor(tableName); desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); HBaseAdmin admin = new HBaseAdmin(conf); admin.createTable(desc); // put some values in the table this.table = new HTable(conf, tableName); byte [] row = Bytes.toBytes("row1"); Put put = new Put(row); put.add(HConstants.CATALOG_FAMILY, null, Bytes.toBytes(tableName)); table.put(put); return row; } /* * Stop the region server serving the meta region and wait for the meta region * to get reassigned. This is always the most problematic case. * * @param abort set to true if region server should be aborted, if false it * is just shut down. */ private void stopOrAbortMetaRegionServer(boolean abort) { List<JVMClusterUtil.RegionServerThread> regionThreads = cluster.getRegionServerThreads(); int server = -1; for (int i = 0; i < regionThreads.size() && server == -1; i++) { HRegionServer s = regionThreads.get(i).getRegionServer(); Collection<HRegion> regions = s.getOnlineRegionsLocalContext(); for (HRegion r : regions) { if (Bytes.equals(r.getTableDesc().getName(), HConstants.META_TABLE_NAME)) { server = i; } } } if (server == -1) { LOG.fatal("could not find region server serving meta region"); fail(); } if (abort) { this.cluster.abortRegionServer(server); } else { this.cluster.stopRegionServer(server); } LOG.info(this.cluster.waitOnRegionServer(server) + " has been " + (abort ? "aborted" : "shut down")); } /* * Run verification in a thread so I can concurrently run a thread-dumper * while we're waiting (because in this test sometimes the meta scanner * looks to be be stuck). * @param tableName Name of table to find. * @param row Row we expect to find. * @return Verification thread. Caller needs to calls start on it. */ private Thread startVerificationThread(final String tableName, final byte [] row) { Runnable runnable = new Runnable() { public void run() { try { // Now try to open a scanner on the meta table. Should stall until // meta server comes back up. HTable t = new HTable(conf, HConstants.META_TABLE_NAME); Scan scan = new Scan(); scan.addFamily(HConstants.CATALOG_FAMILY); ResultScanner s = t.getScanner(scan); s.close(); } catch (IOException e) { LOG.fatal("could not re-open meta table because", e); fail(); } ResultScanner scanner = null; try { // Verify that the client can find the data after the region has moved // to a different server Scan scan = new Scan(); scan.addFamily(HConstants.CATALOG_FAMILY); scanner = table.getScanner(scan); LOG.info("Obtained scanner " + scanner); for (Result r : scanner) { assertTrue(Bytes.equals(r.getRow(), row)); assertEquals(1, r.size()); byte[] bytes = r.value(); assertNotNull(bytes); assertTrue(tableName.equals(Bytes.toString(bytes))); } LOG.info("Success!"); } catch (Exception e) { e.printStackTrace(); fail(); } finally { if (scanner != null) { LOG.info("Closing scanner " + scanner); scanner.close(); } } } }; return new Thread(runnable); } }