Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (revision 1326084) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java (working copy) @@ -3274,6 +3274,7 @@ private int isScan; private boolean filterClosed = false; private long readPt; + private long maxBufferSize; public HRegionInfo getRegionInfo() { return regionInfo; @@ -3281,6 +3282,7 @@ RegionScannerImpl(Scan scan, List additionalScanners) throws IOException { //DebugPrint.println("HRegionScanner."); + this.maxBufferSize = scan.getMaxBufferSize(); this.filter = scan.getFilter(); this.batch = scan.getBatch(); if (Bytes.equals(scan.getStopRow(), HConstants.EMPTY_END_ROW)) { @@ -3323,6 +3325,11 @@ RegionScannerImpl(Scan scan) throws IOException { this(scan, null); } + + @Override + public long getMaxBufferSize() { + return maxBufferSize; + } /** * Reset both the filter and the old filter. Index: src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java (revision 1326084) +++ src/main/java/org/apache/hadoop/hbase/regionserver/RegionScanner.java (working copy) @@ -21,6 +21,7 @@ import java.io.IOException; import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.client.Scan; /** * RegionScanner describes iterators over rows in an HRegion. @@ -49,4 +50,8 @@ */ public boolean reseek(byte[] row) throws IOException; + /** + * @return The preferred max buffersize that is set on the scan. See {@link Scan#setMaxBufferSize(long)} + */ + public long getMaxBufferSize(); } Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1326084) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -2390,9 +2390,14 @@ : results.toArray(new Result[0]); } } - + long maxBufferSize; + if (s.getMaxBufferSize() > -1) { + maxBufferSize = s.getMaxBufferSize(); + } else { + maxBufferSize = maxScannerResultSize; + } for (int i = 0; i < nbRows - && currentScanResultSize < maxScannerResultSize; i++) { + && currentScanResultSize < maxBufferSize; i++) { requestCount.incrementAndGet(); // Collect values to be returned here boolean moreRows = s.next(values); Index: src/main/java/org/apache/hadoop/hbase/client/Scan.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/Scan.java (revision 1326084) +++ src/main/java/org/apache/hadoop/hbase/client/Scan.java (working copy) @@ -52,7 +52,11 @@ *

* To modify scanner caching for just this scan, use {@link #setCaching(int) setCaching}. * If caching is NOT set, we will use the caching value of the hosting - * {@link HTable}. See {@link HTable#setScannerCaching(int)}. + * {@link HTable}. See {@link HTable#setScannerCaching(int)}. In addition to + * row caching, it is possible to specify a maximum buffer size, using + * {@link #setMaxBufferSize(long) setMaxBufferSize}. When both are used, single + * server requests are limited by either number of rows or maximum buffer size, + * whichever limit comes first. *

* To further define the scope of what to get when scanning, perform additional * methods as outlined below. @@ -84,7 +88,7 @@ private static final String RAW_ATTR = "_raw_"; private static final String ISOLATION_LEVEL = "_isolationlevel_"; - private static final byte SCAN_VERSION = (byte)2; + private static final byte SCAN_VERSION = (byte)3; private byte [] startRow = HConstants.EMPTY_START_ROW; private byte [] stopRow = HConstants.EMPTY_END_ROW; private int maxVersions = 1; @@ -100,6 +104,7 @@ * -1 means no caching */ private int caching = -1; + private long maxBufferSize = -1; private boolean cacheBlocks = true; private Filter filter = null; private TimeRange tr = new TimeRange(); @@ -149,6 +154,7 @@ maxVersions = scan.getMaxVersions(); batch = scan.getBatch(); caching = scan.getCaching(); + maxBufferSize = scan.getMaxBufferSize(); cacheBlocks = scan.getCacheBlocks(); filter = scan.getFilter(); // clone? TimeRange ctr = scan.getTimeRange(); @@ -321,6 +327,25 @@ public void setCaching(int caching) { this.caching = caching; } + + /** + * @return the maximum buffer size in bytes. Also see + * {@link #setMaxBufferSize(int)} + */ + public long getMaxBufferSize() { + return maxBufferSize; + } + + /** + * Set the maximum buffer size. The default is -1; this means that no specific + * maximum buffer size will be set for this scan, and the global configured + * value will be used instead. (Defaults to unlimited). + * + * @param maxBufferSize The maximum buffer size in bytes. + */ + public void setMaxBufferSize(long maxBufferSize) { + this.maxBufferSize = maxBufferSize; + } /** * Apply the specified server-side filter when performing the Scan. @@ -500,6 +525,7 @@ map.put("maxVersions", this.maxVersions); map.put("batch", this.batch); map.put("caching", this.caching); + map.put("maxBufferSize", this.maxBufferSize); map.put("cacheBlocks", this.cacheBlocks); List timeRange = new ArrayList(); timeRange.add(this.tr.getMin()); @@ -582,6 +608,9 @@ if (version > 1) { readAttributes(in); } + if (version > 2) { + this.maxBufferSize = in.readLong(); + } } public void write(final DataOutput out) @@ -615,6 +644,7 @@ } } writeAttributes(out); + out.writeLong(maxBufferSize); } /** Index: src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java (revision 1326084) +++ src/test/java/org/apache/hadoop/hbase/coprocessor/TestCoprocessorInterface.java (working copy) @@ -89,6 +89,11 @@ return false; } + @Override + public long getMaxBufferSize() { + return delegate.getMaxBufferSize(); + } + } public static class CoprocessorImpl extends BaseRegionObserver {