View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.hbase.Cell;
28  import org.apache.hadoop.hbase.CellUtil;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HTestConst;
32  import org.apache.hadoop.hbase.KeyValue;
33  import org.apache.hadoop.hbase.TableName;
34  import org.apache.hadoop.hbase.client.Put;
35  import org.apache.hadoop.hbase.client.Result;
36  import org.apache.hadoop.hbase.client.ResultScanner;
37  import org.apache.hadoop.hbase.client.Scan;
38  import org.apache.hadoop.hbase.client.Table;
39  import org.apache.hadoop.hbase.filter.Filter;
40  import org.apache.hadoop.hbase.filter.FilterBase;
41  import org.apache.hadoop.hbase.testclassification.MediumTests;
42  import org.apache.hadoop.hbase.util.Bytes;
43  import org.apache.hadoop.hbase.util.Threads;
44  import org.junit.AfterClass;
45  import org.junit.Assert;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  import org.junit.experimental.categories.Category;
49  
50  @Category(MediumTests.class)
51  public class TestScannerCursor {
52  
53    private static final Log LOG =
54        LogFactory.getLog(TestScannerCursor.class);
55  
56    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
57  
58    private static Table TABLE = null;
59  
60    /**
61     * Table configuration
62     */
63    private static TableName TABLE_NAME = TableName.valueOf("TestScannerCursor");
64  
65    private static int NUM_ROWS = 5;
66    private static byte[] ROW = Bytes.toBytes("testRow");
67    private static byte[][] ROWS = HTestConst.makeNAscii(ROW, NUM_ROWS);
68  
69    private static int NUM_FAMILIES = 2;
70    private static byte[] FAMILY = Bytes.toBytes("testFamily");
71    private static byte[][] FAMILIES = HTestConst.makeNAscii(FAMILY, NUM_FAMILIES);
72  
73    private static int NUM_QUALIFIERS = 2;
74    private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
75    private static byte[][] QUALIFIERS = HTestConst.makeNAscii(QUALIFIER, NUM_QUALIFIERS);
76  
77    private static int VALUE_SIZE = 10;
78    private static byte[] VALUE = Bytes.createMaxByteArray(VALUE_SIZE);
79  
80    private static final int TIMEOUT = 4000;
81  
82    @BeforeClass
83    public static void setUpBeforeClass() throws Exception {
84      Configuration conf = TEST_UTIL.getConfiguration();
85  
86      conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, TIMEOUT);
87      conf.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, TIMEOUT);
88  
89      // Check the timeout condition after every cell
90      conf.setLong(StoreScanner.HBASE_CELLS_SCANNED_PER_HEARTBEAT_CHECK, 1);
91      TEST_UTIL.startMiniCluster(1);
92  
93      TABLE = createTestTable(TABLE_NAME, ROWS, FAMILIES, QUALIFIERS, VALUE);
94  
95    }
96  
97    static Table createTestTable(TableName name, byte[][] rows, byte[][] families,
98        byte[][] qualifiers, byte[] cellValue) throws IOException {
99      Table ht = TEST_UTIL.createTable(name, families);
100     List<Put> puts = createPuts(rows, families, qualifiers, cellValue);
101     ht.put(puts);
102     return ht;
103   }
104 
105   static ArrayList<Put> createPuts(byte[][] rows, byte[][] families, byte[][] qualifiers,
106       byte[] value) throws IOException {
107     Put put;
108     ArrayList<Put> puts = new ArrayList<>();
109 
110     for (int row = 0; row < rows.length; row++) {
111       put = new Put(rows[row]);
112       for (int fam = 0; fam < families.length; fam++) {
113         for (int qual = 0; qual < qualifiers.length; qual++) {
114           KeyValue kv = new KeyValue(rows[row], families[fam], qualifiers[qual], qual, value);
115           put.add(kv);
116         }
117       }
118       puts.add(put);
119     }
120 
121     return puts;
122   }
123 
124   @AfterClass
125   public static void tearDownAfterClass() throws Exception {
126     TEST_UTIL.shutdownMiniCluster();
127   }
128 
129   public static class SparseFilter extends FilterBase {
130 
131     @Override
132     public ReturnCode filterKeyValue(Cell v) throws IOException {
133       Threads.sleep(TIMEOUT / 2 + 100);
134       return Bytes.equals(CellUtil.cloneRow(v), ROWS[NUM_ROWS - 1]) ? ReturnCode.INCLUDE
135           : ReturnCode.SKIP;
136     }
137 
138     public static Filter parseFrom(final byte[] pbBytes) {
139       return new SparseFilter();
140     }
141   }
142 
143   @Test
144   public void testHeartbeatWithSparseFilter() throws Exception {
145     Scan scan = new Scan();
146     scan.setMaxResultSize(Long.MAX_VALUE);
147     scan.setCaching(Integer.MAX_VALUE);
148     scan.setNeedCursorResult(true);
149     scan.setAllowPartialResults(true);
150     scan.setFilter(new SparseFilter());
151     try(ResultScanner scanner = TABLE.getScanner(scan)) {
152       int num = 0;
153       Result r;
154       while ((r = scanner.next()) != null) {
155 
156         if (num < (NUM_ROWS - 1) * NUM_FAMILIES * NUM_QUALIFIERS) {
157           Assert.assertTrue(r.isCursor());
158           Assert.assertArrayEquals(ROWS[num / NUM_FAMILIES / NUM_QUALIFIERS], r.getCursor().getRow());
159         } else {
160           Assert.assertFalse(r.isCursor());
161           Assert.assertArrayEquals(ROWS[num / NUM_FAMILIES / NUM_QUALIFIERS], r.getRow());
162         }
163         num++;
164       }
165     }
166   }
167 
168   @Test
169   public void testSizeLimit() throws IOException {
170     Scan scan = new Scan();
171     scan.setMaxResultSize(1);
172     scan.setCaching(Integer.MAX_VALUE);
173     scan.setNeedCursorResult(true);
174     try (ResultScanner scanner = TABLE.getScanner(scan)) {
175       int num = 0;
176       Result r;
177       while ((r = scanner.next()) != null) {
178 
179         if (num % (NUM_FAMILIES * NUM_QUALIFIERS) != (NUM_FAMILIES * NUM_QUALIFIERS)-1) {
180           Assert.assertTrue(r.isCursor());
181           Assert.assertArrayEquals(ROWS[num / NUM_FAMILIES / NUM_QUALIFIERS], r.getCursor().getRow());
182         } else {
183           Assert.assertFalse(r.isCursor());
184           Assert.assertArrayEquals(ROWS[num / NUM_FAMILIES / NUM_QUALIFIERS], r.getRow());
185         }
186         num++;
187       }
188     }
189   }
190 
191 }