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