Skip to content

Commit 786f2b4

Browse files
committed
HBASE-27570 Unify tracking of block IO across all read request types
1 parent 8e72cc6 commit 786f2b4

File tree

3 files changed

+29
-55
lines changed

3 files changed

+29
-55
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.net.BindException;
2525
import java.net.InetAddress;
2626
import java.net.InetSocketAddress;
27-
import java.nio.ByteBuffer;
2827
import java.util.ArrayList;
2928
import java.util.Arrays;
3029
import java.util.Collections;
@@ -45,7 +44,6 @@
4544
import org.apache.hadoop.conf.Configuration;
4645
import org.apache.hadoop.fs.FileSystem;
4746
import org.apache.hadoop.fs.Path;
48-
import org.apache.hadoop.hbase.ByteBufferExtendedCell;
4947
import org.apache.hadoop.hbase.CacheEvictionStats;
5048
import org.apache.hadoop.hbase.CacheEvictionStatsBuilder;
5149
import org.apache.hadoop.hbase.Cell;
@@ -710,7 +708,6 @@ private List<CellScannable> doNonAtomicRegionMutation(final HRegion region,
710708
List<ClientProtos.Action> mutations = null;
711709
long maxQuotaResultSize = Math.min(maxScannerResultSize, quota.getReadAvailable());
712710
IOException sizeIOE = null;
713-
Object lastBlock = null;
714711
ClientProtos.ResultOrException.Builder resultOrExceptionBuilder =
715712
ResultOrException.newBuilder();
716713
boolean hasResultOrException = false;
@@ -835,7 +832,7 @@ private List<CellScannable> doNonAtomicRegionMutation(final HRegion region,
835832
} else {
836833
pbResult = ProtobufUtil.toResult(r);
837834
}
838-
lastBlock = addSize(context, r, lastBlock);
835+
addSize(context, r);
839836
hasResultOrException = true;
840837
resultOrExceptionBuilder.setResult(pbResult);
841838
}
@@ -1293,44 +1290,17 @@ long getScannerVirtualTime(long scannerId) {
12931290
}
12941291

12951292
/**
1296-
* Method to account for the size of retained cells and retained data blocks.
1297-
* @param context rpc call context
1298-
* @param r result to add size.
1299-
* @param lastBlock last block to check whether we need to add the block size in context.
1293+
* Method to account for the size of retained cells.
1294+
* @param context rpc call context
1295+
* @param r result to add size.
13001296
* @return an object that represents the last referenced block from this response.
13011297
*/
1302-
Object addSize(RpcCallContext context, Result r, Object lastBlock) {
1298+
void addSize(RpcCallContext context, Result r) {
13031299
if (context != null && r != null && !r.isEmpty()) {
13041300
for (Cell c : r.rawCells()) {
13051301
context.incrementResponseCellSize(PrivateCellUtil.estimatedSerializedSizeOf(c));
1306-
1307-
// Since byte buffers can point all kinds of crazy places it's harder to keep track
1308-
// of which blocks are kept alive by what byte buffer.
1309-
// So we make a guess.
1310-
if (c instanceof ByteBufferExtendedCell) {
1311-
ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) c;
1312-
ByteBuffer bb = bbCell.getValueByteBuffer();
1313-
if (bb != lastBlock) {
1314-
context.incrementResponseBlockSize(bb.capacity());
1315-
lastBlock = bb;
1316-
}
1317-
} else {
1318-
// We're using the last block being the same as the current block as
1319-
// a proxy for pointing to a new block. This won't be exact.
1320-
// If there are multiple gets that bounce back and forth
1321-
// Then it's possible that this will over count the size of
1322-
// referenced blocks. However it's better to over count and
1323-
// use two rpcs than to OOME the regionserver.
1324-
byte[] valueArray = c.getValueArray();
1325-
if (valueArray != lastBlock) {
1326-
context.incrementResponseBlockSize(valueArray.length);
1327-
lastBlock = valueArray;
1328-
}
1329-
}
1330-
13311302
}
13321303
}
1333-
return lastBlock;
13341304
}
13351305

