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