1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.client;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.fail;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.*;
29  import org.apache.hadoop.hbase.catalog.MetaReader;
30  import org.apache.hadoop.hbase.regionserver.HRegionServer;
31  import org.apache.hadoop.hbase.util.Bytes;
32  import org.junit.AfterClass;
33  import org.junit.Before;
34  import org.junit.BeforeClass;
35  import org.junit.Test;
36  import org.junit.experimental.categories.Category;
37  
38  /**
39   * Test various scanner timeout issues.
40   */
41  @Category(LargeTests.class)
42  public class TestScannerTimeout {
43  
44    private final static HBaseTestingUtility
45        TEST_UTIL = new HBaseTestingUtility();
46  
47    final Log LOG = LogFactory.getLog(getClass());
48    private final static byte[] SOME_BYTES = Bytes.toBytes("f");
49    private final static byte[] TABLE_NAME = Bytes.toBytes("t");
50    private final static int NB_ROWS = 10;
51    // Be careful w/ what you set this timer too... it can get in the way of
52    // the mini cluster coming up -- the verification in particular.
53    private final static int SCANNER_TIMEOUT = 15000;
54    private final static int SCANNER_CACHING = 5;
55  
56     /**
57     * @throws java.lang.Exception
58     */
59    @BeforeClass
60    public static void setUpBeforeClass() throws Exception {
61      Configuration c = TEST_UTIL.getConfiguration();
62      c.setInt("hbase.regionserver.lease.period", SCANNER_TIMEOUT);
63      // We need more than one region server for this test
64      TEST_UTIL.startMiniCluster(2);
65      HTable table = TEST_UTIL.createTable(TABLE_NAME, SOME_BYTES);
66       for (int i = 0; i < NB_ROWS; i++) {
67        Put put = new Put(Bytes.toBytes(i));
68        put.add(SOME_BYTES, SOME_BYTES, SOME_BYTES);
69        table.put(put);
70      }
71      table.close();
72    }
73  
74    /**
75     * @throws java.lang.Exception
76     */
77    @AfterClass
78    public static void tearDownAfterClass() throws Exception {
79      TEST_UTIL.shutdownMiniCluster();
80    }
81  
82    /**
83     * @throws java.lang.Exception
84     */
85    @Before
86    public void setUp() throws Exception {
87      TEST_UTIL.ensureSomeNonStoppedRegionServersAvailable(2);
88    }
89  
90    /**
91     * Test that we do get a ScannerTimeoutException
92     * @throws Exception
93     */
94    @Test(timeout=300000)
95    public void test2481() throws Exception {
96      LOG.info("START ************ test2481");
97      Scan scan = new Scan();
98      HTable table =
99        new HTable(new Configuration(TEST_UTIL.getConfiguration()), TABLE_NAME);
100     ResultScanner r = table.getScanner(scan);
101     int count = 0;
102     try {
103       Result res = r.next();
104       while (res != null) {
105         count++;
106         if (count == 5) {
107           // Sleep just a bit more to be sure
108           Thread.sleep(SCANNER_TIMEOUT+100);
109         }
110         res = r.next();
111       }
112     } catch (ScannerTimeoutException e) {
113       LOG.info("Got the timeout " + e.getMessage(), e);
114       return;
115     }  finally {
116       table.close();
117     }
118     fail("We should be timing out");
119     LOG.info("END ************ test2481");
120   }
121 
122   /**
123    * Test that scanner can continue even if the region server it was reading
124    * from failed. Before 2772, it reused the same scanner id.
125    * @throws Exception
126    */
127   @Test(timeout=300000)
128   public void test2772() throws Exception {
129     LOG.info("START************ test2772");
130     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME);
131     Scan scan = new Scan();
132     // Set a very high timeout, we want to test what happens when a RS
133     // fails but the region is recovered before the lease times out.
134     // Since the RS is already created, this conf is client-side only for
135     // this new table
136     Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
137     conf.setInt(
138         HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, SCANNER_TIMEOUT*100);
139     HTable higherScanTimeoutTable = new HTable(conf, TABLE_NAME);
140     ResultScanner r = higherScanTimeoutTable.getScanner(scan);
141     // This takes way less than SCANNER_TIMEOUT*100
142     rs.abort("die!");
143     Result[] results = r.next(NB_ROWS);
144     assertEquals(NB_ROWS, results.length);
145     r.close();
146     higherScanTimeoutTable.close();
147     LOG.info("END ************ test2772");
148 
149   }
150   
151   /**
152    * Test that scanner won't miss any rows if the region server it was reading
153    * from failed. Before 3686, it would skip rows in the scan.
154    * @throws Exception
155    */
156   @Test(timeout=300000)
157   public void test3686a() throws Exception {
158     LOG.info("START ************ TEST3686A---1");
159     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME);
160     LOG.info("START ************ TEST3686A---1111");
161 
162     Scan scan = new Scan();
163     scan.setCaching(SCANNER_CACHING);
164     LOG.info("************ TEST3686A");
165     MetaReader.fullScanMetaAndPrint(TEST_UTIL.getHBaseCluster().getMaster().getCatalogTracker());
166     HTable table = new HTable(TEST_UTIL.getConfiguration(), TABLE_NAME);
167     LOG.info("START ************ TEST3686A---22");
168 
169     ResultScanner r = table.getScanner(scan);
170     LOG.info("START ************ TEST3686A---33");
171 
172     int count = 1;
173     r.next();
174     LOG.info("START ************ TEST3686A---44");
175 
176     // Kill after one call to next(), which got 5 rows.
177     rs.abort("die!");
178     while(r.next() != null) {
179       count ++;
180     }
181     assertEquals(NB_ROWS, count);
182     r.close();
183     table.close();
184     LOG.info("************ END TEST3686A");
185   }
186   
187   /**
188    * Make sure that no rows are lost if the scanner timeout is longer on the
189    * client than the server, and the scan times out on the server but not the
190    * client.
191    * @throws Exception
192    */
193   @Test(timeout=300000)
194   public void test3686b() throws Exception {
195     LOG.info("START ************ test3686b");
196     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME);
197     Scan scan = new Scan();
198     scan.setCaching(SCANNER_CACHING);
199     // Set a very high timeout, we want to test what happens when a RS
200     // fails but the region is recovered before the lease times out.
201     // Since the RS is already created, this conf is client-side only for
202     // this new table
203     Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
204     conf.setInt(
205         HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, SCANNER_TIMEOUT*100);
206     HTable higherScanTimeoutTable = new HTable(conf, TABLE_NAME);
207     ResultScanner r = higherScanTimeoutTable.getScanner(scan);
208     int count = 1;
209     r.next();
210     // Sleep, allowing the scan to timeout on the server but not on the client.
211     Thread.sleep(SCANNER_TIMEOUT+2000);
212     while(r.next() != null) {
213       count ++;
214     }
215     assertEquals(NB_ROWS, count);
216     r.close();
217     higherScanTimeoutTable.close();
218     LOG.info("END ************ END test3686b");
219 
220   }
221 
222   @org.junit.Rule
223   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
224     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
225 }
226