/** * * 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 static org.junit.Assert.fail; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.LargeTests; import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.util.Bytes; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; /** * Test various scanner timeout issues. */ @Category(LargeTests.class) public class TestScannerTimeout { private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); final Log LOG = LogFactory.getLog(getClass()); private final static byte[] SOME_BYTES = Bytes.toBytes("f"); private final static byte[] TABLE_NAME = Bytes.toBytes("t"); private final static int NB_ROWS = 10; // Be careful w/ what you set this timer to... it can get in the way of // the mini cluster coming up -- the verification in particular. private final static int THREAD_WAKE_FREQUENCY = 1000; private final static int SCANNER_TIMEOUT = 10000; private final static int SCANNER_CACHING = 5; /** * @throws java.lang.Exception */ @BeforeClass public static void setUpBeforeClass() throws Exception { Configuration c = TEST_UTIL.getConfiguration(); c.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT); c.setInt(HConstants.THREAD_WAKE_FREQUENCY, THREAD_WAKE_FREQUENCY); // We need more than one region server for this test TEST_UTIL.startMiniCluster(2); HTable table = TEST_UTIL.createTable(TABLE_NAME, SOME_BYTES); for (int i = 0; i < NB_ROWS; i++) { Put put = new Put(Bytes.toBytes(i)); put.add(SOME_BYTES, SOME_BYTES, SOME_BYTES); table.put(put); } table.close(); } /** * @throws java.lang.Exception */ @AfterClass public static void tearDownAfterClass() throws Exception { TEST_UTIL.shutdownMiniCluster(); } /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { TEST_UTIL.ensureSomeRegionServersAvailable(2); } /** * Test that we do get a ScannerTimeoutException * @throws Exception */ @Test(timeout=300000) public void test2481() throws Exception { LOG.info("START ************ test2481"); Scan scan = new Scan(); HTable table = new HTable(new Configuration(TEST_UTIL.getConfiguration()), TABLE_NAME); ResultScanner r = table.getScanner(scan); int count = 0; try { Result res = r.next(); while (res != null) { count++; if (count == 5) { // Sleep just a bit more to be sure Thread.sleep(SCANNER_TIMEOUT + THREAD_WAKE_FREQUENCY + 100); } res = r.next(); } } catch (ScannerTimeoutException e) { LOG.info("Got the timeout " + e.getMessage(), e); return; } finally { table.close(); } fail("We should be timing out"); LOG.info("END ************ test2481"); } /** * Test that scanner can continue even if the region server it was reading * from failed. Before 2772, it reused the same scanner id. * @throws Exception */ @Test(timeout=300000) public void test2772() throws Exception { LOG.info("START************ test2772"); HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); Scan scan = new Scan(); // Set a very high timeout, we want to test what happens when a RS // fails but the region is recovered before the lease times out. // Since the RS is already created, this conf is client-side only for // this new table Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT * 100); HTable higherScanTimeoutTable = new HTable(conf, TABLE_NAME); ResultScanner r = higherScanTimeoutTable.getScanner(scan); // This takes way less than SCANNER_TIMEOUT*100 rs.abort("die!"); Result[] results = r.next(NB_ROWS); assertEquals(NB_ROWS, results.length); r.close(); higherScanTimeoutTable.close(); LOG.info("END ************ test2772"); } /** * Test that scanner won't miss any rows if the region server it was reading * from failed. Before 3686, it would skip rows in the scan. * @throws Exception */ @Test(timeout=300000) public void test3686a() throws Exception { LOG.info("START ************ TEST3686A---1"); HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); LOG.info("START ************ TEST3686A---1111"); Scan scan = new Scan(); scan.setCaching(SCANNER_CACHING); LOG.info("************ TEST3686A"); MetaReader.fullScanMetaAndPrint(TEST_UTIL.getHBaseCluster().getMaster().getCatalogTracker()); HTable table = new HTable(TEST_UTIL.getConfiguration(), TABLE_NAME); LOG.info("START ************ TEST3686A---22"); ResultScanner r = table.getScanner(scan); LOG.info("START ************ TEST3686A---33"); int count = 1; r.next(); LOG.info("START ************ TEST3686A---44"); // Kill after one call to next(), which got 5 rows. rs.abort("die!"); while(r.next() != null) { count ++; } assertEquals(NB_ROWS, count); r.close(); table.close(); LOG.info("************ END TEST3686A"); } /** * Make sure that no rows are lost if the scanner timeout is longer on the * client than the server, and the scan times out on the server but not the * client. * @throws Exception */ @Test(timeout=300000) public void test3686b() throws Exception { LOG.info("START ************ test3686b"); HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); Scan scan = new Scan(); scan.setCaching(SCANNER_CACHING); // Set a very high timeout, we want to test what happens when a RS // fails but the region is recovered before the lease times out. // Since the RS is already created, this conf is client-side only for // this new table Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT * 100); HTable higherScanTimeoutTable = new HTable(conf, TABLE_NAME); ResultScanner r = higherScanTimeoutTable.getScanner(scan); int count = 1; r.next(); // Sleep, allowing the scan to timeout on the server but not on the client. Thread.sleep(SCANNER_TIMEOUT+2000); while(r.next() != null) { count ++; } assertEquals(NB_ROWS, count); r.close(); higherScanTimeoutTable.close(); LOG.info("END ************ END test3686b"); } }