/**
* 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;
import java.io.IOException;
import java.util.TreeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.io.Text;
/**
* Tests region server failover when a region server exits both cleanly and
* when it aborts.
*/
public class TestRegionServerExit extends HBaseClusterTestCase {
final Log LOG = LogFactory.getLog(this.getClass().getName());
HTable table;
/** constructor */
public TestRegionServerExit() {
super(2);
conf.setInt("ipc.client.timeout", 10000); // reduce client timeout
conf.setInt("ipc.client.connect.max.retries", 5); // and number of retries
conf.setInt("hbase.client.retries.number", 5); // reduce 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();
Text 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 region server and wait for it to go down.
this.cluster.abortRegionServer(0);
LOG.info(this.cluster.waitOnRegionServer(0) + " has been aborted");
Thread t = startVerificationThread(tableName, row);
t.start();
threadDumpingJoin(t);
}
/**
* Test abort of region server.
* @throws IOException
*/
public void REMOVEtestCleanExit() 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();
Text 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 shutdown the region server and wait for it to go down.
this.cluster.stopRegionServer(0);
LOG.info(this.cluster.waitOnRegionServer(0) + " has been shutdown");
Thread t = startVerificationThread(tableName, row);
t.start();
threadDumpingJoin(t);
}
private Text createTableAndAddRow(final String tableName) throws IOException {
HTableDescriptor desc = new HTableDescriptor(tableName);
desc.addFamily(new HColumnDescriptor(HConstants.COLUMN_FAMILY.toString()));
HBaseAdmin admin = new HBaseAdmin(conf);
admin.createTable(desc);
// put some values in the table
this.table = new HTable(conf, new Text(tableName));
final Text row = new Text("row1");
long lockid = table.startUpdate(row);
table.put(lockid, HConstants.COLUMN_FAMILY,
tableName.getBytes(HConstants.UTF8_ENCODING));
table.commit(lockid);
return row;
}
/*
* 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 Text row) {
Runnable runnable = new Runnable() {
public void run() {
HScannerInterface scanner = null;
try {
// Verify that the client can find the data after the region has moved
// to a different server
scanner =
table.obtainScanner(HConstants.COLUMN_FAMILY_ARRAY, new Text());
LOG.info("Obtained scanner " + scanner);
HStoreKey key = new HStoreKey();
TreeMap<Text, byte[]> results = new TreeMap<Text, byte[]>();
while (scanner.next(key, results)) {
assertTrue(key.getRow().equals(row));
assertEquals(1, results.size());
byte[] bytes = results.get(HConstants.COLUMN_FAMILY);
assertNotNull(bytes);
assertTrue(tableName.equals(new String(bytes,
HConstants.UTF8_ENCODING)));
}
LOG.info("Success!");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
LOG.info("Closing scanner " + scanner);
try {
scanner.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
return new Thread(runnable);
}
}