001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.quotas; 019 020import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerUserCacheRefresh; 021 022import java.io.IOException; 023import java.util.UUID; 024import java.util.concurrent.TimeUnit; 025import org.apache.hadoop.hbase.HBaseTestingUtil; 026import org.apache.hadoop.hbase.HConstants; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.client.Admin; 029import org.apache.hadoop.hbase.client.Table; 030import org.apache.hadoop.hbase.security.User; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.testclassification.RegionServerTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 035import org.junit.jupiter.api.AfterAll; 036import org.junit.jupiter.api.BeforeAll; 037import org.junit.jupiter.api.Tag; 038import org.junit.jupiter.api.Test; 039 040@Tag(RegionServerTests.TAG) 041@Tag(MediumTests.TAG) 042public class TestDefaultHandlerUsageQuota { 043 044 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 045 private static final TableName TABLE_NAME = TableName.valueOf(UUID.randomUUID().toString()); 046 private static final byte[] FAMILY = Bytes.toBytes("cf"); 047 private static final byte[] QUALIFIER = Bytes.toBytes("q"); 048 049 @AfterAll 050 public static void tearDown() throws Exception { 051 ThrottleQuotaTestUtil.clearQuotaCache(TEST_UTIL); 052 EnvironmentEdgeManager.reset(); 053 TEST_UTIL.deleteTable(TABLE_NAME); 054 TEST_UTIL.shutdownMiniCluster(); 055 } 056 057 @BeforeAll 058 public static void setUp() throws Exception { 059 // quotas enabled, using block bytes scanned 060 TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true); 061 // Set default to very strict 062 TEST_UTIL.getConfiguration() 063 .setInt(QuotaUtil.QUOTA_DEFAULT_USER_MACHINE_REQUEST_HANDLER_USAGE_MS, 10); 064 065 // don't cache blocks to make IO predictable 066 TEST_UTIL.getConfiguration().setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0.0f); 067 068 TEST_UTIL.startMiniCluster(1); 069 TEST_UTIL.waitTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME); 070 TEST_UTIL.createTable(TABLE_NAME, FAMILY); 071 TEST_UTIL.waitTableAvailable(TABLE_NAME); 072 TEST_UTIL.flush(TABLE_NAME); 073 // increase the tick so we can calculate a positive rpc request time, and then consume all the 074 // available quota and make request fail next time 075 ThrottleQuotaTestUtil.envEdge.setValue(System.currentTimeMillis() + 1000); 076 } 077 078 @Test 079 public void testDefaultHandlerUsageLimits() throws Exception { 080 // Should have a strict throttle by default 081 TEST_UTIL.waitFor(60_000, () -> runPutTest(100) < 100); 082 083 // Add big quota and should be effectively unlimited 084 configureLenientThrottle(); 085 // Should run without error 086 TEST_UTIL.waitFor(60_000, () -> runPutTest(100) == 100); 087 088 // Remove all the limits, and should revert to strict default 089 unsetQuota(); 090 TEST_UTIL.waitFor(60_000, () -> runPutTest(100) < 100); 091 } 092 093 private void configureLenientThrottle() throws Exception { 094 try (Admin admin = TEST_UTIL.getAdmin()) { 095 admin.setQuota(QuotaSettingsFactory.throttleUser(getUserName(), 096 ThrottleType.REQUEST_HANDLER_USAGE_MS, 100_000_000, TimeUnit.SECONDS)); 097 } 098 triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAME); 099 ThrottleQuotaTestUtil.envEdge.setValue(System.currentTimeMillis() + 1000); 100 } 101 102 private static String getUserName() throws IOException { 103 return User.getCurrent().getShortName(); 104 } 105 106 private void unsetQuota() throws Exception { 107 try (Admin admin = TEST_UTIL.getAdmin()) { 108 admin.setQuota(QuotaSettingsFactory.unthrottleUser(getUserName())); 109 } 110 triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAME); 111 ThrottleQuotaTestUtil.envEdge.setValue(System.currentTimeMillis() + 1000); 112 } 113 114 private long runPutTest(int attempts) throws Exception { 115 try (Table table = getTable()) { 116 return ThrottleQuotaTestUtil.doPuts(attempts, FAMILY, QUALIFIER, table); 117 } 118 } 119 120 private Table getTable() throws IOException { 121 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 100); 122 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1); 123 return TEST_UTIL.getConnection().getTableBuilder(TABLE_NAME, null).setOperationTimeout(250) 124 .build(); 125 } 126}