Index: src/java/org/apache/hadoop/hbase/HConstants.java =================================================================== --- src/java/org/apache/hadoop/hbase/HConstants.java (revision 894322) +++ src/java/org/apache/hadoop/hbase/HConstants.java (working copy) @@ -284,4 +284,18 @@ TABLE_SET_HTD, TABLE_SPLIT } + + /** + * Parameter name for maximum number of bytes returned when calling a + * scanner's next method. + */ + public static String HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY = "hbase.client.scanner.max.result.size"; + + /** + * Maximum number of bytes returned when calling a scanner's next method. + * Note that when a single row is larger than this limit the row is still + * returned completely. + */ + public static long DEFAULT_HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE = 1024 * 1024; + } Index: src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 894322) +++ src/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -160,6 +160,8 @@ private final int serverLeaseTimeout; protected final int numRegionsToReport; + + private final long maxScannerResultSize; // Remote HMaster private HMasterRegionInterface hbaseMaster; @@ -262,6 +264,10 @@ sleeper = new Sleeper(this.msgInterval, this.stopRequested); + this.maxScannerResultSize = conf.getLong( + HConstants.HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY, + HConstants.DEFAULT_HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE); + // Task thread to process requests from Master this.worker = new Worker(); @@ -1878,12 +1884,16 @@ } this.leases.renewLease(scannerName); List results = new ArrayList(); - for (int i = 0; i < nbRows; i++) { + long currentScanResultSize = 0; + for (int i = 0; i < nbRows && currentScanResultSize < maxScannerResultSize; i++) { requestCount.incrementAndGet(); // Collect values to be returned here List values = new ArrayList(); boolean moreRows = s.next(values); if (!values.isEmpty()) { + for (KeyValue kv : values) { + currentScanResultSize += kv.heapSize(); + } results.add(new Result(values)); } if (!moreRows) { Index: src/java/org/apache/hadoop/hbase/client/HTable.java =================================================================== --- src/java/org/apache/hadoop/hbase/client/HTable.java (revision 894322) +++ src/java/org/apache/hadoop/hbase/client/HTable.java (working copy) @@ -70,7 +70,8 @@ private boolean autoFlush; private long currentWriteBufferSize; protected int scannerCaching; - + private long maxScannerResultSize; + /** * Creates an object to access a HBase table * @@ -129,6 +130,9 @@ this.autoFlush = true; this.currentWriteBufferSize = 0; this.scannerCaching = conf.getInt("hbase.client.scanner.caching", 1); + this.maxScannerResultSize = conf.getLong( + HConstants.HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE_KEY, + HConstants.DEFAULT_HBASE_CLIENT_SCANNER_MAX_RESULT_SIZE); } /** @@ -1954,6 +1958,7 @@ } if (cache.size() == 0) { Result [] values = null; + long remainingResultSize = maxScannerResultSize; int countdown = this.caching; // We need to reset it if it's a new callable that was created // with a countdown in nextScanner @@ -2001,12 +2006,15 @@ if (values != null && values.length > 0) { for (Result rs : values) { cache.add(rs); + for (KeyValue kv : rs.raw()) { + remainingResultSize -= kv.heapSize(); + } countdown--; this.lastResult = rs; } } // Values == null means server-side filter has determined we must STOP - } while (countdown > 0 && nextScanner(countdown, values == null)); + } while (remainingResultSize > 0 && countdown > 0 && nextScanner(countdown, values == null)); } if (cache.size() > 0) {