001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.fail; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.HBaseTestingUtility; 026import org.apache.hadoop.hbase.HConstants; 027import org.apache.hadoop.hbase.MetaTableAccessor; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.regionserver.HRegionServer; 030import org.apache.hadoop.hbase.testclassification.ClientTests; 031import org.apache.hadoop.hbase.testclassification.LargeTests; 032import org.apache.hadoop.hbase.util.Bytes; 033import org.junit.AfterClass; 034import org.junit.Before; 035import org.junit.BeforeClass; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042/** 043 * Test various scanner timeout issues. 044 */ 045@Category({LargeTests.class, ClientTests.class}) 046public class TestScannerTimeout { 047 048 @ClassRule 049 public static final HBaseClassTestRule CLASS_RULE = 050 HBaseClassTestRule.forClass(TestScannerTimeout.class); 051 052 private final static HBaseTestingUtility 053 TEST_UTIL = new HBaseTestingUtility(); 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestScannerTimeout.class); 056 private final static byte[] SOME_BYTES = Bytes.toBytes("f"); 057 private final static TableName TABLE_NAME = TableName.valueOf("t"); 058 private final static int NB_ROWS = 10; 059 // Be careful w/ what you set this timer to... it can get in the way of 060 // the mini cluster coming up -- the verification in particular. 061 private final static int THREAD_WAKE_FREQUENCY = 1000; 062 private final static int SCANNER_TIMEOUT = 15000; 063 private final static int SCANNER_CACHING = 5; 064 065 /** 066 * @throws java.lang.Exception 067 */ 068 @BeforeClass 069 public static void setUpBeforeClass() throws Exception { 070 Configuration c = TEST_UTIL.getConfiguration(); 071 c.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT); 072 c.setInt(HConstants.THREAD_WAKE_FREQUENCY, THREAD_WAKE_FREQUENCY); 073 // We need more than one region server for this test 074 TEST_UTIL.startMiniCluster(2); 075 Table table = TEST_UTIL.createTable(TABLE_NAME, SOME_BYTES); 076 for (int i = 0; i < NB_ROWS; i++) { 077 Put put = new Put(Bytes.toBytes(i)); 078 put.addColumn(SOME_BYTES, SOME_BYTES, SOME_BYTES); 079 table.put(put); 080 } 081 table.close(); 082 } 083 084 /** 085 * @throws java.lang.Exception 086 */ 087 @AfterClass 088 public static void tearDownAfterClass() throws Exception { 089 TEST_UTIL.shutdownMiniCluster(); 090 } 091 092 /** 093 * @throws java.lang.Exception 094 */ 095 @Before 096 public void setUp() throws Exception { 097 TEST_UTIL.ensureSomeNonStoppedRegionServersAvailable(2); 098 } 099 100 /** 101 * Test that scanner can continue even if the region server it was reading 102 * from failed. Before 2772, it reused the same scanner id. 103 * @throws Exception 104 */ 105 @Test 106 public void test2772() throws Exception { 107 LOG.info("START************ test2772"); 108 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); 109 Scan scan = new Scan(); 110 // Set a very high timeout, we want to test what happens when a RS 111 // fails but the region is recovered before the lease times out. 112 // Since the RS is already created, this conf is client-side only for 113 // this new table 114 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 115 conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT * 100); 116 117 Connection connection = ConnectionFactory.createConnection(conf); 118 Table higherScanTimeoutTable = connection.getTable(TABLE_NAME); 119 ResultScanner r = higherScanTimeoutTable.getScanner(scan); 120 // This takes way less than SCANNER_TIMEOUT*100 121 rs.abort("die!"); 122 Result[] results = r.next(NB_ROWS); 123 assertEquals(NB_ROWS, results.length); 124 r.close(); 125 higherScanTimeoutTable.close(); 126 connection.close(); 127 LOG.info("END ************ test2772"); 128 129 } 130 131 /** 132 * Test that scanner won't miss any rows if the region server it was reading 133 * from failed. Before 3686, it would skip rows in the scan. 134 * @throws Exception 135 */ 136 @Test 137 public void test3686a() throws Exception { 138 LOG.info("START ************ TEST3686A---1"); 139 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); 140 LOG.info("START ************ TEST3686A---1111"); 141 142 Scan scan = new Scan(); 143 scan.setCaching(SCANNER_CACHING); 144 LOG.info("************ TEST3686A"); 145 MetaTableAccessor.fullScanMetaAndPrint(TEST_UTIL.getAdmin().getConnection()); 146 // Set a very high timeout, we want to test what happens when a RS 147 // fails but the region is recovered before the lease times out. 148 // Since the RS is already created, this conf is client-side only for 149 // this new table 150 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 151 conf.setInt( 152 HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT*100); 153 Connection connection = ConnectionFactory.createConnection(conf); 154 Table table = connection.getTable(TABLE_NAME); 155 LOG.info("START ************ TEST3686A---22"); 156 157 ResultScanner r = table.getScanner(scan); 158 LOG.info("START ************ TEST3686A---33"); 159 160 int count = 1; 161 r.next(); 162 LOG.info("START ************ TEST3686A---44"); 163 164 // Kill after one call to next(), which got 5 rows. 165 rs.abort("die!"); 166 while(r.next() != null) { 167 count ++; 168 } 169 assertEquals(NB_ROWS, count); 170 r.close(); 171 table.close(); 172 connection.close(); 173 LOG.info("************ END TEST3686A"); 174 } 175 176 /** 177 * Make sure that no rows are lost if the scanner timeout is longer on the 178 * client than the server, and the scan times out on the server but not the 179 * client. 180 * @throws Exception 181 */ 182 @Test 183 public void test3686b() throws Exception { 184 LOG.info("START ************ test3686b"); 185 HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); 186 Scan scan = new Scan(); 187 scan.setCaching(SCANNER_CACHING); 188 // Set a very high timeout, we want to test what happens when a RS 189 // fails but the region is recovered before the lease times out. 190 // Since the RS is already created, this conf is client-side only for 191 // this new table 192 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 193 conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, SCANNER_TIMEOUT * 100); 194 Connection connection = ConnectionFactory.createConnection(conf); 195 Table higherScanTimeoutTable = connection.getTable(TABLE_NAME); 196 ResultScanner r = higherScanTimeoutTable.getScanner(scan); 197 int count = 1; 198 r.next(); 199 // Sleep, allowing the scan to timeout on the server but not on the client. 200 Thread.sleep(SCANNER_TIMEOUT+2000); 201 while(r.next() != null) { 202 count ++; 203 } 204 assertEquals(NB_ROWS, count); 205 r.close(); 206 higherScanTimeoutTable.close(); 207 connection.close(); 208 LOG.info("END ************ END test3686b"); 209 210 } 211 212} 213