Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1411532) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3412,6 +3412,10 @@ this(scan, null); } + @Override + public long getReadPt() { + return this.readPt; + } /** * Reset both the filter and the old filter. */ @@ -3442,22 +3446,28 @@ // This could be a new thread from the last time we called next(). MultiVersionConsistencyControl.setThreadReadPoint(this.readPt); - results.clear(); - - boolean returnResult = nextInternal(limit, metric); - - outResults.addAll(results); - resetFilters(); - if (isFilterDone()) { - return false; - } - return returnResult; + return nextInternal(outResults, limit, metric); } finally { closeRegionOperation(); } } @Override + public synchronized boolean nextInternal(List outResults, int limit, + String metric) throws IOException { + results.clear(); + + boolean returnResult = nextInternal(limit, metric); + + outResults.addAll(results); + resetFilters(); + if (isFilterDone()) { + return false; + } + return returnResult; + } + + @Override public synchronized boolean next(List outResults) throws IOException { // apply the batching limit by default @@ -5120,7 +5130,7 @@ * Acquires a read lock and checks if the region is closing or closed. * @throws NotServingRegionException when the region is closing or closed */ - private void startRegionOperation() throws NotServingRegionException { + public void startRegionOperation() throws NotServingRegionException { if (this.closing.get()) { throw new NotServingRegionException(regionInfo.getRegionNameAsString() + " is closing"); @@ -5137,7 +5147,7 @@ * Closes the lock. This needs to be called in the finally block corresponding * to the try block of #startRegionOperation */ - private void closeRegionOperation(){ + public void closeRegionOperation(){ lock.readLock().unlock(); } Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1411532) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -165,6 +165,7 @@ import org.apache.hadoop.util.StringUtils; import org.apache.zookeeper.KeeperException; import org.codehaus.jackson.map.ObjectMapper; +import org.joda.time.field.MillisDurationField; import com.google.common.base.Function; import com.google.common.collect.Lists; @@ -2430,23 +2431,29 @@ } } - for (int i = 0; i < nbRows - && currentScanResultSize < maxScannerResultSize; i++) { - requestCount.incrementAndGet(); - // Collect values to be returned here - boolean moreRows = s.next(values, SchemaMetrics.METRIC_NEXTSIZE); - if (!values.isEmpty()) { - for (KeyValue kv : values) { - currentScanResultSize += kv.heapSize(); + MultiVersionConsistencyControl.setThreadReadPoint(s.getReadPt()); + region.startRegionOperation(); + try { + for (int i = 0; i < nbRows + && currentScanResultSize < maxScannerResultSize; i++) { + requestCount.incrementAndGet(); + // Collect values to be returned here + boolean moreRows = s.nextInternal(values, -1, SchemaMetrics.METRIC_NEXTSIZE); + if (!values.isEmpty()) { + for (KeyValue kv : values) { + currentScanResultSize += kv.heapSize(); + } + results.add(new Result(values)); } - results.add(new Result(values)); + if (!moreRows) { + break; + } + values.clear(); } - if (!moreRows) { - break; - } - values.clear(); + region.readRequestsCount.add(results.size()); + } finally { + region.closeRegionOperation(); } - // coprocessor postNext hook if (region != null && region.getCoprocessorHost() != null) { region.getCoprocessorHost().postScannerNext(s, results, nbRows, true); Index: src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java (revision 1411532) +++ src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java (working copy) @@ -20,7 +20,10 @@ package org.apache.hadoop.hbase.regionserver; import java.io.IOException; +import java.util.List; + import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.KeyValue; /** * RegionScanner describes iterators over rows in an HRegion. @@ -49,4 +52,20 @@ */ public boolean reseek(byte[] row) throws IOException; + /** + * @return The Scanner's readPt + */ + public long getReadPt(); + + /** + * Grab the next row's worth of values with a limit on the number of values + * to return. + * This is a special method to be called from coprocessor hooks to avoid expensive setup + * @param result return output array + * @param limit limit on row count to get + * @param metric the metric name + * @return true if more rows exist after this one, false if scanner is done + * @throws IOException e + */ + public boolean nextInternal(List result, int limit, String metric) throws IOException; } Index: src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java (revision 1411532) +++ src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java (working copy) @@ -85,6 +85,12 @@ } @Override + public boolean nextInternal(List result, int limit, String metric) + throws IOException { + return delegate.nextInternal(result, limit, metric); + } + + @Override public void close() throws IOException { delegate.close(); } @@ -104,6 +110,10 @@ return false; } + @Override + public long getReadPt() { + return delegate.getReadPt(); + } } public static class CoprocessorImpl extends BaseRegionObserver {