Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1434509) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3520,7 +3520,6 @@ private final KeyValue KV_LIMIT = new KeyValue(); private final byte [] stopRow; private Filter filter; - private List results = new ArrayList(); private int batch; private int isScan; private boolean filterClosed = false; @@ -3635,11 +3634,16 @@ @Override public boolean nextRaw(List outResults, int limit, String metric) throws IOException { - results.clear(); - - boolean returnResult = nextInternal(limit, metric); - - outResults.addAll(results); + boolean returnResult; + if (outResults.isEmpty()) { + // Usually outResults is empty. This is true when next is called + // to handle scan or get operation. + returnResult = nextInternal(outResults, limit, metric); + } else { + List tmpList = new ArrayList(); + returnResult = nextInternal(tmpList, limit, metric); + outResults.addAll(tmpList); + } resetFilters(); if (isFilterDone()) { return false; @@ -3661,10 +3665,12 @@ return next(outResults, batch, metric); } - private void populateFromJoinedHeap(int limit, String metric) throws IOException { + private void populateFromJoinedHeap(List results, int limit, String metric) + throws IOException { assert joinedContinuationRow != null; - KeyValue kv = populateResult(this.joinedHeap, limit, joinedContinuationRow.getBuffer(), - joinedContinuationRow.getRowOffset(), joinedContinuationRow.getRowLength(), metric); + KeyValue kv = populateResult(results, this.joinedHeap, limit, + joinedContinuationRow.getBuffer(), joinedContinuationRow.getRowOffset(), + joinedContinuationRow.getRowLength(), metric); if (kv != KV_LIMIT) { // We are done with this row, reset the continuation. joinedContinuationRow = null; @@ -3676,6 +3682,7 @@ /** * Fetches records with this row into result list, until next row or limit (if not -1). + * @param results * @param heap KeyValueHeap to fetch data from. It must be positioned on correct row before call. * @param limit Max amount of KVs to place in result list, -1 means no limit. * @param currentRow Byte array with key we are fetching. @@ -3684,8 +3691,8 @@ * @param metric Metric key to be passed into KeyValueHeap::next(). * @return true if limit reached, false otherwise. */ - private KeyValue populateResult(KeyValueHeap heap, int limit, byte[] currentRow, int offset, - short length, String metric) throws IOException { + private KeyValue populateResult(List results, KeyValueHeap heap, int limit, + byte[] currentRow, int offset, short length, String metric) throws IOException { KeyValue nextKv; do { heap.next(results, limit - results.size(), metric); @@ -3704,7 +3711,11 @@ return this.filter != null && this.filter.filterAllRemaining(); } - private boolean nextInternal(int limit, String metric) throws IOException { + private boolean nextInternal(List results, int limit, String metric) + throws IOException { + if (!results.isEmpty()) { + throw new IllegalArgumentException("First parameter should be an empty list"); + } RpcCallContext rpcCall = HBaseServer.getCurrentCall(); // The loop here is used only when at some point during the next we determine // that due to effects of filters or otherwise, we have an empty row in the result. @@ -3750,11 +3761,13 @@ // Techically, if we hit limits before on this row, we don't need this call. if (filterRowKey(currentRow, offset, length)) { nextRow(currentRow, offset, length); + results.clear(); continue; } // Ok, we are good, let's try to get some results from the main heap. - KeyValue nextKv = populateResult(this.storeHeap, limit, currentRow, offset, length, metric); + KeyValue nextKv = populateResult(results, this.storeHeap, limit, currentRow, + offset, length, metric); if (nextKv == KV_LIMIT) { if (this.filter != null && filter.hasFilterRow()) { throw new IncompatibleFilterException( @@ -3773,13 +3786,8 @@ } if (isEmptyRow || filterRow()) { - // this seems like a redundant step - we already consumed the row - // there're no left overs. - // the reasons for calling this method are: - // 1. reset the filters. - // 2. provide a hook to fast forward the row (used by subclasses) nextRow(currentRow, offset, length); - + results.clear(); // This row was totally filtered out, if this is NOT the last row, // we should continue on. Otherwise, nothing else to do. if (!stopRow) continue; @@ -3799,12 +3807,12 @@ || this.joinedHeap.seek(KeyValue.createFirstOnRow(currentRow, offset, length)); if (mayHaveData) { joinedContinuationRow = current; - populateFromJoinedHeap(limit, metric); + populateFromJoinedHeap(results, limit, metric); } } } else { // Populating from the joined map was stopped by limits, populate some more. - populateFromJoinedHeap(limit, metric); + populateFromJoinedHeap(results, limit, metric); } // We may have just called populateFromJoinedMap and hit the limits. If that is @@ -3840,7 +3848,6 @@ while((next = this.storeHeap.peek()) != null && next.matchingRow(currentRow, offset, length)) { this.storeHeap.next(MOCKED_LIST); } - results.clear(); resetFilters(); } Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1434509) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -2457,8 +2457,10 @@ results, nbRows); if (!results.isEmpty()) { for (Result r : results) { - for (KeyValue kv : r.raw()) { - currentScanResultSize += kv.heapSize(); + if (maxScannerResultSize < Long.MAX_VALUE){ + for (KeyValue kv : r.raw()) { + currentScanResultSize += kv.heapSize(); + } } } } @@ -2478,8 +2480,10 @@ // Collect values to be returned here boolean moreRows = s.nextRaw(values, SchemaMetrics.METRIC_NEXTSIZE); if (!values.isEmpty()) { - for (KeyValue kv : values) { - currentScanResultSize += kv.heapSize(); + if (maxScannerResultSize < Long.MAX_VALUE){ + for (KeyValue kv : values) { + currentScanResultSize += kv.heapSize(); + } } results.add(new Result(values)); }