1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase;
19
20 import static org.junit.Assert.assertArrayEquals;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Set;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.hbase.client.ClientScanner;
36 import org.apache.hadoop.hbase.client.Delete;
37 import org.apache.hadoop.hbase.client.Put;
38 import org.apache.hadoop.hbase.client.Result;
39 import org.apache.hadoop.hbase.client.ResultScanner;
40 import org.apache.hadoop.hbase.client.Scan;
41 import org.apache.hadoop.hbase.client.Table;
42 import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
43 import org.apache.hadoop.hbase.filter.ColumnRangeFilter;
44 import org.apache.hadoop.hbase.filter.Filter;
45 import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
46 import org.apache.hadoop.hbase.filter.FirstKeyValueMatchingQualifiersFilter;
47 import org.apache.hadoop.hbase.filter.RandomRowFilter;
48 import org.apache.hadoop.hbase.testclassification.MediumTests;
49 import org.apache.hadoop.hbase.util.Bytes;
50 import org.apache.hadoop.hbase.util.Pair;
51 import org.junit.AfterClass;
52 import org.junit.BeforeClass;
53 import org.junit.Test;
54 import org.junit.experimental.categories.Category;
55
56
57
58
59
60
61
62
63
64
65
66 @Category(MediumTests.class)
67 public class TestPartialResultsFromClientSide {
68 private static final Log LOG = LogFactory.getLog(TestPartialResultsFromClientSide.class);
69
70 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
71 private final static int MINICLUSTER_SIZE = 5;
72 private static Table TABLE = null;
73
74
75
76
77 private static TableName TABLE_NAME = TableName.valueOf("testTable");
78
79 private static int NUM_ROWS = 5;
80 private static byte[] ROW = Bytes.toBytes("testRow");
81 private static byte[][] ROWS = HTestConst.makeNAscii(ROW, NUM_ROWS);
82
83
84
85
86 private static int NUM_FAMILIES = 10;
87 private static byte[] FAMILY = Bytes.toBytes("testFamily");
88 private static byte[][] FAMILIES = HTestConst.makeNAscii(FAMILY, NUM_FAMILIES);
89
90 private static int NUM_QUALIFIERS = 10;
91 private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
92 private static byte[][] QUALIFIERS = HTestConst.makeNAscii(QUALIFIER, NUM_QUALIFIERS);
93
94 private static int VALUE_SIZE = 1024;
95 private static byte[] VALUE = Bytes.createMaxByteArray(VALUE_SIZE);
96
97 private static int NUM_COLS = NUM_FAMILIES * NUM_QUALIFIERS;
98
99
100
101 private static long CELL_HEAP_SIZE = -1;
102
103 private static long timeout = 10000;
104
105 @BeforeClass
106 public static void setUpBeforeClass() throws Exception {
107 TEST_UTIL.getConfiguration().setLong(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, timeout);
108 TEST_UTIL.startMiniCluster(MINICLUSTER_SIZE);
109 TEST_UTIL.getHBaseAdmin().setBalancerRunning(false, true);
110 TABLE = createTestTable(TABLE_NAME, ROWS, FAMILIES, QUALIFIERS, VALUE);
111 }
112
113 static Table createTestTable(TableName name, byte[][] rows, byte[][] families,
114 byte[][] qualifiers, byte[] cellValue) throws IOException {
115 Table ht = TEST_UTIL.createTable(name, families);
116 List<Put> puts = createPuts(rows, families, qualifiers, cellValue);
117 ht.put(puts);
118
119 return ht;
120 }
121
122 @AfterClass
123 public static void tearDownAfterClass() throws Exception {
124 TEST_UTIL.shutdownMiniCluster();
125 }
126
127
128
129
130
131
132 @Test
133 public void testExpectedValuesOfPartialResults() throws Exception {
134 testExpectedValuesOfPartialResults(false);
135 testExpectedValuesOfPartialResults(true);
136 }
137
138 public void testExpectedValuesOfPartialResults(boolean reversed) throws Exception {
139 Scan partialScan = new Scan();
140 partialScan.setMaxVersions();
141
142
143 partialScan.setMaxResultSize(1);
144 partialScan.setReversed(reversed);
145 ResultScanner partialScanner = TABLE.getScanner(partialScan);
146
147 final int startRow = reversed ? ROWS.length - 1 : 0;
148 final int endRow = reversed ? -1 : ROWS.length;
149 final int loopDelta = reversed ? -1 : 1;
150 String message;
151
152 for (int row = startRow; row != endRow; row = row + loopDelta) {
153 message = "Ensuring the expected keyValues are present for row " + row;
154 List<Cell> expectedKeyValues = createKeyValuesForRow(ROWS[row], FAMILIES, QUALIFIERS, VALUE);
155 Result result = partialScanner.next();
156 assertFalse(result.mayHaveMoreCellsInRow());
157 verifyResult(result, expectedKeyValues, message);
158 }
159
160 partialScanner.close();
161 }
162
163
164
165
166
167 @Test
168 public void testAllowPartialResults() throws Exception {
169 Scan scan = new Scan();
170 scan.setAllowPartialResults(true);
171 scan.setMaxResultSize(1);
172 ResultScanner scanner = TABLE.getScanner(scan);
173 Result result = scanner.next();
174
175 assertTrue(result != null);
176 assertTrue(result.mayHaveMoreCellsInRow());
177 assertTrue(result.rawCells() != null);
178 assertTrue(result.rawCells().length == 1);
179
180 scanner.close();
181
182 scan.setAllowPartialResults(false);
183 scanner = TABLE.getScanner(scan);
184 result = scanner.next();
185
186 assertTrue(result != null);
187 assertTrue(!result.mayHaveMoreCellsInRow());
188 assertTrue(result.rawCells() != null);
189 assertTrue(result.rawCells().length == NUM_COLS);
190
191 scanner.close();
192 }
193
194
195
196
197
198
199
200 @Test
201 public void testEquivalenceOfScanResults() throws Exception {
202 Scan oneShotScan = new Scan();
203 oneShotScan.setMaxResultSize(Long.MAX_VALUE);
204
205 Scan partialScan = new Scan(oneShotScan);
206 partialScan.setMaxResultSize(1);
207
208 testEquivalenceOfScanResults(TABLE, oneShotScan, partialScan);
209 }
210
211 public void testEquivalenceOfScanResults(Table table, Scan scan1, Scan scan2) throws Exception {
212 ResultScanner scanner1 = table.getScanner(scan1);
213 ResultScanner scanner2 = table.getScanner(scan2);
214
215 Result r1 = null;
216 Result r2 = null;
217 int count = 0;
218
219 while ((r1 = scanner1.next()) != null) {
220 r2 = scanner2.next();
221
222 assertTrue(r2 != null);
223 compareResults(r1, r2, "Comparing result #" + count);
224 count++;
225 }
226
227 r2 = scanner2.next();
228 assertTrue("r2: " + r2 + " Should be null", r2 == null);
229
230 scanner1.close();
231 scanner2.close();
232 }
233
234
235
236
237
238 @Test
239 public void testOrderingOfCellsInPartialResults() throws Exception {
240 Scan scan = new Scan();
241
242 for (int col = 1; col <= NUM_COLS; col++) {
243 scan.setMaxResultSize(getResultSizeForNumberOfCells(col));
244 testOrderingOfCellsInPartialResults(scan);
245
246
247 scan.setReversed(true);
248 testOrderingOfCellsInPartialResults(scan);
249 }
250 }
251
252 public void testOrderingOfCellsInPartialResults(final Scan basePartialScan) throws Exception {
253
254
255
256 Scan partialScan = new Scan(basePartialScan);
257 partialScan.setAllowPartialResults(true);
258 ResultScanner partialScanner = TABLE.getScanner(partialScan);
259
260
261 Scan oneShotScan = new Scan(basePartialScan);
262 oneShotScan.setMaxResultSize(Long.MAX_VALUE);
263 oneShotScan.setCaching(ROWS.length);
264 ResultScanner oneShotScanner = TABLE.getScanner(oneShotScan);
265
266 Result oneShotResult = oneShotScanner.next();
267 Result partialResult = null;
268 int iterationCount = 0;
269
270 while (oneShotResult != null && oneShotResult.rawCells() != null) {
271 List<Cell> aggregatePartialCells = new ArrayList<Cell>();
272 do {
273 partialResult = partialScanner.next();
274 assertTrue("Partial Result is null. iteration: " + iterationCount, partialResult != null);
275 assertTrue("Partial cells are null. iteration: " + iterationCount,
276 partialResult.rawCells() != null);
277
278 for (Cell c : partialResult.rawCells()) {
279 aggregatePartialCells.add(c);
280 }
281 } while (partialResult.mayHaveMoreCellsInRow());
282
283 assertTrue("Number of cells differs. iteration: " + iterationCount,
284 oneShotResult.rawCells().length == aggregatePartialCells.size());
285 final Cell[] oneShotCells = oneShotResult.rawCells();
286 for (int cell = 0; cell < oneShotCells.length; cell++) {
287 Cell oneShotCell = oneShotCells[cell];
288 Cell partialCell = aggregatePartialCells.get(cell);
289
290 assertTrue("One shot cell was null", oneShotCell != null);
291 assertTrue("Partial cell was null", partialCell != null);
292 assertTrue("Cell differs. oneShotCell:" + oneShotCell + " partialCell:" + partialCell,
293 oneShotCell.equals(partialCell));
294 }
295
296 oneShotResult = oneShotScanner.next();
297 iterationCount++;
298 }
299
300 assertTrue(partialScanner.next() == null);
301
302 partialScanner.close();
303 oneShotScanner.close();
304 }
305
306
307
308
309
310
311 @Test
312 public void testExpectedNumberOfCellsPerPartialResult() throws Exception {
313 Scan scan = new Scan();
314 testExpectedNumberOfCellsPerPartialResult(scan);
315
316 scan.setReversed(true);
317 testExpectedNumberOfCellsPerPartialResult(scan);
318 }
319
320 public void testExpectedNumberOfCellsPerPartialResult(Scan baseScan) throws Exception {
321 for (int expectedCells = 1; expectedCells <= NUM_COLS; expectedCells++) {
322 testExpectedNumberOfCellsPerPartialResult(baseScan, expectedCells);
323 }
324 }
325
326 public void testExpectedNumberOfCellsPerPartialResult(Scan baseScan, int expectedNumberOfCells)
327 throws Exception {
328
329 if (LOG.isInfoEnabled()) LOG.info("groupSize:" + expectedNumberOfCells);
330
331
332
333
334
335 Scan scan = new Scan(baseScan);
336 scan.setAllowPartialResults(true);
337 scan.setMaxResultSize(getResultSizeForNumberOfCells(expectedNumberOfCells));
338
339 ResultScanner scanner = TABLE.getScanner(scan);
340 Result result = null;
341 byte[] prevRow = null;
342 while ((result = scanner.next()) != null) {
343 assertTrue(result.rawCells() != null);
344
345
346
347
348
349 assertTrue(
350 "Result's cell count differed from expected number. result: " + result,
351 result.rawCells().length == expectedNumberOfCells || !result.mayHaveMoreCellsInRow()
352 || !Bytes.equals(prevRow, result.getRow()));
353 prevRow = result.getRow();
354 }
355
356 scanner.close();
357 }
358
359
360
361
362
363
364
365 private long getCellHeapSize() throws Exception {
366 if (CELL_HEAP_SIZE == -1) {
367
368 Scan scan = new Scan();
369 scan.setMaxResultSize(2);
370 scan.setAllowPartialResults(true);
371 ResultScanner scanner = TABLE.getScanner(scan);
372
373 Result result = scanner.next();
374
375 assertTrue(result != null);
376 assertTrue(result.rawCells() != null);
377 assertTrue(result.rawCells().length == 1);
378
379
380
381
382 CELL_HEAP_SIZE = CellUtil.estimatedHeapSizeOf(result.rawCells()[0]);
383 if (LOG.isInfoEnabled()) LOG.info("Cell heap size: " + CELL_HEAP_SIZE);
384 scanner.close();
385 }
386
387 return CELL_HEAP_SIZE;
388 }
389
390
391
392
393
394
395
396 private long getResultSizeForNumberOfCells(int numberOfCells) throws Exception {
397 return getCellHeapSize() * numberOfCells;
398 }
399
400
401
402
403 @Test
404 public void testPartialResultsAndBatch() throws Exception {
405 for (int batch = 1; batch <= NUM_COLS / 4; batch++) {
406 for (int cellsPerPartial = 1; cellsPerPartial <= NUM_COLS / 4; cellsPerPartial++) {
407 testPartialResultsAndBatch(batch, cellsPerPartial);
408 }
409 }
410 }
411
412 public void testPartialResultsAndBatch(final int batch, final int cellsPerPartialResult)
413 throws Exception {
414 if (LOG.isInfoEnabled()) {
415 LOG.info("batch: " + batch + " cellsPerPartialResult: " + cellsPerPartialResult);
416 }
417
418 Scan scan = new Scan();
419 scan.setMaxResultSize(getResultSizeForNumberOfCells(cellsPerPartialResult));
420 scan.setBatch(batch);
421 ResultScanner scanner = TABLE.getScanner(scan);
422 Result result = scanner.next();
423 int repCount = 0;
424
425 while ((result = scanner.next()) != null) {
426 assertTrue(result.rawCells() != null);
427
428 if (result.mayHaveMoreCellsInRow()) {
429 final String error =
430 "Cells:" + result.rawCells().length + " Batch size:" + batch
431 + " cellsPerPartialResult:" + cellsPerPartialResult + " rep:" + repCount;
432 assertTrue(error, result.rawCells().length == batch);
433 } else {
434 assertTrue(result.rawCells().length <= batch);
435 }
436 repCount++;
437 }
438
439 scanner.close();
440 }
441
442
443
444
445
446 @Test
447 public void testPartialResultsReassembly() throws Exception {
448 Scan scan = new Scan();
449 testPartialResultsReassembly(scan);
450 scan.setReversed(true);
451 testPartialResultsReassembly(scan);
452 }
453
454 public void testPartialResultsReassembly(Scan scanBase) throws Exception {
455 Scan partialScan = new Scan(scanBase);
456 partialScan.setMaxResultSize(1);
457 partialScan.setAllowPartialResults(true);
458 ResultScanner partialScanner = TABLE.getScanner(partialScan);
459
460 Scan oneShotScan = new Scan(scanBase);
461 oneShotScan.setMaxResultSize(Long.MAX_VALUE);
462 ResultScanner oneShotScanner = TABLE.getScanner(oneShotScan);
463
464 ArrayList<Result> partials = new ArrayList<>();
465 for (int i = 0; i < NUM_ROWS; i++) {
466 Result partialResult = null;
467 Result completeResult = null;
468 Result oneShotResult = null;
469 partials.clear();
470
471 do {
472 partialResult = partialScanner.next();
473 partials.add(partialResult);
474 } while (partialResult != null && partialResult.mayHaveMoreCellsInRow());
475
476 completeResult = Result.createCompleteResult(partials);
477 oneShotResult = oneShotScanner.next();
478
479 compareResults(completeResult, oneShotResult, null);
480 }
481
482 assertTrue(oneShotScanner.next() == null);
483 assertTrue(partialScanner.next() == null);
484
485 oneShotScanner.close();
486 partialScanner.close();
487 }
488
489
490
491
492
493 @Test
494 public void testExceptionThrownOnMismatchedPartialResults() throws IOException {
495 assertTrue(NUM_ROWS >= 2);
496
497 ArrayList<Result> partials = new ArrayList<>();
498 Scan scan = new Scan();
499 scan.setMaxResultSize(Long.MAX_VALUE);
500 ResultScanner scanner = TABLE.getScanner(scan);
501 Result r1 = scanner.next();
502 partials.add(r1);
503 Result r2 = scanner.next();
504 partials.add(r2);
505
506 assertFalse(Bytes.equals(r1.getRow(), r2.getRow()));
507
508 try {
509 Result.createCompleteResult(partials);
510 fail("r1 and r2 are from different rows. It should not be possible to combine them into"
511 + " a single result");
512 } catch (IOException e) {
513 }
514
515 scanner.close();
516 }
517
518
519
520
521
522
523 @Test
524 public void testNoPartialResultsWhenRowFilterPresent() throws Exception {
525 Scan scan = new Scan();
526 scan.setMaxResultSize(1);
527 scan.setAllowPartialResults(true);
528
529
530 scan.setFilter(new RandomRowFilter(1.0f));
531 ResultScanner scanner = TABLE.getScanner(scan);
532
533 Result r = null;
534 while ((r = scanner.next()) != null) {
535 assertFalse(r.mayHaveMoreCellsInRow());
536 }
537
538 scanner.close();
539 }
540
541
542
543
544
545
546
547
548 @Test
549 public void testPartialResultsAndCaching() throws Exception {
550 for (int caching = 1; caching <= NUM_ROWS; caching++) {
551 for (int maxResultRows = 0; maxResultRows <= NUM_ROWS; maxResultRows++) {
552 testPartialResultsAndCaching(maxResultRows, caching);
553 }
554 }
555 }
556
557
558
559
560
561
562 public void testPartialResultsAndCaching(int resultSizeRowLimit, int cachingRowLimit)
563 throws Exception {
564 Scan scan = new Scan();
565 scan.setAllowPartialResults(true);
566
567
568
569
570
571 int cellOffset = NUM_COLS / 3;
572 long maxResultSize = getResultSizeForNumberOfCells(resultSizeRowLimit * NUM_COLS + cellOffset);
573 scan.setMaxResultSize(maxResultSize);
574 scan.setCaching(cachingRowLimit);
575
576 ResultScanner scanner = TABLE.getScanner(scan);
577 ClientScanner clientScanner = (ClientScanner) scanner;
578 Result r = null;
579
580
581
582
583 boolean expectToSeePartialResults = resultSizeRowLimit < cachingRowLimit;
584 while ((r = clientScanner.next()) != null) {
585 assertTrue(!r.mayHaveMoreCellsInRow() || expectToSeePartialResults);
586 }
587
588 scanner.close();
589 }
590
591
592
593
594
595
596
597
598
599
600 static ArrayList<Put> createPuts(byte[][] rows, byte[][] families, byte[][] qualifiers,
601 byte[] value) throws IOException {
602 Put put;
603 ArrayList<Put> puts = new ArrayList<>();
604
605 for (int row = 0; row < rows.length; row++) {
606 put = new Put(rows[row]);
607 for (int fam = 0; fam < families.length; fam++) {
608 for (int qual = 0; qual < qualifiers.length; qual++) {
609 KeyValue kv = new KeyValue(rows[row], families[fam], qualifiers[qual], qual, value);
610 put.add(kv);
611 }
612 }
613 puts.add(put);
614 }
615
616 return puts;
617 }
618
619
620
621
622
623
624
625
626
627
628 static ArrayList<Cell> createKeyValuesForRow(byte[] row, byte[][] families, byte[][] qualifiers,
629 byte[] value) {
630 ArrayList<Cell> outList = new ArrayList<>();
631 for (int fam = 0; fam < families.length; fam++) {
632 for (int qual = 0; qual < qualifiers.length; qual++) {
633 outList.add(new KeyValue(row, families[fam], qualifiers[qual], qual, value));
634 }
635 }
636 return outList;
637 }
638
639
640
641
642
643
644
645 static void verifyResult(Result result, List<Cell> expKvList, String msg) {
646 if (LOG.isInfoEnabled()) {
647 LOG.info(msg);
648 LOG.info("Expected count: " + expKvList.size());
649 LOG.info("Actual count: " + result.size());
650 }
651
652 if (expKvList.size() == 0) return;
653
654 int i = 0;
655 for (Cell kv : result.rawCells()) {
656 if (i >= expKvList.size()) {
657 break;
658 }
659
660 Cell kvExp = expKvList.get(i++);
661 assertTrue("Not equal. get kv: " + kv.toString() + " exp kv: " + kvExp.toString(),
662 kvExp.equals(kv));
663 }
664
665 assertEquals(expKvList.size(), result.size());
666 }
667
668
669
670
671
672
673
674 static void compareResults(Result r1, Result r2, final String message) {
675 if (LOG.isInfoEnabled()) {
676 if (message != null) LOG.info(message);
677 LOG.info("r1: " + r1);
678 LOG.info("r2: " + r2);
679 }
680
681 final String failureMessage = "Results r1:" + r1 + " \nr2:" + r2 + " are not equivalent";
682 if (r1 == null && r2 == null) fail(failureMessage);
683 else if (r1 == null || r2 == null) fail(failureMessage);
684
685 try {
686 Result.compareResults(r1, r2);
687 } catch (Exception e) {
688 fail(failureMessage);
689 }
690 }
691
692 @Test
693 public void testReadPointAndPartialResults() throws Exception {
694 TableName testName = TableName.valueOf("testReadPointAndPartialResults");
695 int numRows = 5;
696 int numFamilies = 5;
697 int numQualifiers = 5;
698 byte[][] rows = HTestConst.makeNAscii(Bytes.toBytes("testRow"), numRows);
699 byte[][] families = HTestConst.makeNAscii(Bytes.toBytes("testFamily"), numFamilies);
700 byte[][] qualifiers = HTestConst.makeNAscii(Bytes.toBytes("testQualifier"), numQualifiers);
701 byte[] value = Bytes.createMaxByteArray(100);
702
703 Table tmpTable = createTestTable(testName, rows, families, qualifiers, value);
704
705 ResultScanner scanner =
706 tmpTable.getScanner(new Scan().setMaxResultSize(1).setAllowPartialResults(true));
707
708
709
710 int scannerCount = scanner.next().rawCells().length;
711 Delete delete1 = new Delete(rows[0]);
712 delete1.addColumn(families[0], qualifiers[0], 0);
713 tmpTable.delete(delete1);
714
715 Delete delete2 = new Delete(rows[1]);
716 delete2.addColumn(families[1], qualifiers[1], 1);
717 tmpTable.delete(delete2);
718
719
720 scannerCount += countCellsFromScanner(scanner);
721 int expectedCount = numRows * numFamilies * numQualifiers;
722 assertTrue("scannerCount: " + scannerCount + " expectedCount: " + expectedCount,
723 scannerCount == expectedCount);
724
725
726 scanner = tmpTable.getScanner(new Scan().setMaxResultSize(1).setAllowPartialResults(true));
727 scannerCount = countCellsFromScanner(scanner);
728 expectedCount = numRows * numFamilies * numQualifiers - 2;
729 assertTrue("scannerCount: " + scannerCount + " expectedCount: " + expectedCount,
730 scannerCount == expectedCount);
731
732 scanner = tmpTable.getScanner(new Scan().setMaxResultSize(1).setAllowPartialResults(true));
733 scannerCount = scanner.next().rawCells().length;
734
735 Put put1 = new Put(rows[0]);
736 put1.add(new KeyValue(rows[0], families[0], qualifiers[0], 1, value));
737 tmpTable.put(put1);
738
739 Put put2 = new Put(rows[1]);
740 put2.add(new KeyValue(rows[1], families[1], qualifiers[1], 2, value));
741 tmpTable.put(put2);
742
743
744 scannerCount += countCellsFromScanner(scanner);
745 expectedCount = numRows * numFamilies * numQualifiers - 2;
746 assertTrue("scannerCount: " + scannerCount + " expectedCount: " + expectedCount,
747 scannerCount == expectedCount);
748
749
750 scanner = tmpTable.getScanner(new Scan().setMaxResultSize(1).setAllowPartialResults(true));
751 scannerCount = countCellsFromScanner(scanner);
752 expectedCount = numRows * numFamilies * numQualifiers;
753 assertTrue("scannerCount: " + scannerCount + " expectedCount: " + expectedCount,
754 scannerCount == expectedCount);
755
756 TEST_UTIL.deleteTable(testName);
757 }
758
759
760
761
762
763
764
765
766 private int countCellsFromScanner(ResultScanner scanner) throws Exception {
767 Result result = null;
768 int numCells = 0;
769 while ((result = scanner.next()) != null) {
770 numCells += result.rawCells().length;
771 }
772
773 scanner.close();
774 return numCells;
775 }
776
777
778
779
780
781
782
783
784 @Test
785 public void testPartialResultsWithColumnFilter() throws Exception {
786 testPartialResultsWithColumnFilter(new FirstKeyOnlyFilter());
787 testPartialResultsWithColumnFilter(new ColumnPrefixFilter(Bytes.toBytes("testQualifier5")));
788 testPartialResultsWithColumnFilter(new ColumnRangeFilter(Bytes.toBytes("testQualifer1"), true,
789 Bytes.toBytes("testQualifier7"), true));
790
791 Set<byte[]> qualifiers = new LinkedHashSet<>();
792 qualifiers.add(Bytes.toBytes("testQualifier5"));
793 testPartialResultsWithColumnFilter(new FirstKeyValueMatchingQualifiersFilter(qualifiers));
794 }
795
796 public void testPartialResultsWithColumnFilter(Filter filter) throws Exception {
797 assertTrue(!filter.hasFilterRow());
798
799 Scan partialScan = new Scan();
800 partialScan.setFilter(filter);
801
802 Scan oneshotScan = new Scan();
803 oneshotScan.setFilter(filter);
804 oneshotScan.setMaxResultSize(Long.MAX_VALUE);
805
806 for (int i = 1; i <= NUM_COLS; i++) {
807 partialScan.setMaxResultSize(getResultSizeForNumberOfCells(i));
808 testEquivalenceOfScanResults(TABLE, partialScan, oneshotScan);
809 }
810 }
811
812 private void moveRegion(Table table, int index) throws IOException{
813 List<Pair<HRegionInfo, ServerName>> regions = MetaTableAccessor
814 .getTableRegionsAndLocations(TEST_UTIL.getZooKeeperWatcher(), TEST_UTIL.getConnection(),
815 table.getName());
816 assertEquals(1, regions.size());
817 HRegionInfo regionInfo = regions.get(0).getFirst();
818 ServerName name = TEST_UTIL.getHBaseCluster().getRegionServer(index).getServerName();
819 TEST_UTIL.getHBaseAdmin().move(regionInfo.getEncodedNameAsBytes(),
820 Bytes.toBytes(name.getServerName()));
821 }
822
823 private void assertCell(Cell cell, byte[] row, byte[] cf, byte[] cq) {
824 assertArrayEquals(row,
825 Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
826 assertArrayEquals(cf,
827 Bytes.copy(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
828 assertArrayEquals(cq,
829 Bytes.copy(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
830 }
831
832 @Test
833 public void testPartialResultWhenRegionMove() throws IOException {
834 Table table=createTestTable(TableName.valueOf("testPartialResultWhenRegionMove"),
835 ROWS, FAMILIES, QUALIFIERS, VALUE);
836
837 moveRegion(table, 1);
838
839 Scan scan = new Scan();
840 scan.setMaxResultSize(1);
841 scan.setAllowPartialResults(true);
842 ResultScanner scanner = table.getScanner(scan);
843 for (int i = 0; i < NUM_FAMILIES * NUM_QUALIFIERS - 1; i++) {
844 scanner.next();
845 }
846 Result result1 = scanner.next();
847 assertEquals(1, result1.rawCells().length);
848 Cell c1 = result1.rawCells()[0];
849 assertCell(c1, ROWS[0], FAMILIES[NUM_FAMILIES - 1], QUALIFIERS[NUM_QUALIFIERS - 1]);
850 assertFalse(result1.mayHaveMoreCellsInRow());
851
852 moveRegion(table, 2);
853
854 Result result2 = scanner.next();
855 assertEquals(1, result2.rawCells().length);
856 Cell c2 = result2.rawCells()[0];
857 assertCell(c2, ROWS[1], FAMILIES[0], QUALIFIERS[0]);
858 assertTrue(result2.mayHaveMoreCellsInRow());
859
860 moveRegion(table, 3);
861
862 Result result3 = scanner.next();
863 assertEquals(1, result3.rawCells().length);
864 Cell c3 = result3.rawCells()[0];
865 assertCell(c3, ROWS[1], FAMILIES[0], QUALIFIERS[1]);
866 assertTrue(result3.mayHaveMoreCellsInRow());
867
868 }
869
870 @Test
871 public void testReversedPartialResultWhenRegionMove() throws IOException {
872 Table table=createTestTable(TableName.valueOf("testReversedPartialResultWhenRegionMove"),
873 ROWS, FAMILIES, QUALIFIERS, VALUE);
874
875 moveRegion(table, 1);
876
877 Scan scan = new Scan();
878 scan.setMaxResultSize(1);
879 scan.setAllowPartialResults(true);
880 scan.setReversed(true);
881 ResultScanner scanner = table.getScanner(scan);
882 for (int i = 0; i < NUM_FAMILIES * NUM_QUALIFIERS-1; i++) {
883 scanner.next();
884 }
885 Result result1 = scanner.next();
886 assertEquals(1, result1.rawCells().length);
887 Cell c1 = result1.rawCells()[0];
888 assertCell(c1, ROWS[NUM_ROWS-1], FAMILIES[NUM_FAMILIES - 1], QUALIFIERS[NUM_QUALIFIERS - 1]);
889 assertFalse(result1.mayHaveMoreCellsInRow());
890
891 moveRegion(table, 2);
892
893 Result result2 = scanner.next();
894 assertEquals(1, result2.rawCells().length);
895 Cell c2 = result2.rawCells()[0];
896 assertCell(c2, ROWS[NUM_ROWS-2], FAMILIES[0], QUALIFIERS[0]);
897 assertTrue(result2.mayHaveMoreCellsInRow());
898
899 moveRegion(table, 3);
900
901 Result result3 = scanner.next();
902 assertEquals(1, result3.rawCells().length);
903 Cell c3 = result3.rawCells()[0];
904 assertCell(c3, ROWS[NUM_ROWS-2], FAMILIES[0], QUALIFIERS[1]);
905 assertTrue(result3.mayHaveMoreCellsInRow());
906
907 }
908
909 @Test
910 public void testCompleteResultWhenRegionMove() throws IOException {
911 Table table=createTestTable(TableName.valueOf("testCompleteResultWhenRegionMove"),
912 ROWS, FAMILIES, QUALIFIERS, VALUE);
913
914 moveRegion(table, 1);
915
916 Scan scan = new Scan();
917 scan.setMaxResultSize(1);
918 scan.setCaching(1);
919 ResultScanner scanner = table.getScanner(scan);
920
921 Result result1 = scanner.next();
922 assertEquals(NUM_FAMILIES * NUM_QUALIFIERS, result1.rawCells().length);
923 Cell c1 = result1.rawCells()[0];
924 assertCell(c1, ROWS[0], FAMILIES[0], QUALIFIERS[0]);
925 assertFalse(result1.mayHaveMoreCellsInRow());
926
927 moveRegion(table, 2);
928
929 Result result2 = scanner.next();
930 assertEquals(NUM_FAMILIES * NUM_QUALIFIERS, result2.rawCells().length);
931 Cell c2 = result2.rawCells()[0];
932 assertCell(c2, ROWS[1], FAMILIES[0], QUALIFIERS[0]);
933 assertFalse(result2.mayHaveMoreCellsInRow());
934
935 moveRegion(table, 3);
936
937 Result result3 = scanner.next();
938 assertEquals(NUM_FAMILIES * NUM_QUALIFIERS, result3.rawCells().length);
939 Cell c3 = result3.rawCells()[0];
940 assertCell(c3, ROWS[2], FAMILIES[0], QUALIFIERS[0]);
941 assertFalse(result3.mayHaveMoreCellsInRow());
942
943 }
944
945 @Test
946 public void testReversedCompleteResultWhenRegionMove() throws IOException {
947 Table table=createTestTable(TableName.valueOf("testReversedCompleteResultWhenRegionMove"),
948 ROWS, FAMILIES, QUALIFIERS, VALUE);
949
950 moveRegion(table, 1);
951
952 Scan scan = new Scan();
953 scan.setMaxResultSize(1);
954 scan.setCaching(1);
955 scan.setReversed(true);
956 ResultScanner scanner = table.getScanner(scan);
957
958 Result result1 = scanner.next();
959 assertEquals(NUM_FAMILIES*NUM_QUALIFIERS, result1.rawCells().length);
960 Cell c1 = result1.rawCells()[0];
961 assertCell(c1, ROWS[NUM_ROWS-1], FAMILIES[0], QUALIFIERS[0]);
962 assertFalse(result1.mayHaveMoreCellsInRow());
963
964 moveRegion(table, 2);
965
966 Result result2 = scanner.next();
967 assertEquals(NUM_FAMILIES*NUM_QUALIFIERS, result2.rawCells().length);
968 Cell c2 = result2.rawCells()[0];
969 assertCell(c2, ROWS[NUM_ROWS-2], FAMILIES[0], QUALIFIERS[0]);
970 assertFalse(result2.mayHaveMoreCellsInRow());
971
972 moveRegion(table, 3);
973
974 Result result3 = scanner.next();
975 assertEquals(NUM_FAMILIES*NUM_QUALIFIERS, result3.rawCells().length);
976 Cell c3 = result3.rawCells()[0];
977 assertCell(c3, ROWS[NUM_ROWS-3], FAMILIES[0], QUALIFIERS[0]);
978 assertFalse(result3.mayHaveMoreCellsInRow());
979
980 }
981
982 @Test
983 public void testBatchingResultWhenRegionMove() throws IOException {
984
985
986
987 Table table = createTestTable(TableName.valueOf("testBatchingResultWhenRegionMove"),
988 ROWS, FAMILIES, QUALIFIERS, VALUE);
989
990 Put put = new Put(ROWS[1]);
991 put.addColumn(FAMILIES[0], QUALIFIERS[1], new byte[VALUE_SIZE * 10]);
992 table.put(put);
993 Delete delete = new Delete(ROWS[1]);
994 delete.addColumn(FAMILIES[NUM_FAMILIES - 1], QUALIFIERS[NUM_QUALIFIERS - 1]);
995 table.delete(delete);
996
997 moveRegion(table, 1);
998
999 Scan scan = new Scan();
1000 scan.setCaching(1);
1001 scan.setBatch(5);
1002 scan.setMaxResultSize(VALUE_SIZE * 6);
1003
1004 ResultScanner scanner = table.getScanner(scan);
1005 for (int i = 0; i < NUM_FAMILIES * NUM_QUALIFIERS / 5 - 1; i++) {
1006 assertTrue(scanner.next().mayHaveMoreCellsInRow());
1007 }
1008 Result result1 = scanner.next();
1009 assertEquals(5, result1.rawCells().length);
1010 assertCell(result1.rawCells()[0], ROWS[0], FAMILIES[NUM_FAMILIES - 1],
1011 QUALIFIERS[NUM_QUALIFIERS - 5]);
1012 assertCell(result1.rawCells()[4], ROWS[0], FAMILIES[NUM_FAMILIES - 1],
1013 QUALIFIERS[NUM_QUALIFIERS - 1]);
1014 assertFalse(result1.mayHaveMoreCellsInRow());
1015
1016 moveRegion(table, 2);
1017
1018 Result result2 = scanner.next();
1019 assertEquals(5, result2.rawCells().length);
1020 assertCell(result2.rawCells()[0], ROWS[1], FAMILIES[0], QUALIFIERS[0]);
1021 assertCell(result2.rawCells()[4], ROWS[1], FAMILIES[0], QUALIFIERS[4]);
1022 assertTrue(result2.mayHaveMoreCellsInRow());
1023
1024 moveRegion(table, 3);
1025
1026 Result result3 = scanner.next();
1027 assertEquals(5, result3.rawCells().length);
1028 assertCell(result3.rawCells()[0], ROWS[1], FAMILIES[0], QUALIFIERS[5]);
1029 assertCell(result3.rawCells()[4], ROWS[1], FAMILIES[0], QUALIFIERS[9]);
1030 assertTrue(result3.mayHaveMoreCellsInRow());
1031
1032 for (int i = 0; i < NUM_FAMILIES * NUM_QUALIFIERS / 5 - 3; i++) {
1033 Result result = scanner.next();
1034 assertEquals(5, result.rawCells().length);
1035 assertTrue(result.mayHaveMoreCellsInRow());
1036 }
1037 Result result = scanner.next();
1038 assertEquals(4, result.rawCells().length);
1039 assertFalse(result.mayHaveMoreCellsInRow());
1040
1041
1042 for (int i = 2; i < NUM_ROWS; i++) {
1043 for (int j = 0; j < NUM_FAMILIES; j++) {
1044 for (int k = 0; k < NUM_QUALIFIERS; k += 5) {
1045 result = scanner.next();
1046 assertCell(result.rawCells()[0], ROWS[i], FAMILIES[j], QUALIFIERS[k]);
1047 assertEquals(5, result.rawCells().length);
1048 if (j == NUM_FAMILIES - 1 && k == NUM_QUALIFIERS - 5) {
1049 assertFalse(result.mayHaveMoreCellsInRow());
1050 } else {
1051 assertTrue(result.mayHaveMoreCellsInRow());
1052 }
1053 }
1054 }
1055 }
1056 assertNull(scanner.next());
1057 }
1058
1059 @Test
1060 public void testDontThrowUnknowScannerExceptionToClient() throws Exception {
1061 Table table =
1062 createTestTable(TableName.valueOf("testDontThrowUnknowScannerException"), ROWS, FAMILIES,
1063 QUALIFIERS, VALUE);
1064 Scan scan = new Scan();
1065 scan.setCaching(1);
1066 ResultScanner scanner = table.getScanner(scan);
1067 scanner.next();
1068 Thread.sleep(timeout * 2);
1069 int count = 1;
1070 while (scanner.next() != null) {
1071 count++;
1072 }
1073 assertEquals(NUM_ROWS, count);
1074 scanner.close();
1075 }
1076
1077 @Test
1078 public void testMayHaveMoreCellsInRowReturnsTrueAndSetBatch() throws IOException {
1079 Table table = createTestTable(TableName.valueOf(
1080 "testMayHaveMoreCellsInRowReturnsTrueAndSetBatch"), ROWS, FAMILIES,
1081 QUALIFIERS, VALUE);
1082 Scan scan = new Scan();
1083 scan.setBatch(1);
1084 scan.setFilter(new FirstKeyOnlyFilter());
1085 ResultScanner scanner = table.getScanner(scan);
1086 Result result;
1087 while ((result = scanner.next()) != null) {
1088 assertTrue(result.rawCells() != null);
1089 assertEquals(1, result.rawCells().length);
1090 }
1091 }
1092
1093 }