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; 024import org.apache.hadoop.hbase.Cell; 025import org.apache.hadoop.hbase.CellUtil; 026import org.apache.yetus.audience.InterfaceAudience; 027 028/** 029 * A ScanResultCache that may return partial result. 030 * <p> 031 * As we can only scan from the starting of a row when error, so here we also implement the logic 032 * that skips the cells that have already been returned. 033 */ 034@InterfaceAudience.Private 035class AllowPartialScanResultCache implements ScanResultCache { 036 037 // used to filter out the cells that already returned to user as we always start from the 038 // beginning of a row when retry. 039 private Cell lastCell; 040 041 private boolean lastResultPartial; 042 043 private int numberOfCompleteRows; 044 045 private void recordLastResult(Result result) { 046 lastCell = result.rawCells()[result.rawCells().length - 1]; 047 lastResultPartial = result.mayHaveMoreCellsInRow(); 048 } 049 050 @Override 051 public Result[] addAndGet(Result[] results, boolean isHeartbeatMessage) throws IOException { 052 if (results.length == 0) { 053 if (!isHeartbeatMessage && lastResultPartial) { 054 // An empty non heartbeat result indicate that there must be a row change. So if the 055 // lastResultPartial is true then we need to increase numberOfCompleteRows. 056 numberOfCompleteRows++; 057 } 058 return EMPTY_RESULT_ARRAY; 059 } 060 int i; 061 for (i = 0; i < results.length; i++) { 062 Result r = filterCells(results[i], lastCell); 063 if (r != null) { 064 results[i] = r; 065 break; 066 } 067 } 068 if (i == results.length) { 069 return EMPTY_RESULT_ARRAY; 070 } 071 if (lastResultPartial && !CellUtil.matchingRows(lastCell, results[0].getRow())) { 072 // there is a row change, so increase numberOfCompleteRows 073 numberOfCompleteRows++; 074 } 075 recordLastResult(results[results.length - 1]); 076 if (i > 0) { 077 results = Arrays.copyOfRange(results, i, results.length); 078 } 079 for (Result result : results) { 080 if (!result.mayHaveMoreCellsInRow()) { 081 numberOfCompleteRows++; 082 } 083 } 084 return results; 085 } 086 087 @Override 088 public void clear() { 089 // we do not cache anything 090 } 091 092 @Override 093 public int numberOfCompleteRows() { 094 return numberOfCompleteRows; 095 } 096}