13361306
/** Returns Remote client's ip and port else null if can't be determined. */
@@ -2515,7 +2485,7 @@ public GetResponse get(final RpcController controller, final GetRequest request)
25152485
pbr = ProtobufUtil.toResultNoData(r);
25162486
((HBaseRpcController) controller)
25172487
.setCellScanner(CellUtil.createCellScanner(r.rawCells()));
2518-
addSize(context, r, null);
2488+
addSize(context, r);
25192489
} else {
25202490
pbr = ProtobufUtil.toResult(r);
25212491
}
@@ -2957,7 +2927,7 @@ public MutateResponse mutate(final RpcController rpcc, final MutateRequest reque
29572927
boolean clientCellBlockSupported = isClientCellBlockSupport(context);
29582928
addResult(builder, result.getResult(), controller, clientCellBlockSupported);
29592929
if (clientCellBlockSupported) {
2960-
addSize(context, result.getResult(), null);
2930+
addSize(context, result.getResult());
29612931
}
29622932
} else {
29632933
Result r = null;
@@ -2989,7 +2959,7 @@ public MutateResponse mutate(final RpcController rpcc, final MutateRequest reque
29892959
boolean clientCellBlockSupported = isClientCellBlockSupport(context);
29902960
addResult(builder, r, controller, clientCellBlockSupported);
29912961
if (clientCellBlockSupported) {
2992-
addSize(context, r, null);
2962+
addSize(context, r);
29932963
}
29942964
}
29952965
return builder.build();
@@ -3343,9 +3313,10 @@ private void scan(HBaseRpcController controller, ScanRequest request, RegionScan
33433313
// of heap size occupied by cells(being read). Cell data means its key and value parts.
33443314
// maxQuotaResultSize - max results just from server side configuration and quotas, without
33453315
// user's specified max. We use this for evaluating limits based on blocks (not cells).
3346-
// We may have accumulated some results in coprocessor preScannerNext call. We estimate
3347-
// block and cell size of those using call to addSize. Update our maximums for scanner
3348-
// context so we can account for them in the real scan.
3316+
// We may have accumulated some results in coprocessor preScannerNext call. Subtract any
3317+
// cell or block size from maximum here so we adhere to total limits of request.
3318+
// Note: we track block size in StoreScanner. If the CP hook got cells from hbase, it will
3319+
// have accumulated block bytes. If not, this will be 0 for block size.
33493320
long maxCellSize = maxResultSize;
33503321
long maxBlockSize = maxQuotaResultSize;
33513322
if (rpcCall != null) {
@@ -3461,7 +3432,6 @@ private void scan(HBaseRpcController controller, ScanRequest request, RegionScan
34613432
values.clear();
34623433
}
34633434
if (rpcCall != null) {
3464-
rpcCall.incrementResponseBlockSize(scannerContext.getBlockSizeProgress());
34653435
rpcCall.incrementResponseCellSize(scannerContext.getHeapSizeProgress());
34663436
}
34673437
builder.setMoreResultsInRegion(moreRows);
@@ -3634,18 +3604,11 @@ public ScanResponse scan(final RpcController controller, final ScanRequest reque
36343604
if (region.getCoprocessorHost() != null) {
36353605
Boolean bypass = region.getCoprocessorHost().preScannerNext(scanner, results, rows);
36363606
if (!results.isEmpty()) {
3637-
// If scanner CP added results to list, we want to account for cell and block size of
3638-
// that work. We estimate this using addSize, since CP does not get ScannerContext. If
3639-
// !done, the actual scan call below will use more accurate ScannerContext block and
3640-
// cell size tracking for the rest of the request. The two result sets will be added
3641-
// together in the RpcCall accounting.
3642-
// This here is just an estimate (see addSize for more details on estimation). We don't
3643-
// pass lastBlock to the scan call below because the real scan uses ScannerContext,
3644-
// which does not use lastBlock tracking. This may result in over counting by 1 block,
3645-
// but that is unlikely since addSize is already a rough estimate.
3646-
Object lastBlock = null;
36473607
for (Result r : results) {
3648-
lastBlock = addSize(rpcCall, r, lastBlock);
3608+
// add cell size from CP results so we can track response size and update limits
3609+
// when calling scan below if !done. We'll also have tracked block size if the CP
3610+
// got results from hbase, since StoreScanner tracks that for all calls automatically.
3611+
addSize(rpcCall, r);
36493612
}
36503613
}
36513614
if (bypass != null && bypass.booleanValue()) {

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreScanner.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.ArrayList;
2323
import java.util.List;
2424
import java.util.NavigableSet;
25+
import java.util.Optional;
2526
import java.util.concurrent.CountDownLatch;
2627
import java.util.concurrent.locks.ReentrantLock;
2728
import org.apache.hadoop.hbase.Cell;
@@ -36,6 +37,8 @@
3637
import org.apache.hadoop.hbase.client.Scan;
3738
import org.apache.hadoop.hbase.executor.ExecutorService;
3839
import org.apache.hadoop.hbase.filter.Filter;
40+
import org.apache.hadoop.hbase.ipc.RpcCall;
41+
import org.apache.hadoop.hbase.ipc.RpcServer;
3942
import org.apache.hadoop.hbase.regionserver.ScannerContext.LimitScope;
4043
import org.apache.hadoop.hbase.regionserver.ScannerContext.NextState;
4144
import org.apache.hadoop.hbase.regionserver.handler.ParallelSeekHandler;
@@ -573,6 +576,9 @@ public boolean next(List<Cell> outResult, ScannerContext scannerContext) throws
573576
scannerContext.clearProgress();
574577
}
575578

579+
Optional<RpcCall> rpcCall =
580+
matcher.isUserScan() ? RpcServer.getCurrentCall() : Optional.empty();
581+
576582
int count = 0;
577583
long totalBytesRead = 0;
578584
// track the cells for metrics only if it is a user read request.
@@ -613,7 +619,12 @@ public boolean next(List<Cell> outResult, ScannerContext scannerContext) throws
613619
scannerContext.returnImmediately();
614620
}
615621

616-
heap.recordBlockSize(scannerContext::incrementBlockProgress);
622+
heap.recordBlockSize(blockSize -> {
623+
if (rpcCall.isPresent()) {
624+
rpcCall.get().incrementResponseBlockSize(blockSize);
625+
}
626+
scannerContext.incrementBlockProgress(blockSize);
627+
});
617628

618629
prevCell = cell;
619630
scannerContext.setLastPeekedCell(cell);

hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestMultiRespectsLimits.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class TestMultiRespectsLimits {
6262
private static final MetricsAssertHelper METRICS_ASSERT =
6363
CompatibilityFactory.getInstance(MetricsAssertHelper.class);
6464
private final static byte[] FAMILY = Bytes.toBytes("D");
65-
public static final int MAX_SIZE = 100;
65+
public static final int MAX_SIZE = 50;
6666
private static String LOG_LEVEL;
6767

6868
@Rule

0 commit comments

Comments
 (0)