You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by rm...@apache.org on 2026/10/09 12:46:51 UTC
(hbase) 01/01: HBASE-30467 Exempt scanner close requests from quotas (#8749) (#8751)
This is an automated email from the ASF dual-hosted git repository.
rmdmattingly pushed a commit to branch HBASE-30467-branch-2.6
in repository https://gitbox.apache.org/repos/asf/hbase.git
commit eb9bb5e531bfc215627b627cc026b2a6dae07814
Author: Ray Mattingly <rm...@apache.org>
AuthorDate: Fri Oct 9 08:44:34 2026 -0400
HBASE-30467 Exempt scanner close requests from quotas (#8749) (#8751)
Signed-off-by: Ray Mattingly <rm...@apache.org>
Co-authored-by: Ma Zhengxuan <49...@users.noreply.github.com>
---
.../hbase/quotas/RegionServerRpcQuotaManager.java | 6 +++
.../hadoop/hbase/quotas/TestAtomicReadQuota.java | 48 ++++++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
index 34fc57cb081..b2716c50e14 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
@@ -181,6 +181,12 @@ public class RegionServerRpcQuotaManager implements RpcQuotaManager, Configurati
final ClientProtos.ScanRequest scanRequest, long maxScannerResultSize,
long maxBlockBytesScanned, long prevBlockBytesScannedDifference)
throws IOException, RpcThrottlingException {
+ if (
+ scanRequest.hasScannerId() && scanRequest.getCloseScanner()
+ && scanRequest.getNumberOfRows() == 0 && !scanRequest.getRenew()
+ ) {
+ return NoopOperationQuota.get();
+ }
Optional<User> user = RpcServer.getRequestUser();
UserGroupInformation ugi;
if (user.isPresent()) {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestAtomicReadQuota.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestAtomicReadQuota.java
index 7b3b73895bb..b66d427517b 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestAtomicReadQuota.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestAtomicReadQuota.java
@@ -17,6 +17,10 @@
*/
package org.apache.hadoop.hbase.quotas;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -33,7 +37,10 @@ import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
import org.apache.hadoop.hbase.client.RowMutations;
+import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.ipc.HBaseRpcControllerImpl;
+import org.apache.hadoop.hbase.regionserver.RSRpcServices;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
@@ -46,6 +53,11 @@ import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
+
+import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse;
+
@Tag(RegionServerTests.TAG)
@Tag(MediumTests.TAG)
public class TestAtomicReadQuota {
@@ -76,6 +88,42 @@ public class TestAtomicReadQuota {
TEST_UTIL.waitTableAvailable(TABLE_NAME);
}
+ @Test
+ public void testCloseScannerWhenReadQuotaIsExhausted() throws Exception {
+ setupGenericQuota();
+ try {
+ RSRpcServices rpcServices = TEST_UTIL.getHBaseCluster().getRegionServer(0).getRSRpcServices();
+ int scannerCount = rpcServices.getScannersCount();
+ byte[] regionName = TEST_UTIL.getAdmin().getRegions(TABLE_NAME).get(0).getRegionName();
+ ScanResponse opened = rpcServices.scan(new HBaseRpcControllerImpl(),
+ RequestConverter.buildScanRequest(regionName, new Scan(), 0, false));
+ long scannerId = opened.getScannerId();
+ assertEquals(scannerCount + 1, rpcServices.getScannersCount());
+
+ ServiceException throttled =
+ assertThrows(ServiceException.class, () -> rpcServices.scan(new HBaseRpcControllerImpl(),
+ RequestConverter.buildScanRequest(scannerId, 1, true, false)));
+ assertInstanceOf(RpcThrottlingException.class, throttled.getCause());
+ assertEquals(scannerCount + 1, rpcServices.getScannersCount());
+
+ ServiceException renewThrottled =
+ assertThrows(ServiceException.class, () -> rpcServices.scan(new HBaseRpcControllerImpl(),
+ RequestConverter.buildScanRequest(scannerId, 0, true, 0, false, true, -1)));
+ assertInstanceOf(RpcThrottlingException.class, renewThrottled.getCause());
+
+ ServiceException openThrottled =
+ assertThrows(ServiceException.class, () -> rpcServices.scan(new HBaseRpcControllerImpl(),
+ RequestConverter.buildScanRequest(regionName, new Scan(), 0, true)));
+ assertInstanceOf(RpcThrottlingException.class, openThrottled.getCause());
+
+ rpcServices.scan(new HBaseRpcControllerImpl(),
+ RequestConverter.buildScanRequest(scannerId, 0, true, false));
+ assertEquals(scannerCount, rpcServices.getScannersCount());
+ } finally {
+ cleanupQuota();
+ }
+ }
+
@Test
public void testIncrementCountedAgainstReadCapacity() throws Exception {
setupGenericQuota();