@Override
  public Result[] addAndGet(Result[] results, boolean isHeartbeatMessage) throws IOException {
    if (results.length == 0) {
      if (!isHeartbeatMessage && lastResultPartial) {
        // An empty non heartbeat result indicate that there must be a row change. So if the
        // lastResultPartial is true then we need to increase numberOfCompleteRows.
        numberOfCompleteRows++;
      }
      return EMPTY_RESULT_ARRAY;
    }
    int i;
    for (i = 0; i < results.length; i++) {
      Result r = filterCells(results[i], lastCell);
      if (r != null) {
        results[i] = r;
        break;
      }
    }
    if (i == results.length) {
      return EMPTY_RESULT_ARRAY;
    }
    if (lastResultPartial && !CellUtil.matchingRows(lastCell, results[0].getRow())) {
      // there is a row change, so increase numberOfCompleteRows
      numberOfCompleteRows++;
    }
    recordLastResult(results[results.length - 1]);
    if (i > 0) {
      results = Arrays.copyOfRange(results, i, results.length);
    }
    for (Result result : results) {
      if (!result.mayHaveMoreCellsInRow()) {
        numberOfCompleteRows++;
      }
    }
    return results;
  }
A ScanResultCache that may return partial result.
<p>
As we can only scan from the starting of a row when error, so here we also implement the logic
that skips the cells that have already been returned.
hbase-client/src/main/java/org/apache/hadoop/hbase/client/AllowPartialScanResultCache.java