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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org
.apache
.hadoop
.hbase
.client
;
20 import static org
.apache
.hadoop
.hbase
.HConstants
.RPC_CODEC_CONF_KEY
;
21 import static org
.apache
.hadoop
.hbase
.client
.TestFromClientSide3
.generateHugeValue
;
22 import static org
.apache
.hadoop
.hbase
.ipc
.RpcClient
.DEFAULT_CODEC_CLASS
;
23 import static org
.junit
.Assert
.assertArrayEquals
;
24 import static org
.junit
.Assert
.assertEquals
;
25 import static org
.junit
.Assert
.assertFalse
;
26 import static org
.junit
.Assert
.assertNotNull
;
27 import static org
.junit
.Assert
.assertNull
;
28 import static org
.junit
.Assert
.assertTrue
;
29 import static org
.junit
.Assert
.fail
;
31 import java
.io
.IOException
;
32 import java
.util
.ArrayList
;
33 import java
.util
.List
;
34 import java
.util
.concurrent
.TimeUnit
;
35 import java
.util
.function
.Consumer
;
36 import java
.util
.stream
.IntStream
;
37 import org
.apache
.hadoop
.conf
.Configuration
;
38 import org
.apache
.hadoop
.hbase
.Cell
;
39 import org
.apache
.hadoop
.hbase
.CompareOperator
;
40 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
41 import org
.apache
.hadoop
.hbase
.HBaseTestingUtility
;
42 import org
.apache
.hadoop
.hbase
.HColumnDescriptor
;
43 import org
.apache
.hadoop
.hbase
.HConstants
;
44 import org
.apache
.hadoop
.hbase
.HRegionInfo
;
45 import org
.apache
.hadoop
.hbase
.HRegionLocation
;
46 import org
.apache
.hadoop
.hbase
.HTestConst
;
47 import org
.apache
.hadoop
.hbase
.KeyValue
;
48 import org
.apache
.hadoop
.hbase
.MiniHBaseCluster
;
49 import org
.apache
.hadoop
.hbase
.TableName
;
50 import org
.apache
.hadoop
.hbase
.TableNotFoundException
;
51 import org
.apache
.hadoop
.hbase
.filter
.BinaryComparator
;
52 import org
.apache
.hadoop
.hbase
.filter
.ColumnPrefixFilter
;
53 import org
.apache
.hadoop
.hbase
.filter
.ColumnRangeFilter
;
54 import org
.apache
.hadoop
.hbase
.filter
.QualifierFilter
;
55 import org
.apache
.hadoop
.hbase
.regionserver
.HRegionServer
;
56 import org
.apache
.hadoop
.hbase
.testclassification
.ClientTests
;
57 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
58 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
59 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
60 import org
.junit
.After
;
61 import org
.junit
.AfterClass
;
62 import org
.junit
.Before
;
63 import org
.junit
.BeforeClass
;
64 import org
.junit
.ClassRule
;
65 import org
.junit
.Rule
;
66 import org
.junit
.Test
;
67 import org
.junit
.experimental
.categories
.Category
;
68 import org
.junit
.rules
.TestName
;
69 import org
.slf4j
.Logger
;
70 import org
.slf4j
.LoggerFactory
;
73 * A client-side test, mostly testing scanners with various parameters.
75 @Category({MediumTests
.class, ClientTests
.class})
76 public class TestScannersFromClientSide
{
79 public static final HBaseClassTestRule CLASS_RULE
=
80 HBaseClassTestRule
.forClass(TestScannersFromClientSide
.class);
82 private static final Logger LOG
= LoggerFactory
.getLogger(TestScannersFromClientSide
.class);
84 private final static HBaseTestingUtility TEST_UTIL
= new HBaseTestingUtility();
85 private static byte [] ROW
= Bytes
.toBytes("testRow");
86 private static byte [] FAMILY
= Bytes
.toBytes("testFamily");
87 private static byte [] QUALIFIER
= Bytes
.toBytes("testQualifier");
88 private static byte [] VALUE
= Bytes
.toBytes("testValue");
91 public TestName name
= new TestName();
94 * @throws java.lang.Exception
97 public static void setUpBeforeClass() throws Exception
{
98 Configuration conf
= TEST_UTIL
.getConfiguration();
99 conf
.setLong(HConstants
.HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY
, 10 * 1024 * 1024);
100 TEST_UTIL
.startMiniCluster(3);
104 * @throws java.lang.Exception
107 public static void tearDownAfterClass() throws Exception
{
108 TEST_UTIL
.shutdownMiniCluster();
112 * @throws java.lang.Exception
115 public void setUp() throws Exception
{
120 * @throws java.lang.Exception
123 public void tearDown() throws Exception
{
128 * Test from client side for batch of scan
133 public void testScanBatch() throws Exception
{
134 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
135 byte [][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, 8);
137 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILY
);
143 ResultScanner scanner
;
144 boolean toLog
= true;
145 List
<Cell
> kvListExp
;
147 // table: row, family, c0:0, c1:1, ... , c7:7
149 for (int i
=0; i
< QUALIFIERS
.length
; i
++) {
150 KeyValue kv
= new KeyValue(ROW
, FAMILY
, QUALIFIERS
[i
], i
, VALUE
);
155 // table: row, family, c0:0, c1:1, ..., c6:2, c6:6 , c7:7
157 KeyValue kv
= new KeyValue(ROW
, FAMILY
, QUALIFIERS
[6], 2, VALUE
);
162 delete
= new Delete(ROW
);
163 delete
.addFamily(FAMILY
, 3);
167 scan
= new Scan().withStartRow(ROW
);
168 scan
.setMaxVersions();
169 scanner
= ht
.getScanner(scan
);
171 // c4:4, c5:5, c6:6, c7:7
172 kvListExp
= new ArrayList
<>();
173 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[4], 4, VALUE
));
174 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[5], 5, VALUE
));
175 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[6], 6, VALUE
));
176 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[7], 7, VALUE
));
177 result
= scanner
.next();
178 verifyResult(result
, kvListExp
, toLog
, "Testing first batch of scan");
181 scan
= new Scan().withStartRow(ROW
);
182 scan
.setMaxVersions();
184 scanner
= ht
.getScanner(scan
);
186 // First batch: c4:4, c5:5
187 kvListExp
= new ArrayList
<>();
188 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[4], 4, VALUE
));
189 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[5], 5, VALUE
));
190 result
= scanner
.next();
191 verifyResult(result
, kvListExp
, toLog
, "Testing first batch of scan");
193 // Second batch: c6:6, c7:7
194 kvListExp
= new ArrayList
<>();
195 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[6], 6, VALUE
));
196 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[7], 7, VALUE
));
197 result
= scanner
.next();
198 verifyResult(result
, kvListExp
, toLog
, "Testing second batch of scan");
203 public void testMaxResultSizeIsSetToDefault() throws Exception
{
204 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
205 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILY
);
207 // The max result size we expect the scan to use by default.
208 long expectedMaxResultSize
=
209 TEST_UTIL
.getConfiguration().getLong(HConstants
.HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY
,
210 HConstants
.DEFAULT_HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE
);
213 byte[][] ROWS
= HTestConst
.makeNAscii(ROW
, numRows
);
215 int numQualifiers
= 10;
216 byte[][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, numQualifiers
);
218 // Specify the cell size such that a single row will be larger than the default
219 // value of maxResultSize. This means that Scan RPCs should return at most a single
220 // result back to the client.
221 int cellSize
= (int) (expectedMaxResultSize
/ (numQualifiers
- 1));
222 byte[] cellValue
= Bytes
.createMaxByteArray(cellSize
);
225 List
<Put
> puts
= new ArrayList
<>();
226 for (int row
= 0; row
< ROWS
.length
; row
++) {
227 put
= new Put(ROWS
[row
]);
228 for (int qual
= 0; qual
< QUALIFIERS
.length
; qual
++) {
229 KeyValue kv
= new KeyValue(ROWS
[row
], FAMILY
, QUALIFIERS
[qual
], cellValue
);
236 // Create a scan with the default configuration.
237 Scan scan
= new Scan();
239 ResultScanner scanner
= ht
.getScanner(scan
);
240 assertTrue(scanner
instanceof ClientScanner
);
241 ClientScanner clientScanner
= (ClientScanner
) scanner
;
243 // Call next to issue a single RPC to the server
246 // The scanner should have, at most, a single result in its cache. If there more results exists
247 // in the cache it means that more than the expected max result size was fetched.
248 assertTrue("The cache contains: " + clientScanner
.getCacheSize() + " results",
249 clientScanner
.getCacheSize() <= 1);
253 * Scan on not existing table should throw the exception with correct message
256 public void testScannerForNotExistingTable() {
257 String
[] tableNames
= {"A", "Z", "A:A", "Z:Z"};
258 for(String tableName
: tableNames
) {
260 Table table
= TEST_UTIL
.getConnection().getTable(TableName
.valueOf(tableName
));
261 testSmallScan(table
, true, 1, 5);
262 fail("TableNotFoundException was not thrown");
263 } catch (TableNotFoundException e
) {
264 // We expect that the message for TableNotFoundException would have only the table name only
265 // Otherwise that would mean that localeRegionInMeta doesn't work properly
266 assertEquals(e
.getMessage(), tableName
);
267 } catch (Exception e
) {
268 fail("Unexpected exception " + e
.getMessage());
274 public void testSmallScan() throws Exception
{
275 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
278 byte[][] ROWS
= HTestConst
.makeNAscii(ROW
, numRows
);
280 int numQualifiers
= 10;
281 byte[][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, numQualifiers
);
283 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILY
);
286 List
<Put
> puts
= new ArrayList
<>();
287 for (int row
= 0; row
< ROWS
.length
; row
++) {
288 put
= new Put(ROWS
[row
]);
289 for (int qual
= 0; qual
< QUALIFIERS
.length
; qual
++) {
290 KeyValue kv
= new KeyValue(ROWS
[row
], FAMILY
, QUALIFIERS
[qual
], VALUE
);
297 int expectedRows
= numRows
;
298 int expectedCols
= numRows
* numQualifiers
;
300 // Test normal and reversed
301 testSmallScan(ht
, true, expectedRows
, expectedCols
);
302 testSmallScan(ht
, false, expectedRows
, expectedCols
);
306 * Run through a variety of test configurations with a small scan
313 private void testSmallScan(Table table
, boolean reversed
, int rows
, int columns
) throws Exception
{
314 Scan baseScan
= new Scan();
315 baseScan
.setReversed(reversed
);
316 baseScan
.setSmall(true);
318 Scan scan
= new Scan(baseScan
);
319 verifyExpectedCounts(table
, scan
, rows
, columns
);
321 scan
= new Scan(baseScan
);
322 scan
.setMaxResultSize(1);
323 verifyExpectedCounts(table
, scan
, rows
, columns
);
325 scan
= new Scan(baseScan
);
326 scan
.setMaxResultSize(1);
327 scan
.setCaching(Integer
.MAX_VALUE
);
328 verifyExpectedCounts(table
, scan
, rows
, columns
);
331 private void verifyExpectedCounts(Table table
, Scan scan
, int expectedRowCount
,
332 int expectedCellCount
) throws Exception
{
333 ResultScanner scanner
= table
.getScanner(scan
);
338 while ((r
= scanner
.next()) != null) {
340 cellCount
+= r
.rawCells().length
;
343 assertTrue("Expected row count: " + expectedRowCount
+ " Actual row count: " + rowCount
,
344 expectedRowCount
== rowCount
);
345 assertTrue("Expected cell count: " + expectedCellCount
+ " Actual cell count: " + cellCount
,
346 expectedCellCount
== cellCount
);
351 * Test from client side for get with maxResultPerCF set
356 public void testGetMaxResults() throws Exception
{
357 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
358 byte [][] FAMILIES
= HTestConst
.makeNAscii(FAMILY
, 3);
359 byte [][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, 20);
361 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILIES
);
366 boolean toLog
= true;
367 List
<Cell
> kvListExp
;
369 kvListExp
= new ArrayList
<>();
370 // Insert one CF for row[0]
372 for (int i
=0; i
< 10; i
++) {
373 KeyValue kv
= new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[i
], 1, VALUE
);
380 result
= ht
.get(get
);
381 verifyResult(result
, kvListExp
, toLog
, "Testing without setting maxResults");
384 get
.setMaxResultsPerColumnFamily(2);
385 result
= ht
.get(get
);
386 kvListExp
= new ArrayList
<>();
387 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[0], 1, VALUE
));
388 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[1], 1, VALUE
));
389 verifyResult(result
, kvListExp
, toLog
, "Testing basic setMaxResults");
391 // Filters: ColumnRangeFilter
393 get
.setMaxResultsPerColumnFamily(5);
394 get
.setFilter(new ColumnRangeFilter(QUALIFIERS
[2], true, QUALIFIERS
[5],
396 result
= ht
.get(get
);
397 kvListExp
= new ArrayList
<>();
398 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[2], 1, VALUE
));
399 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[3], 1, VALUE
));
400 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[4], 1, VALUE
));
401 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[5], 1, VALUE
));
402 verifyResult(result
, kvListExp
, toLog
, "Testing single CF with CRF");
404 // Insert two more CF for row[0]
405 // 20 columns for CF2, 10 columns for CF1
407 for (int i
=0; i
< QUALIFIERS
.length
; i
++) {
408 KeyValue kv
= new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[i
], 1, VALUE
);
414 for (int i
=0; i
< 10; i
++) {
415 KeyValue kv
= new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[i
], 1, VALUE
);
421 get
.setMaxResultsPerColumnFamily(12);
422 get
.addFamily(FAMILIES
[1]);
423 get
.addFamily(FAMILIES
[2]);
424 result
= ht
.get(get
);
425 kvListExp
= new ArrayList
<>();
426 //Exp: CF1:q0, ..., q9, CF2: q0, q1, q10, q11, ..., q19
427 for (int i
=0; i
< 10; i
++) {
428 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[i
], 1, VALUE
));
430 for (int i
=0; i
< 2; i
++) {
431 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[i
], 1, VALUE
));
433 for (int i
=10; i
< 20; i
++) {
434 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[i
], 1, VALUE
));
436 verifyResult(result
, kvListExp
, toLog
, "Testing multiple CFs");
438 // Filters: ColumnRangeFilter and ColumnPrefixFilter
440 get
.setMaxResultsPerColumnFamily(3);
441 get
.setFilter(new ColumnRangeFilter(QUALIFIERS
[2], true, null, true));
442 result
= ht
.get(get
);
443 kvListExp
= new ArrayList
<>();
444 for (int i
=2; i
< 5; i
++) {
445 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[i
], 1, VALUE
));
447 for (int i
=2; i
< 5; i
++) {
448 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[i
], 1, VALUE
));
450 for (int i
=2; i
< 5; i
++) {
451 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[i
], 1, VALUE
));
453 verifyResult(result
, kvListExp
, toLog
, "Testing multiple CFs + CRF");
456 get
.setMaxResultsPerColumnFamily(7);
457 get
.setFilter(new ColumnPrefixFilter(QUALIFIERS
[1]));
458 result
= ht
.get(get
);
459 kvListExp
= new ArrayList
<>();
460 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[1], 1, VALUE
));
461 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[1], 1, VALUE
));
462 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[1], 1, VALUE
));
463 for (int i
=10; i
< 16; i
++) {
464 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[i
], 1, VALUE
));
466 verifyResult(result
, kvListExp
, toLog
, "Testing multiple CFs + PFF");
471 * Test from client side for scan with maxResultPerCF set
476 public void testScanMaxResults() throws Exception
{
477 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
478 byte [][] ROWS
= HTestConst
.makeNAscii(ROW
, 2);
479 byte [][] FAMILIES
= HTestConst
.makeNAscii(FAMILY
, 3);
480 byte [][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, 10);
482 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILIES
);
487 boolean toLog
= true;
488 List
<Cell
> kvListExp
, kvListScan
;
490 kvListExp
= new ArrayList
<>();
492 for (int r
=0; r
< ROWS
.length
; r
++) {
493 put
= new Put(ROWS
[r
]);
494 for (int c
=0; c
< FAMILIES
.length
; c
++) {
495 for (int q
=0; q
< QUALIFIERS
.length
; q
++) {
496 KeyValue kv
= new KeyValue(ROWS
[r
], FAMILIES
[c
], QUALIFIERS
[q
], 1, VALUE
);
507 scan
.setMaxResultsPerColumnFamily(4);
508 ResultScanner scanner
= ht
.getScanner(scan
);
509 kvListScan
= new ArrayList
<>();
510 while ((result
= scanner
.next()) != null) {
511 for (Cell kv
: result
.listCells()) {
515 result
= Result
.create(kvListScan
);
516 verifyResult(result
, kvListExp
, toLog
, "Testing scan with maxResults");
521 * Test from client side for get with rowOffset
526 public void testGetRowOffset() throws Exception
{
527 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
528 byte [][] FAMILIES
= HTestConst
.makeNAscii(FAMILY
, 3);
529 byte [][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, 20);
531 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILIES
);
536 boolean toLog
= true;
537 List
<Cell
> kvListExp
;
539 // Insert one CF for row
540 kvListExp
= new ArrayList
<>();
542 for (int i
=0; i
< 10; i
++) {
543 KeyValue kv
= new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[i
], 1, VALUE
);
545 // skipping first two kvs
551 //setting offset to 2
553 get
.setRowOffsetPerColumnFamily(2);
554 result
= ht
.get(get
);
555 verifyResult(result
, kvListExp
, toLog
, "Testing basic setRowOffset");
557 //setting offset to 20
559 get
.setRowOffsetPerColumnFamily(20);
560 result
= ht
.get(get
);
561 kvListExp
= new ArrayList
<>();
562 verifyResult(result
, kvListExp
, toLog
, "Testing offset > #kvs");
564 //offset + maxResultPerCF
566 get
.setRowOffsetPerColumnFamily(4);
567 get
.setMaxResultsPerColumnFamily(5);
568 result
= ht
.get(get
);
569 kvListExp
= new ArrayList
<>();
570 for (int i
=4; i
< 9; i
++) {
571 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[i
], 1, VALUE
));
573 verifyResult(result
, kvListExp
, toLog
,
574 "Testing offset + setMaxResultsPerCF");
576 // Filters: ColumnRangeFilter
578 get
.setRowOffsetPerColumnFamily(1);
579 get
.setFilter(new ColumnRangeFilter(QUALIFIERS
[2], true, QUALIFIERS
[5],
581 result
= ht
.get(get
);
582 kvListExp
= new ArrayList
<>();
583 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[3], 1, VALUE
));
584 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[4], 1, VALUE
));
585 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[0], QUALIFIERS
[5], 1, VALUE
));
586 verifyResult(result
, kvListExp
, toLog
, "Testing offset with CRF");
588 // Insert into two more CFs for row
589 // 10 columns for CF2, 10 columns for CF1
590 for(int j
=2; j
> 0; j
--) {
592 for (int i
=0; i
< 10; i
++) {
593 KeyValue kv
= new KeyValue(ROW
, FAMILIES
[j
], QUALIFIERS
[i
], 1, VALUE
);
600 get
.setRowOffsetPerColumnFamily(4);
601 get
.setMaxResultsPerColumnFamily(2);
602 get
.addFamily(FAMILIES
[1]);
603 get
.addFamily(FAMILIES
[2]);
604 result
= ht
.get(get
);
605 kvListExp
= new ArrayList
<>();
606 //Exp: CF1:q4, q5, CF2: q4, q5
607 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[4], 1, VALUE
));
608 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[1], QUALIFIERS
[5], 1, VALUE
));
609 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[4], 1, VALUE
));
610 kvListExp
.add(new KeyValue(ROW
, FAMILIES
[2], QUALIFIERS
[5], 1, VALUE
));
611 verifyResult(result
, kvListExp
, toLog
,
612 "Testing offset + multiple CFs + maxResults");
616 public void testScanRawDeleteFamilyVersion() throws Exception
{
617 TableName tableName
= TableName
.valueOf(name
.getMethodName());
618 TEST_UTIL
.createTable(tableName
, FAMILY
);
619 Configuration conf
= new Configuration(TEST_UTIL
.getConfiguration());
620 conf
.set(RPC_CODEC_CONF_KEY
, "");
621 conf
.set(DEFAULT_CODEC_CLASS
, "");
622 try (Connection connection
= ConnectionFactory
.createConnection(conf
);
623 Table table
= connection
.getTable(tableName
)) {
624 Delete delete
= new Delete(ROW
);
625 delete
.addFamilyVersion(FAMILY
, 0L);
626 table
.delete(delete
);
627 Scan scan
= new Scan(ROW
).setRaw(true);
628 ResultScanner scanner
= table
.getScanner(scan
);
630 while (scanner
.next() != null) {
633 assertEquals(1, count
);
635 TEST_UTIL
.deleteTable(tableName
);
640 * Test from client side for scan while the region is reopened
641 * on the same region server.
646 public void testScanOnReopenedRegion() throws Exception
{
647 final TableName tableName
= TableName
.valueOf(name
.getMethodName());
648 byte [][] QUALIFIERS
= HTestConst
.makeNAscii(QUALIFIER
, 2);
650 Table ht
= TEST_UTIL
.createTable(tableName
, FAMILY
);
655 ResultScanner scanner
;
656 boolean toLog
= false;
657 List
<Cell
> kvListExp
;
659 // table: row, family, c0:0, c1:1
661 for (int i
=0; i
< QUALIFIERS
.length
; i
++) {
662 KeyValue kv
= new KeyValue(ROW
, FAMILY
, QUALIFIERS
[i
], i
, VALUE
);
667 scan
= new Scan().withStartRow(ROW
);
668 scanner
= ht
.getScanner(scan
);
672 try (RegionLocator locator
= TEST_UTIL
.getConnection().getRegionLocator(tableName
)) {
673 loc
= locator
.getRegionLocation(ROW
);
675 HRegionInfo hri
= loc
.getRegionInfo();
676 MiniHBaseCluster cluster
= TEST_UTIL
.getMiniHBaseCluster();
677 byte[] regionName
= hri
.getRegionName();
678 int i
= cluster
.getServerWith(regionName
);
679 HRegionServer rs
= cluster
.getRegionServer(i
);
680 LOG
.info("Unassigning " + hri
);
681 TEST_UTIL
.getAdmin().unassign(hri
.getRegionName(), true);
682 long startTime
= EnvironmentEdgeManager
.currentTime();
683 long timeOut
= 10000;
684 boolean offline
= false;
686 if (rs
.getOnlineRegion(regionName
) == null) {
690 assertTrue("Timed out in closing the testing region",
691 EnvironmentEdgeManager
.currentTime() < startTime
+ timeOut
);
694 LOG
.info("Assigning " + hri
);
695 TEST_UTIL
.getAdmin().assign(hri
.getRegionName());
696 startTime
= EnvironmentEdgeManager
.currentTime();
698 rs
= cluster
.getRegionServer(cluster
.getServerWith(regionName
));
699 if (rs
!= null && rs
.getOnlineRegion(regionName
) != null) {
703 assertTrue("Timed out in open the testing region",
704 EnvironmentEdgeManager
.currentTime() < startTime
+ timeOut
);
706 assertFalse(offline
);
709 kvListExp
= new ArrayList
<>();
710 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[0], 0, VALUE
));
711 kvListExp
.add(new KeyValue(ROW
, FAMILY
, QUALIFIERS
[1], 1, VALUE
));
712 result
= scanner
.next();
713 verifyResult(result
, kvListExp
, toLog
, "Testing scan on re-opened region");
717 public void testAsyncScannerWithSmallData() throws Exception
{
718 testAsyncScanner(TableName
.valueOf(name
.getMethodName()),
727 public void testAsyncScannerWithManyRows() throws Exception
{
728 testAsyncScanner(TableName
.valueOf(name
.getMethodName()),
737 public void testAsyncScannerWithoutCaching() throws Exception
{
738 testAsyncScanner(TableName
.valueOf(name
.getMethodName()),
745 TimeUnit
.MILLISECONDS
.sleep(500);
746 } catch (InterruptedException ex
) {
751 private void testAsyncScanner(TableName table
, int rowNumber
, int familyNumber
,
752 int qualifierNumber
, int caching
, Consumer
<Boolean
> listener
) throws Exception
{
753 assert rowNumber
> 0;
754 assert familyNumber
> 0;
755 assert qualifierNumber
> 0;
756 byte[] row
= Bytes
.toBytes("r");
757 byte[] family
= Bytes
.toBytes("f");
758 byte[] qualifier
= Bytes
.toBytes("q");
759 byte[][] rows
= makeNAsciiWithZeroPrefix(row
, rowNumber
);
760 byte[][] families
= makeNAsciiWithZeroPrefix(family
, familyNumber
);
761 byte[][] qualifiers
= makeNAsciiWithZeroPrefix(qualifier
, qualifierNumber
);
763 Table ht
= TEST_UTIL
.createTable(table
, families
);
765 boolean toLog
= true;
766 List
<Cell
> kvListExp
= new ArrayList
<>();
768 List
<Put
> puts
= new ArrayList
<>();
769 for (byte[] r
: rows
) {
770 Put put
= new Put(r
);
771 for (byte[] f
: families
) {
772 for (byte[] q
: qualifiers
) {
773 KeyValue kv
= new KeyValue(r
, f
, q
, 1, VALUE
);
779 if (puts
.size() > 1000) {
784 if (!puts
.isEmpty()) {
789 Scan scan
= new Scan();
790 scan
.setAsyncPrefetch(true);
792 scan
.setCaching(caching
);
794 try (ResultScanner scanner
= ht
.getScanner(scan
)) {
795 assertTrue("Not instance of async scanner",scanner
instanceof ClientAsyncPrefetchScanner
);
796 ((ClientAsyncPrefetchScanner
) scanner
).setPrefetchListener(listener
);
797 List
<Cell
> kvListScan
= new ArrayList
<>();
799 boolean first
= true;
801 while ((result
= scanner
.next()) != null) {
803 // waiting for cache. see HBASE-17376
805 TimeUnit
.SECONDS
.sleep(1);
808 for (Cell kv
: result
.listCells()) {
812 assertEquals(rowNumber
, actualRows
);
813 // These cells may have different rows but it is ok. The Result#getRow
814 // isn't used in the verifyResult()
815 result
= Result
.create(kvListScan
);
816 verifyResult(result
, kvListExp
, toLog
, "Testing async scan");
819 TEST_UTIL
.deleteTable(table
);
822 private static byte[][] makeNAsciiWithZeroPrefix(byte[] base
, int n
) {
823 int maxLength
= Integer
.toString(n
).length();
824 byte [][] ret
= new byte[n
][];
825 for (int i
= 0; i
< n
; i
++) {
826 int length
= Integer
.toString(i
).length();
827 StringBuilder buf
= new StringBuilder(Integer
.toString(i
));
828 IntStream
.range(0, maxLength
- length
).forEach(v
-> buf
.insert(0, "0"));
829 byte[] tail
= Bytes
.toBytes(buf
.toString());
830 ret
[i
] = Bytes
.add(base
, tail
);
835 static void verifyResult(Result result
, List
<Cell
> expKvList
, boolean toLog
,
839 LOG
.info("Expected count: " + expKvList
.size());
840 LOG
.info("Actual count: " + result
.size());
841 if (expKvList
.isEmpty())
845 for (Cell kv
: result
.rawCells()) {
846 if (i
>= expKvList
.size()) {
847 break; // we will check the size later
850 Cell kvExp
= expKvList
.get(i
++);
852 LOG
.info("get kv is: " + kv
.toString());
853 LOG
.info("exp kv is: " + kvExp
.toString());
855 assertTrue("Not equal", kvExp
.equals(kv
));
858 assertEquals(expKvList
.size(), result
.size());
862 public void testReadExpiredDataForRawScan() throws IOException
{
863 TableName tableName
= TableName
.valueOf(name
.getMethodName());
864 long ts
= System
.currentTimeMillis() - 10000;
865 byte[] value
= Bytes
.toBytes("expired");
866 try (Table table
= TEST_UTIL
.createTable(tableName
, FAMILY
)) {
867 table
.put(new Put(ROW
).addColumn(FAMILY
, QUALIFIER
, ts
, value
));
868 assertArrayEquals(value
, table
.get(new Get(ROW
)).getValue(FAMILY
, QUALIFIER
));
869 TEST_UTIL
.getAdmin().modifyColumnFamily(tableName
,
870 new HColumnDescriptor(FAMILY
).setTimeToLive(5));
871 try (ResultScanner scanner
= table
.getScanner(FAMILY
)) {
872 assertNull(scanner
.next());
874 try (ResultScanner scanner
= table
.getScanner(new Scan().setRaw(true))) {
875 assertArrayEquals(value
, scanner
.next().getValue(FAMILY
, QUALIFIER
));
876 assertNull(scanner
.next());
882 public void testScanWithColumnsAndFilterAndVersion() throws IOException
{
883 TableName tableName
= TableName
.valueOf(name
.getMethodName());
884 try (Table table
= TEST_UTIL
.createTable(tableName
, FAMILY
, 4)) {
885 for (int i
= 0; i
< 4; i
++) {
886 Put put
= new Put(ROW
);
887 put
.addColumn(FAMILY
, QUALIFIER
, VALUE
);
891 Scan scan
= new Scan();
892 scan
.addColumn(FAMILY
, QUALIFIER
);
893 scan
.setFilter(new QualifierFilter(CompareOperator
.EQUAL
, new BinaryComparator(QUALIFIER
)));
894 scan
.readVersions(3);
896 try (ResultScanner scanner
= table
.getScanner(scan
)) {
897 Result result
= scanner
.next();
898 assertEquals(3, result
.size());
904 public void testScanWithSameStartRowStopRow() throws IOException
{
905 TableName tableName
= TableName
.valueOf(name
.getMethodName());
906 try (Table table
= TEST_UTIL
.createTable(tableName
, FAMILY
)) {
907 table
.put(new Put(ROW
).addColumn(FAMILY
, QUALIFIER
, VALUE
));
909 Scan scan
= new Scan().withStartRow(ROW
).withStopRow(ROW
);
910 try (ResultScanner scanner
= table
.getScanner(scan
)) {
911 assertNull(scanner
.next());
914 scan
= new Scan().withStartRow(ROW
, true).withStopRow(ROW
, true);
915 try (ResultScanner scanner
= table
.getScanner(scan
)) {
916 Result result
= scanner
.next();
917 assertNotNull(result
);
918 assertArrayEquals(ROW
, result
.getRow());
919 assertArrayEquals(VALUE
, result
.getValue(FAMILY
, QUALIFIER
));
920 assertNull(scanner
.next());
923 scan
= new Scan().withStartRow(ROW
, true).withStopRow(ROW
, false);
924 try (ResultScanner scanner
= table
.getScanner(scan
)) {
925 assertNull(scanner
.next());
928 scan
= new Scan().withStartRow(ROW
, false).withStopRow(ROW
, false);
929 try (ResultScanner scanner
= table
.getScanner(scan
)) {
930 assertNull(scanner
.next());
933 scan
= new Scan().withStartRow(ROW
, false).withStopRow(ROW
, true);
934 try (ResultScanner scanner
= table
.getScanner(scan
)) {
935 assertNull(scanner
.next());
941 public void testReverseScanWithFlush() throws Exception
{
942 TableName tableName
= TableName
.valueOf(name
.getMethodName());
943 final int BATCH_SIZE
= 10;
944 final int ROWS_TO_INSERT
= 100;
945 final byte[] LARGE_VALUE
= generateHugeValue(128 * 1024);
947 try (Table table
= TEST_UTIL
.createTable(tableName
, FAMILY
);
948 Admin admin
= TEST_UTIL
.getAdmin()) {
949 List
<Put
> putList
= new ArrayList
<>();
950 for (long i
= 0; i
< ROWS_TO_INSERT
; i
++) {
951 Put put
= new Put(Bytes
.toBytes(i
));
952 put
.addColumn(FAMILY
, QUALIFIER
, LARGE_VALUE
);
955 if (putList
.size() >= BATCH_SIZE
) {
957 admin
.flush(tableName
);
962 if (!putList
.isEmpty()) {
964 admin
.flush(tableName
);
968 Scan scan
= new Scan();
969 scan
.setReversed(true);
972 try (ResultScanner results
= table
.getScanner(scan
)) {
973 for (Result result
: results
) {
977 assertEquals("Expected " + ROWS_TO_INSERT
+ " rows in the table but it is " + count
,
978 ROWS_TO_INSERT
, count
);