@Override
  public Result[] addAndGet(Result[] results, boolean isHeartbeatMessage) throws IOException {
    if (results.length == 0) {
      if (!isHeartbeatMessage) {
        if (!partialResults.isEmpty()) {
          return new Result[] { createCompletedResult() };
        }
        if (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;
    }
    List<Result> regroupedResults = new ArrayList<>();
    for (Result result : results) {
      result = filterCells(result, lastCell);
      if (result == null) {
        continue;
      }
      if (!partialResults.isEmpty()) {
        if (!Bytes.equals(partialResults.peek().getRow(), result.getRow())) {
          // there is a row change
          regroupedResults.add(createCompletedResult());
        }
      } else if (lastResultPartial && !CellUtil.matchingRows(lastCell, result.getRow())) {
        // As for batched scan we may return partial results to user if we reach the batch limit, so
        // here we need to use lastCell to determine if there is row change and increase
        // numberOfCompleteRows.
        numberOfCompleteRows++;
      }
      // check if we have a row change
      if (
        !partialResults.isEmpty() && !Bytes.equals(partialResults.peek().getRow(), result.getRow())
      ) {
        regroupedResults.add(createCompletedResult());
      }
      Result regroupedResult = regroupResults(result);
      if (regroupedResult != null) {
        if (!regroupedResult.mayHaveMoreCellsInRow()) {
          numberOfCompleteRows++;
        }
        regroupedResults.add(regroupedResult);
        // only update last cell when we actually return it to user.
        recordLastResult(regroupedResult);
      }
      if (!result.mayHaveMoreCellsInRow() && !partialResults.isEmpty()) {
        // We are done for this row
        regroupedResults.add(createCompletedResult());
      }
    }
    return regroupedResults.toArray(new Result[0]);
  }
A scan result cache for batched scan, i.e,
{@code scan.getBatch() > 0 && !scan.getAllowPartialResults()}.
<p>
If user setBatch(5) and rpc returns 3+5+5+5+3 cells, we should return 5+5+5+5+1 to user. setBatch
doesn't mean setAllowPartialResult(true).
@since 2.0.0
hbase-client/src/main/java/org/apache/hadoop/hbase/client/BatchScanResultCache.java