Search in sources :

Example 1 with NextState

use of org.apache.hadoop.hbase.regionserver.ScannerContext.NextState in project hbase by apache.

the class StoreScanner method next.

/**
 * Get the next row of values from this Store.
 * @param outResult
 * @param scannerContext
 * @return true if there are more rows, false if scanner is done
 */
@Override
public boolean next(List<Cell> outResult, ScannerContext scannerContext) throws IOException {
    if (scannerContext == null) {
        throw new IllegalArgumentException("Scanner context cannot be null");
    }
    if (checkFlushed() && reopenAfterFlush()) {
        return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
    }
    // return.
    if (this.heap == null) {
        // By this time partial close should happened because already heap is null
        // Do all cleanup except heap.close()
        close(false);
        return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
    }
    Cell cell = this.heap.peek();
    if (cell == null) {
        // Do all cleanup except heap.close()
        close(false);
        return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
    }
    // comparison.
    if (!scannerContext.hasAnyLimit(LimitScope.BETWEEN_CELLS) || matcher.currentRow() == null) {
        this.countPerRow = 0;
        matcher.setToNewRow(cell);
    }
    // Clear progress away unless invoker has indicated it should be kept.
    if (!scannerContext.getKeepProgress()) {
        scannerContext.clearProgress();
    }
    int count = 0;
    long totalBytesRead = 0;
    // track the cells for metrics only if it is a user read request.
    boolean onlyFromMemstore = matcher.isUserScan();
    try {
        LOOP: do {
            // the shipped method below.
            if (kvsScanned % cellsPerHeartbeatCheck == 0 || (scanUsePread && readType == Scan.ReadType.DEFAULT && bytesRead > preadMaxBytes)) {
                if (scannerContext.checkTimeLimit(LimitScope.BETWEEN_CELLS)) {
                    return scannerContext.setScannerState(NextState.TIME_LIMIT_REACHED).hasMoreValues();
                }
            }
            // Do object compare - we set prevKV from the same heap.
            if (prevCell != cell) {
                ++kvsScanned;
            }
            checkScanOrder(prevCell, cell, comparator);
            int cellSize = PrivateCellUtil.estimatedSerializedSizeOf(cell);
            bytesRead += cellSize;
            if (scanUsePread && readType == Scan.ReadType.DEFAULT && bytesRead > preadMaxBytes) {
                // return immediately if we want to switch from pread to stream. We need this because we
                // can
                // only switch in the shipped method, if user use a filter to filter out everything and
                // rpc
                // timeout is very large then the shipped method will never be called until the whole scan
                // is finished, but at that time we have already scan all the data...
                // See HBASE-20457 for more details.
                // And there is still a scenario that can not be handled. If we have a very large row,
                // which
                // have millions of qualifiers, and filter.filterRow is used, then even if we set the flag
                // here, we still need to scan all the qualifiers before returning...
                scannerContext.returnImmediately();
            }
            prevCell = cell;
            scannerContext.setLastPeekedCell(cell);
            topChanged = false;
            ScanQueryMatcher.MatchCode qcode = matcher.match(cell);
            switch(qcode) {
                case INCLUDE:
                case INCLUDE_AND_SEEK_NEXT_ROW:
                case INCLUDE_AND_SEEK_NEXT_COL:
                    Filter f = matcher.getFilter();
                    if (f != null) {
                        cell = f.transformCell(cell);
                    }
                    this.countPerRow++;
                    // also update metric accordingly
                    if (this.countPerRow > storeOffset) {
                        outResult.add(cell);
                        // Update local tracking information
                        count++;
                        totalBytesRead += cellSize;
                        /**
                         * Increment the metric if all the cells are from memstore.
                         * If not we will account it for mixed reads
                         */
                        onlyFromMemstore = onlyFromMemstore && heap.isLatestCellFromMemstore();
                        // Update the progress of the scanner context
                        scannerContext.incrementSizeProgress(cellSize, cell.heapSize());
                        scannerContext.incrementBatchProgress(1);
                        if (matcher.isUserScan() && totalBytesRead > maxRowSize) {
                            String message = "Max row size allowed: " + maxRowSize + ", but the row is bigger than that, the row info: " + CellUtil.toString(cell, false) + ", already have process row cells = " + outResult.size() + ", it belong to region = " + store.getHRegion().getRegionInfo().getRegionNameAsString();
                            LOG.warn(message);
                            throw new RowTooBigException(message);
                        }
                        if (storeLimit > -1 && this.countPerRow >= (storeLimit + storeOffset)) {
                            // do what SEEK_NEXT_ROW does.
                            if (!matcher.moreRowsMayExistAfter(cell)) {
                                // Do all cleanup except heap.close()
                                close(false);
                                return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
                            }
                            matcher.clearCurrentRow();
                            seekToNextRow(cell);
                            break LOOP;
                        }
                    }
                    if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_ROW) {
                        if (!matcher.moreRowsMayExistAfter(cell)) {
                            // Do all cleanup except heap.close()
                            close(false);
                            return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
                        }
                        matcher.clearCurrentRow();
                        seekOrSkipToNextRow(cell);
                    } else if (qcode == ScanQueryMatcher.MatchCode.INCLUDE_AND_SEEK_NEXT_COL) {
                        seekOrSkipToNextColumn(cell);
                    } else {
                        this.heap.next();
                    }
                    if (scannerContext.checkBatchLimit(LimitScope.BETWEEN_CELLS)) {
                        break LOOP;
                    }
                    if (scannerContext.checkSizeLimit(LimitScope.BETWEEN_CELLS)) {
                        break LOOP;
                    }
                    continue;
                case DONE:
                    // Optimization for Gets! If DONE, no more to get on this row, early exit!
                    if (get) {
                        // Then no more to this row... exit.
                        // Do all cleanup except heap.close()
                        close(false);
                        // update metric
                        return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
                    }
                    matcher.clearCurrentRow();
                    return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
                case DONE_SCAN:
                    // Do all cleanup except heap.close()
                    close(false);
                    return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
                case SEEK_NEXT_ROW:
                    // us if there is an endKey in the scan.
                    if (!matcher.moreRowsMayExistAfter(cell)) {
                        // Do all cleanup except heap.close()
                        close(false);
                        return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
                    }
                    matcher.clearCurrentRow();
                    seekOrSkipToNextRow(cell);
                    NextState stateAfterSeekNextRow = needToReturn(outResult);
                    if (stateAfterSeekNextRow != null) {
                        return scannerContext.setScannerState(stateAfterSeekNextRow).hasMoreValues();
                    }
                    break;
                case SEEK_NEXT_COL:
                    seekOrSkipToNextColumn(cell);
                    NextState stateAfterSeekNextColumn = needToReturn(outResult);
                    if (stateAfterSeekNextColumn != null) {
                        return scannerContext.setScannerState(stateAfterSeekNextColumn).hasMoreValues();
                    }
                    break;
                case SKIP:
                    this.heap.next();
                    break;
                case SEEK_NEXT_USING_HINT:
                    Cell nextKV = matcher.getNextKeyHint(cell);
                    if (nextKV != null) {
                        int difference = comparator.compare(nextKV, cell);
                        if (((!scan.isReversed() && difference > 0) || (scan.isReversed() && difference < 0))) {
                            seekAsDirection(nextKV);
                            NextState stateAfterSeekByHint = needToReturn(outResult);
                            if (stateAfterSeekByHint != null) {
                                return scannerContext.setScannerState(stateAfterSeekByHint).hasMoreValues();
                            }
                            break;
                        }
                    }
                    heap.next();
                    break;
                default:
                    throw new RuntimeException("UNEXPECTED");
            }
        } while ((cell = this.heap.peek()) != null);
        if (count > 0) {
            return scannerContext.setScannerState(NextState.MORE_VALUES).hasMoreValues();
        }
        // No more keys
        // Do all cleanup except heap.close()
        close(false);
        return scannerContext.setScannerState(NextState.NO_MORE_VALUES).hasMoreValues();
    } finally {
        // increment only if we have some result
        if (count > 0 && matcher.isUserScan()) {
            // if true increment memstore metrics, if not the mixed one
            updateMetricsStore(onlyFromMemstore);
        }
    }
}
Also used : Filter(org.apache.hadoop.hbase.filter.Filter) NextState(org.apache.hadoop.hbase.regionserver.ScannerContext.NextState) Cell(org.apache.hadoop.hbase.Cell)

Aggregations

Cell (org.apache.hadoop.hbase.Cell)1 Filter (org.apache.hadoop.hbase.filter.Filter)1 NextState (org.apache.hadoop.hbase.regionserver.ScannerContext.NextState)1