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