001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.apache.hadoop.hbase.client.ConnectionUtils.filterCells;
021
022import java.io.IOException;
023import java.util.Arrays;
024
025import org.apache.hadoop.hbase.Cell;
026import org.apache.hadoop.hbase.CellUtil;
027import org.apache.yetus.audience.InterfaceAudience;
028
029/**
030 * A ScanResultCache that may return partial result.
031 * <p>
032 * As we can only scan from the starting of a row when error, so here we also implement the logic
033 * that skips the cells that have already been returned.
034 */
035@InterfaceAudience.Private
036class AllowPartialScanResultCache implements ScanResultCache {
037
038  // used to filter out the cells that already returned to user as we always start from the
039  // beginning of a row when retry.
040  private Cell lastCell;
041
042  private boolean lastResultPartial;
043
044  private int numberOfCompleteRows;
045
046  private void recordLastResult(Result result) {
047    lastCell = result.rawCells()[result.rawCells().length - 1];
048    lastResultPartial = result.mayHaveMoreCellsInRow();
049  }
050
051  @Override
052  public Result[] addAndGet(Result[] results, boolean isHeartbeatMessage) throws IOException {
053    if (results.length == 0) {
054      if (!isHeartbeatMessage && lastResultPartial) {
055        // An empty non heartbeat result indicate that there must be a row change. So if the
056        // lastResultPartial is true then we need to increase numberOfCompleteRows.
057        numberOfCompleteRows++;
058      }
059      return EMPTY_RESULT_ARRAY;
060    }
061    int i;
062    for (i = 0; i < results.length; i++) {
063      Result r = filterCells(results[i], lastCell);
064      if (r != null) {
065        results[i] = r;
066        break;
067      }
068    }
069    if (i == results.length) {
070      return EMPTY_RESULT_ARRAY;
071    }
072    if (lastResultPartial && !CellUtil.matchingRows(lastCell, results[0].getRow())) {
073      // there is a row change, so increase numberOfCompleteRows
074      numberOfCompleteRows++;
075    }
076    recordLastResult(results[results.length - 1]);
077    if (i > 0) {
078      results = Arrays.copyOfRange(results, i, results.length);
079    }
080    for (Result result : results) {
081      if (!result.mayHaveMoreCellsInRow()) {
082        numberOfCompleteRows++;
083      }
084    }
085    return results;
086  }
087
088  @Override
089  public void clear() {
090    // we do not cache anything
091  }
092
093  @Override
094  public int numberOfCompleteRows() {
095    return numberOfCompleteRows;
096  }
097}