HBASE-26688 Threads shared EMPTY_RESULT may lead to unexpected client job down. ...
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / client / AllowPartialScanResultCache.java
blob8d21994c23e0fb895525605c1ed8d0572791270c
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.client;
20 import static org.apache.hadoop.hbase.client.ConnectionUtils.filterCells;
22 import java.io.IOException;
23 import java.util.Arrays;
25 import org.apache.hadoop.hbase.Cell;
26 import org.apache.hadoop.hbase.CellUtil;
27 import org.apache.yetus.audience.InterfaceAudience;
29 /**
30 * A ScanResultCache that may return partial result.
31 * <p>
32 * As we can only scan from the starting of a row when error, so here we also implement the logic
33 * that skips the cells that have already been returned.
35 @InterfaceAudience.Private
36 class AllowPartialScanResultCache implements ScanResultCache {
38 // used to filter out the cells that already returned to user as we always start from the
39 // beginning of a row when retry.
40 private Cell lastCell;
42 private boolean lastResultPartial;
44 private int numberOfCompleteRows;
46 private void recordLastResult(Result result) {
47 lastCell = result.rawCells()[result.rawCells().length - 1];
48 lastResultPartial = result.mayHaveMoreCellsInRow();
51 @Override
52 public Result[] addAndGet(Result[] results, boolean isHeartbeatMessage) throws IOException {
53 if (results.length == 0) {
54 if (!isHeartbeatMessage && lastResultPartial) {
55 // An empty non heartbeat result indicate that there must be a row change. So if the
56 // lastResultPartial is true then we need to increase numberOfCompleteRows.
57 numberOfCompleteRows++;
59 return EMPTY_RESULT_ARRAY;
61 int i;
62 for (i = 0; i < results.length; i++) {
63 Result r = filterCells(results[i], lastCell);
64 if (r != null) {
65 results[i] = r;
66 break;
69 if (i == results.length) {
70 return EMPTY_RESULT_ARRAY;
72 if (lastResultPartial && !CellUtil.matchingRows(lastCell, results[0].getRow())) {
73 // there is a row change, so increase numberOfCompleteRows
74 numberOfCompleteRows++;
76 recordLastResult(results[results.length - 1]);
77 if (i > 0) {
78 results = Arrays.copyOfRange(results, i, results.length);
80 for (Result result : results) {
81 if (!result.mayHaveMoreCellsInRow()) {
82 numberOfCompleteRows++;
85 return results;
88 @Override
89 public void clear() {
90 // we do not cache anything
93 @Override
94 public int numberOfCompleteRows() {
95 return numberOfCompleteRows;