1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import com.google.common.annotations.VisibleForTesting;
23
24 import java.io.IOException;
25 import java.io.InterruptedIOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.NavigableSet;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.locks.ReentrantLock;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.hadoop.hbase.Cell;
36 import org.apache.hadoop.hbase.CellUtil;
37 import org.apache.hadoop.hbase.DoNotRetryIOException;
38 import org.apache.hadoop.hbase.HConstants;
39 import org.apache.hadoop.hbase.KeyValue;
40 import org.apache.hadoop.hbase.KeyValue.KVComparator;
41 import org.apache.hadoop.hbase.KeyValueUtil;
42 import org.apache.hadoop.hbase.classification.InterfaceAudience;
43 import org.apache.hadoop.hbase.client.IsolationLevel;
44 import org.apache.hadoop.hbase.client.Scan;
45 import org.apache.hadoop.hbase.executor.ExecutorService;
46 import org.apache.hadoop.hbase.filter.Filter;
47 import org.apache.hadoop.hbase.regionserver.ScannerContext.LimitScope;
48 import org.apache.hadoop.hbase.regionserver.ScannerContext.NextState;
49 import org.apache.hadoop.hbase.regionserver.handler.ParallelSeekHandler;
50 import org.apache.hadoop.hbase.regionserver.querymatcher.CompactionScanQueryMatcher;
51 import org.apache.hadoop.hbase.regionserver.querymatcher.LegacyScanQueryMatcher;
52 import org.apache.hadoop.hbase.regionserver.querymatcher.ScanQueryMatcher;
53 import org.apache.hadoop.hbase.regionserver.querymatcher.UserScanQueryMatcher;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.CollectionUtils;
56 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
57
58
59
60
61
62 @InterfaceAudience.Private
63 public class StoreScanner extends NonReversedNonLazyKeyValueScanner
64 implements KeyValueScanner, InternalScanner, ChangedReadersObserver {
65 private static final Log LOG = LogFactory.getLog(StoreScanner.class);
66
67 protected final Store store;
68 protected ScanQueryMatcher matcher;
69 protected KeyValueHeap heap;
70 protected boolean cacheBlocks;
71
72 protected long countPerRow = 0;
73 protected int storeLimit = -1;
74 protected int storeOffset = 0;
75
76
77
78 protected boolean closing = false;
79 protected final boolean get;
80 protected final boolean explicitColumnQuery;
81 protected final boolean useRowColBloom;
82
83
84
85 protected boolean parallelSeekEnabled = false;
86 protected ExecutorService executor;
87 protected final Scan scan;
88 protected final NavigableSet<byte[]> columns;
89 protected final long oldestUnexpiredTS;
90 protected final long now;
91 protected final int minVersions;
92 protected final long maxRowSize;
93 protected final long cellsPerHeartbeatCheck;
94
95
96
97
98
99 private final List<KeyValueScanner> scannersForDelayedClose = new ArrayList<>();
100
101
102
103
104 private long kvsScanned = 0;
105 private Cell prevCell = null;
106
107
108 static final boolean LAZY_SEEK_ENABLED_BY_DEFAULT = true;
109 public static final String STORESCANNER_PARALLEL_SEEK_ENABLE =
110 "hbase.storescanner.parallel.seek.enable";
111
112
113 protected static boolean lazySeekEnabledGlobally =
114 LAZY_SEEK_ENABLED_BY_DEFAULT;
115
116
117
118
119
120
121 public static final String HBASE_CELLS_SCANNED_PER_HEARTBEAT_CHECK =
122 "hbase.cells.scanned.per.heartbeat.check";
123
124
125
126
127 public static final long DEFAULT_HBASE_CELLS_SCANNED_PER_HEARTBEAT_CHECK = 10000;
128
129
130 protected Cell lastTop = null;
131
132
133 private boolean scanUsePread = false;
134
135 private volatile boolean flushed = false;
136
137
138 private final List<KeyValueScanner> flushedstoreFileScanners =
139 new ArrayList<KeyValueScanner>(1);
140
141 private final List<KeyValueScanner> memStoreScannersAfterFlush = new ArrayList<>(1);
142
143 private final List<KeyValueScanner> currentScanners = new ArrayList<KeyValueScanner>();
144
145 private ReentrantLock flushLock = new ReentrantLock();
146
147 private final long readPt;
148 private boolean topChanged = false;
149
150
151 enum StoreScannerCompactionRace {
152 BEFORE_SEEK,
153 AFTER_SEEK,
154 COMPACT_COMPLETE
155 }
156
157
158 protected StoreScanner(Store store, Scan scan, final ScanInfo scanInfo,
159 final NavigableSet<byte[]> columns, long readPt, boolean cacheBlocks) {
160 this.readPt = readPt;
161 this.store = store;
162 this.cacheBlocks = cacheBlocks;
163 get = scan.isGetScan();
164 int numCol = columns == null ? 0 : columns.size();
165 explicitColumnQuery = numCol > 0;
166 this.scan = scan;
167 this.columns = columns;
168 this.now = EnvironmentEdgeManager.currentTime();
169 this.oldestUnexpiredTS = scan.isRaw() ? 0L : now - scanInfo.getTtl();
170 this.minVersions = scanInfo.getMinVersions();
171
172
173
174
175
176 this.useRowColBloom = numCol > 1 || (!get && numCol == 1);
177
178 this.maxRowSize = scanInfo.getTableMaxRowSize();
179 this.scanUsePread = scan.isSmall()? true: scanInfo.isUsePread();
180 this.cellsPerHeartbeatCheck = scanInfo.getCellsPerTimeoutCheck();
181
182 if (this.store != null && this.store.getStorefilesCount() > 1) {
183 RegionServerServices rsService = ((HStore)store).getHRegion().getRegionServerServices();
184 if (rsService != null && scanInfo.isParallelSeekEnabled()) {
185 this.parallelSeekEnabled = true;
186 this.executor = rsService.getExecutorService();
187 }
188 }
189 }
190
191 protected void addCurrentScanners(List<? extends KeyValueScanner> scanners) {
192 this.currentScanners.addAll(scanners);
193 }
194
195
196
197
198
199
200
201
202
203
204 public StoreScanner(Store store, ScanInfo scanInfo, Scan scan, final NavigableSet<byte[]> columns,
205 long readPt)
206 throws IOException {
207 this(store, scan, scanInfo, columns, readPt, scan.getCacheBlocks());
208 if (columns != null && scan.isRaw()) {
209 throw new DoNotRetryIOException("Cannot specify any column for a raw scan");
210 }
211 matcher = UserScanQueryMatcher.create(scan, scanInfo, columns, oldestUnexpiredTS, now,
212 store.getCoprocessorHost());
213
214 this.store.addChangedReaderObserver(this);
215
216 try {
217
218 List<KeyValueScanner> scanners = getScannersNoCompaction();
219
220
221
222
223
224 seekScanners(scanners, matcher.getStartKey(), explicitColumnQuery && lazySeekEnabledGlobally,
225 parallelSeekEnabled);
226
227
228 this.storeLimit = scan.getMaxResultsPerColumnFamily();
229
230
231 this.storeOffset = scan.getRowOffsetPerColumnFamily();
232 addCurrentScanners(scanners);
233
234 resetKVHeap(scanners, store.getComparator());
235 } catch (IOException e) {
236
237
238 this.store.deleteChangedReaderObserver(this);
239 throw e;
240 }
241 }
242
243
244
245
246
247
248
249
250
251
252
253 public StoreScanner(Store store, ScanInfo scanInfo, Scan scan,
254 List<? extends KeyValueScanner> scanners, ScanType scanType,
255 long smallestReadPoint, long earliestPutTs) throws IOException {
256 this(store, scanInfo, scan, scanners, scanType, smallestReadPoint, earliestPutTs, null, null);
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270 public StoreScanner(Store store, ScanInfo scanInfo, Scan scan,
271 List<? extends KeyValueScanner> scanners, long smallestReadPoint, long earliestPutTs,
272 byte[] dropDeletesFromRow, byte[] dropDeletesToRow) throws IOException {
273 this(store, scanInfo, scan, scanners, ScanType.COMPACT_RETAIN_DELETES, smallestReadPoint,
274 earliestPutTs, dropDeletesFromRow, dropDeletesToRow);
275 }
276
277 private StoreScanner(Store store, ScanInfo scanInfo, Scan scan,
278 List<? extends KeyValueScanner> scanners, ScanType scanType, long smallestReadPoint,
279 long earliestPutTs, byte[] dropDeletesFromRow, byte[] dropDeletesToRow) throws IOException {
280 this(store, scan, scanInfo, null,
281 ((HStore) store).getHRegion().getReadpoint(IsolationLevel.READ_COMMITTED), false);
282 if (scan.hasFilter() || (scan.getStartRow() != null && scan.getStartRow().length > 0)
283 || (scan.getStopRow() != null && scan.getStopRow().length > 0)
284 || !scan.getTimeRange().isAllTime()) {
285
286
287 matcher = LegacyScanQueryMatcher.create(scan, scanInfo, null, scanType, smallestReadPoint,
288 earliestPutTs, oldestUnexpiredTS, now, dropDeletesFromRow, dropDeletesToRow,
289 store.getCoprocessorHost());
290 } else {
291 matcher = CompactionScanQueryMatcher.create(scanInfo, scanType, smallestReadPoint,
292 earliestPutTs, oldestUnexpiredTS, now, dropDeletesFromRow, dropDeletesToRow,
293 store.getCoprocessorHost());
294 }
295
296
297 scanners = selectScannersFrom(scanners);
298
299
300 seekScanners(scanners, matcher.getStartKey(), false, parallelSeekEnabled);
301 addCurrentScanners(scanners);
302
303 resetKVHeap(scanners, store.getComparator());
304 }
305
306 @VisibleForTesting
307 StoreScanner(final Scan scan, ScanInfo scanInfo,
308 ScanType scanType, final NavigableSet<byte[]> columns,
309 final List<KeyValueScanner> scanners) throws IOException {
310 this(scan, scanInfo, scanType, columns, scanners,
311 HConstants.LATEST_TIMESTAMP,
312
313 0);
314 }
315
316 @VisibleForTesting
317 StoreScanner(final Scan scan, ScanInfo scanInfo,
318 ScanType scanType, final NavigableSet<byte[]> columns,
319 final List<KeyValueScanner> scanners, long earliestPutTs)
320 throws IOException {
321 this(scan, scanInfo, scanType, columns, scanners, earliestPutTs,
322
323 0);
324 }
325
326 public StoreScanner(final Scan scan, ScanInfo scanInfo, ScanType scanType,
327 final NavigableSet<byte[]> columns, final List<KeyValueScanner> scanners, long earliestPutTs,
328 long readPt) throws IOException {
329 this(null, scan, scanInfo, columns, readPt, scan.getCacheBlocks());
330 if (scanType == ScanType.USER_SCAN) {
331 this.matcher = UserScanQueryMatcher.create(scan, scanInfo, columns, oldestUnexpiredTS, now,
332 null);
333 } else {
334 if (scan.hasFilter() || (scan.getStartRow() != null && scan.getStartRow().length > 0)
335 || (scan.getStopRow() != null && scan.getStopRow().length > 0)
336 || !scan.getTimeRange().isAllTime() || columns != null) {
337
338
339 matcher = LegacyScanQueryMatcher.create(scan, scanInfo, columns, scanType, Long.MAX_VALUE,
340 earliestPutTs, oldestUnexpiredTS, now, null, null, store.getCoprocessorHost());
341 } else {
342 this.matcher = CompactionScanQueryMatcher.create(scanInfo, scanType, Long.MAX_VALUE,
343 earliestPutTs, oldestUnexpiredTS, now, null, null, null);
344 }
345 }
346
347
348 seekScanners(scanners, matcher.getStartKey(), false, parallelSeekEnabled);
349 addCurrentScanners(scanners);
350 resetKVHeap(scanners, scanInfo.getComparator());
351 }
352
353
354
355
356
357 protected List<KeyValueScanner> getScannersNoCompaction() throws IOException {
358 final boolean isCompaction = false;
359 boolean usePread = get || scanUsePread;
360 return selectScannersFrom(store.getScanners(cacheBlocks, get, usePread,
361 isCompaction, matcher, scan.getStartRow(), scan.getStopRow(), this.readPt));
362 }
363
364
365
366
367
368
369
370
371
372 protected void seekScanners(List<? extends KeyValueScanner> scanners,
373 Cell seekKey, boolean isLazy, boolean isParallelSeek)
374 throws IOException {
375
376
377
378
379 if (isLazy) {
380 for (KeyValueScanner scanner : scanners) {
381 scanner.requestSeek(seekKey, false, true);
382 }
383 } else {
384 if (!isParallelSeek) {
385 long totalScannersSoughtBytes = 0;
386 for (KeyValueScanner scanner : scanners) {
387 if (matcher.isUserScan() && totalScannersSoughtBytes >= maxRowSize) {
388 throw new RowTooBigException("Max row size allowed: " + maxRowSize
389 + ", but row is bigger than that");
390 }
391 scanner.seek(seekKey);
392 Cell c = scanner.peek();
393 if (c != null) {
394 totalScannersSoughtBytes += CellUtil.estimatedSerializedSizeOf(c);
395 }
396 }
397 } else {
398 parallelSeek(scanners, seekKey);
399 }
400 }
401 }
402
403 protected void resetKVHeap(List<? extends KeyValueScanner> scanners,
404 KVComparator comparator) throws IOException {
405
406 heap = new KeyValueHeap(scanners, comparator);
407 }
408
409
410
411
412
413 protected List<KeyValueScanner> selectScannersFrom(
414 final List<? extends KeyValueScanner> allScanners) {
415 boolean memOnly;
416 boolean filesOnly;
417 if (scan instanceof InternalScan) {
418 InternalScan iscan = (InternalScan)scan;
419 memOnly = iscan.isCheckOnlyMemStore();
420 filesOnly = iscan.isCheckOnlyStoreFiles();
421 } else {
422 memOnly = false;
423 filesOnly = false;
424 }
425
426 List<KeyValueScanner> scanners =
427 new ArrayList<KeyValueScanner>(allScanners.size());
428
429
430
431 long expiredTimestampCutoff = minVersions == 0 ? oldestUnexpiredTS: Long.MIN_VALUE;
432
433
434 for (KeyValueScanner kvs : allScanners) {
435 boolean isFile = kvs.isFileScanner();
436 if ((!isFile && filesOnly) || (isFile && memOnly)) {
437 continue;
438 }
439
440 if (kvs.shouldUseScanner(scan, store, expiredTimestampCutoff)) {
441 scanners.add(kvs);
442 } else {
443 kvs.close();
444 }
445 }
446 return scanners;
447 }
448
449 @Override
450 public Cell peek() {
451 if (this.heap == null) {
452 return this.lastTop;
453 }
454 return this.heap.peek();
455 }
456
457 @Override
458 public KeyValue next() {
459
460 throw new RuntimeException("Never call StoreScanner.next()");
461 }
462
463 @Override
464 public void close() {
465 if (this.closing) {
466 return;
467 }
468
469
470 if (this.store != null) {
471 this.store.deleteChangedReaderObserver(this);
472 }
473
474
475
476 flushLock.lock();
477 try {
478 this.closing = true;
479 clearAndClose(scannersForDelayedClose);
480 clearAndClose(memStoreScannersAfterFlush);
481
482
483
484 clearAndClose(flushedstoreFileScanners);
485 } finally {
486 flushLock.unlock();
487 }
488 if (this.heap != null)
489 this.heap.close();
490 this.heap = null;
491 this.lastTop = null;
492 }
493
494 @Override
495 public boolean seek(Cell key) throws IOException {
496 boolean flushed = checkFlushed();
497
498 checkReseek(flushed);
499 return this.heap.seek(key);
500 }
501
502 @Override
503 public boolean next(List<Cell> outResult) throws IOException {
504 return next(outResult, NoLimitScannerContext.getInstance());
505 }
506
507
508
509
510
511
512
513 @Override
514 public boolean next(List<Cell> outResult, ScannerContext scannerContext) throws IOException {
515 if (scannerContext == null) {
516 throw new IllegalArgumentException("Scanner context cannot be null");
517 }
518 boolean flushed = checkFlushed();
519 if (checkReseek(flushed)) {
520 return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
521 }
522
523
524
525 if (this.heap == null) {
526 close();
527 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
528 }
529
530 Cell cell = this.heap.peek();
531 if (cell == null) {
532 close();
533 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
534 }
535
536
537
538
539
540
541
542 if (!scannerContext.hasAnyLimit(LimitScope.BETWEEN_CELLS) || matcher.currentRow() == null) {
543 this.countPerRow = 0;
544 matcher.setToNewRow(cell);
545 }
546
547
548 if (!scannerContext.getKeepProgress()) scannerContext.clearProgress();
549
550
551 KeyValue.KVComparator comparator =
552 store != null ? store.getComparator() : null;
553
554 int count = 0;
555 long totalBytesRead = 0;
556
557 LOOP: do {
558
559 if ((kvsScanned % cellsPerHeartbeatCheck == 0)) {
560 scannerContext.updateTimeProgress();
561 if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {
562 return scannerContext.setScannerState(NextState.TIME_LIMIT_REACHED).hasMoreValues();
563 }
564 }
565
566 if (prevCell != cell) ++kvsScanned;
567 checkScanOrder(prevCell, cell, comparator);
568 prevCell = cell;
569 scannerContext.setLastPeekedCell(cell);
570 topChanged = false;
571 ScanQueryMatcher.MatchCode qcode = matcher.match(cell);
572 switch (qcode) {
573 case INCLUDE:
574 case INCLUDE_AND_SEEK_NEXT_ROW:
575 case INCLUDE_AND_SEEK_NEXT_COL:
576
577 Filter f = matcher.getFilter();
578 if (f != null) {
579 cell = f.transformCell(cell);
580 }
581
582 this.countPerRow++;
583 if (storeLimit > -1 &&
584 this.countPerRow > (storeLimit + storeOffset)) {
585
586 if (!matcher.moreRowsMayExistAfter(cell)) {
587 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
588 }
589
590
591
592 matcher.clearCurrentRow();
593 seekToNextRow(cell);
594 break LOOP;
595 }
596
597
598
599 if (this.countPerRow > storeOffset) {
600 outResult.add(cell);
601
602
603 count++;
604 totalBytesRead += CellUtil.estimatedSerializedSizeOf(cell);
605
606
607 scannerContext.incrementSizeProgress(CellUtil.estimatedHeapSizeOfWithoutTags(cell));
608 scannerContext.incrementBatchProgress(1);
609
610 if (matcher.isUserScan() && totalBytesRead > maxRowSize) {
611 throw new RowTooBigException("Max row size allowed: " + maxRowSize
612 + ", but the row is bigger than that.");
613 }
614 }
615
616 if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW) {
617 if (!matcher.moreRowsMayExistAfter(cell)) {
618 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
619 }
620
621
622
623 matcher.clearCurrentRow();
624 seekOrSkipToNextRow(cell);
625 } else if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL) {
626 seekOrSkipToNextColumn(cell);
627 } else {
628 this.heap.next();
629 }
630
631 if (scannerContext.checkBatchLimit(LimitScope.BETWEEN_CELLS)) {
632 break LOOP;
633 }
634 if (scannerContext.checkSizeLimit(LimitScope.BETWEEN_CELLS)) {
635 break LOOP;
636 }
637 continue;
638
639 case DONE:
640
641 if (this.scan.isGetScan()) {
642
643 close();
644 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
645 }
646
647
648
649 matcher.clearCurrentRow();
650 return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
651
652 case DONE_SCAN:
653 close();
654 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
655
656 case SEEK_NEXT_ROW:
657
658
659 if (!matcher.moreRowsMayExistAfter(cell)) {
660 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
661 }
662
663
664
665 matcher.clearCurrentRow();
666 seekOrSkipToNextRow(cell);
667 NextState stateAfterSeekNextRow = needToReturn(outResult);
668 if (stateAfterSeekNextRow != null) {
669 return scannerContext.setScannerState(stateAfterSeekNextRow).hasMoreValues();
670 }
671 break;
672
673 case SEEK_NEXT_COL:
674 seekOrSkipToNextColumn(cell);
675 NextState stateAfterSeekNextColumn = needToReturn(outResult);
676 if (stateAfterSeekNextColumn != null) {
677 return scannerContext.setScannerState(stateAfterSeekNextColumn).hasMoreValues();
678 }
679 break;
680
681 case SKIP:
682 this.heap.next();
683 break;
684
685 case SEEK_NEXT_USING_HINT:
686 Cell nextKV = matcher.getNextKeyHint(cell);
687 if (nextKV != null) {
688 seekAsDirection(nextKV);
689 NextState stateAfterSeekByHint = needToReturn(outResult);
690 if (stateAfterSeekByHint != null) {
691 return scannerContext.setScannerState(stateAfterSeekByHint).hasMoreValues();
692 }
693 } else {
694 heap.next();
695 }
696 break;
697
698 default:
699 throw new RuntimeException("UNEXPECTED");
700 }
701 } while((cell = this.heap.peek()) != null);
702
703 if (count > 0) {
704 return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
705 }
706
707
708 close();
709 return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
710 }
711
712
713
714
715
716
717
718
719
720
721
722
723 private NextState needToReturn(List<Cell> outResult) {
724 if (!outResult.isEmpty() && topChanged) {
725 return heap.peek() == null ? NextState.NO_MORE_VALUES : NextState.MORE_VALUES;
726 }
727 return null;
728 }
729
730 private void seekOrSkipToNextRow(Cell cell) throws IOException {
731
732
733 if (!get) {
734 if (trySkipToNextRow(cell)) {
735 return;
736 }
737 }
738 seekToNextRow(cell);
739 }
740
741 private void seekOrSkipToNextColumn(Cell cell) throws IOException {
742 if (!trySkipToNextColumn(cell)) {
743 seekAsDirection(matcher.getKeyForNextColumn(cell));
744 }
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796 @VisibleForTesting
797 protected boolean trySkipToNextRow(Cell cell) throws IOException {
798 Cell nextCell = null;
799 do {
800 Cell nextIndexedKey = getNextIndexedKey();
801 if (nextIndexedKey != null && nextIndexedKey != KeyValueScanner.NO_NEXT_INDEXED_KEY
802 && matcher.compareKeyForNextRow(nextIndexedKey, cell) >= 0) {
803 this.heap.next();
804 ++kvsScanned;
805 } else {
806 return false;
807 }
808 } while ((nextCell = this.heap.peek()) != null && CellUtil.matchingRow(cell, nextCell));
809 return true;
810 }
811
812
813
814
815
816
817 @VisibleForTesting
818 protected boolean trySkipToNextColumn(Cell cell) throws IOException {
819 Cell nextCell = null;
820 do {
821 Cell nextIndexedKey = getNextIndexedKey();
822 if (nextIndexedKey != null && nextIndexedKey != KeyValueScanner.NO_NEXT_INDEXED_KEY
823 && matcher.compareKeyForNextColumn(nextIndexedKey, cell) >= 0) {
824 this.heap.next();
825 ++kvsScanned;
826 } else {
827 return false;
828 }
829 } while ((nextCell = this.heap.peek()) != null && CellUtil.matchingRowColumn(cell, nextCell));
830
831
832
833 if (nextCell != null && matcher.compareKeyForNextColumn(nextCell, cell) < 0) {
834 return false;
835 }
836 return true;
837 }
838
839 @Override
840 public long getReadPoint() {
841 return readPt;
842 }
843
844 private static void clearAndClose(List<KeyValueScanner> scanners) {
845 for (KeyValueScanner s : scanners) {
846 s.close();
847 }
848 scanners.clear();
849 }
850
851
852 @Override
853 public void updateReaders(List<StoreFile> sfs, List<KeyValueScanner> memStoreScanners) throws IOException {
854 if (CollectionUtils.isEmpty(sfs) && CollectionUtils.isEmpty(memStoreScanners)) {
855 return;
856 }
857 flushLock.lock();
858 try {
859 if (this.closing) {
860
861
862 if (!CollectionUtils.isEmpty(memStoreScanners)) {
863 clearAndClose(new ArrayList<>(memStoreScanners));
864 }
865 return;
866 }
867 flushed = true;
868 final boolean isCompaction = false;
869 boolean usePread = get || scanUsePread;
870
871
872
873
874
875
876 List<KeyValueScanner> scanners = store.getScanners(sfs, cacheBlocks, get, usePread,
877 isCompaction, matcher, scan.getStartRow(), scan.getStopRow(), this.readPt, false);
878 flushedstoreFileScanners.addAll(scanners);
879 if (!CollectionUtils.isEmpty(memStoreScanners)) {
880 clearAndClose(memStoreScannersAfterFlush);
881 memStoreScannersAfterFlush.addAll(memStoreScanners);
882 }
883 } finally {
884 flushLock.unlock();
885 }
886 }
887
888
889 protected void nullifyCurrentHeap() throws IOException {
890 if (this.closing) return;
891
892
893
894
895
896
897 if (this.heap == null) return;
898
899
900 this.lastTop = this.heap.peek();
901
902
903
904
905 this.heap.close();
906 this.heap = null;
907
908
909 }
910
911
912
913
914
915
916
917 protected boolean checkReseek(boolean flushed) throws IOException {
918 if (flushed && this.lastTop != null) {
919 resetScannerStack(this.lastTop);
920 if (this.heap.peek() == null
921 || store.getComparator().compareRows(this.lastTop, this.heap.peek()) != 0) {
922 LOG.info("Storescanner.peek() is changed where before = "
923 + this.lastTop.toString() + ",and after = " + this.heap.peek());
924 this.lastTop = null;
925 topChanged = true;
926 return true;
927 }
928 this.lastTop = null;
929 }
930
931 topChanged = false;
932 return false;
933 }
934
935 protected void resetScannerStack(Cell lastTopKey) throws IOException {
936
937
938
939
940
941 final boolean isCompaction = false;
942 boolean usePread = get || scanUsePread;
943 List<KeyValueScanner> scanners = null;
944 flushLock.lock();
945 try {
946 List<KeyValueScanner> allScanners =
947 new ArrayList<>(flushedstoreFileScanners.size() + memStoreScannersAfterFlush.size());
948 allScanners.addAll(flushedstoreFileScanners);
949 allScanners.addAll(memStoreScannersAfterFlush);
950 scanners = selectScannersFrom(allScanners);
951
952 flushedstoreFileScanners.clear();
953 memStoreScannersAfterFlush.clear();
954 } finally {
955 flushLock.unlock();
956 }
957
958
959 seekScanners(scanners, lastTopKey, false, parallelSeekEnabled);
960
961 for (int i = 0; i < currentScanners.size(); i++) {
962 if (!currentScanners.get(i).isFileScanner()) {
963 scannersForDelayedClose.add(currentScanners.remove(i));
964 break;
965 }
966 }
967
968 addCurrentScanners(scanners);
969
970 resetKVHeap(this.currentScanners, store.getComparator());
971
972
973
974 Cell kv = heap.peek();
975 if (kv == null) {
976 kv = lastTopKey;
977 }
978 byte[] row = kv.getRowArray();
979 int offset = kv.getRowOffset();
980 short length = kv.getRowLength();
981 Cell currentRow = matcher.currentRow();
982
983 if ((currentRow == null) || !Bytes.equals(row, offset, length, currentRow.getRowArray(),
984 currentRow.getRowOffset(), currentRow.getRowLength())) {
985 this.countPerRow = 0;
986 matcher.setToNewRow(kv);
987 }
988 }
989
990
991
992
993
994
995
996
997 protected void checkScanOrder(Cell prevKV, Cell kv,
998 KeyValue.KVComparator comparator) throws IOException {
999
1000 assert prevKV == null || comparator == null
1001 || comparator.compare(prevKV, kv) <= 0 : "Key " + prevKV
1002 + " followed by a " + "smaller key " + kv + " in cf " + store;
1003 }
1004
1005 protected boolean seekToNextRow(Cell kv) throws IOException {
1006 return reseek(KeyValueUtil.createLastOnRow(kv));
1007 }
1008
1009
1010
1011
1012
1013
1014
1015 protected boolean seekAsDirection(Cell kv)
1016 throws IOException {
1017 return reseek(kv);
1018 }
1019
1020 @Override
1021 public boolean reseek(Cell kv) throws IOException {
1022 boolean flushed = checkFlushed();
1023
1024
1025
1026 checkReseek(flushed);
1027 if (explicitColumnQuery && lazySeekEnabledGlobally) {
1028 return heap.requestSeek(kv, true, useRowColBloom);
1029 }
1030 return heap.reseek(kv);
1031 }
1032
1033 protected boolean checkFlushed() {
1034
1035
1036
1037
1038
1039 if (flushed) {
1040
1041
1042 if(!this.closing) {
1043 this.lastTop = this.peek();
1044 } else {
1045 return false;
1046 }
1047
1048 flushed = false;
1049 return true;
1050 }
1051 return false;
1052 }
1053
1054
1055
1056
1057 @Override
1058 public long getScannerOrder() {
1059 return 0;
1060 }
1061
1062
1063
1064
1065
1066
1067
1068 private void parallelSeek(final List<? extends KeyValueScanner>
1069 scanners, final Cell kv) throws IOException {
1070 if (scanners.isEmpty()) return;
1071 int storeFileScannerCount = scanners.size();
1072 CountDownLatch latch = new CountDownLatch(storeFileScannerCount);
1073 List<ParallelSeekHandler> handlers =
1074 new ArrayList<ParallelSeekHandler>(storeFileScannerCount);
1075 for (KeyValueScanner scanner : scanners) {
1076 if (scanner instanceof StoreFileScanner) {
1077 ParallelSeekHandler seekHandler = new ParallelSeekHandler(scanner, kv,
1078 this.readPt, latch);
1079 executor.submit(seekHandler);
1080 handlers.add(seekHandler);
1081 } else {
1082 scanner.seek(kv);
1083 latch.countDown();
1084 }
1085 }
1086
1087 try {
1088 latch.await();
1089 } catch (InterruptedException ie) {
1090 throw (InterruptedIOException)new InterruptedIOException().initCause(ie);
1091 }
1092
1093 for (ParallelSeekHandler handler : handlers) {
1094 if (handler.getErr() != null) {
1095 throw new IOException(handler.getErr());
1096 }
1097 }
1098 }
1099
1100
1101
1102
1103
1104 List<KeyValueScanner> getAllScannersForTesting() {
1105 List<KeyValueScanner> allScanners = new ArrayList<KeyValueScanner>();
1106 KeyValueScanner current = heap.getCurrentForTesting();
1107 if (current != null)
1108 allScanners.add(current);
1109 for (KeyValueScanner scanner : heap.getHeap())
1110 allScanners.add(scanner);
1111 return allScanners;
1112 }
1113
1114 static void enableLazySeekGlobally(boolean enable) {
1115 lazySeekEnabledGlobally = enable;
1116 }
1117
1118
1119
1120
1121 public long getEstimatedNumberOfKvsScanned() {
1122 return this.kvsScanned;
1123 }
1124
1125 @Override
1126 public Cell getNextIndexedKey() {
1127 return this.heap.getNextIndexedKey();
1128 }
1129 }
1130