|  | 
|  | 1 | +/* | 
|  | 2 | + * Licensed to the Apache Software Foundation (ASF) under one | 
|  | 3 | + * or more contributor license agreements.  See the NOTICE file | 
|  | 4 | + * distributed with this work for additional information | 
|  | 5 | + * regarding copyright ownership.  The ASF licenses this file | 
|  | 6 | + * to you under the Apache License, Version 2.0 (the | 
|  | 7 | + * "License"); you may not use this file except in compliance | 
|  | 8 | + * with the License.  You may obtain a copy of the License at | 
|  | 9 | + * | 
|  | 10 | + *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 11 | + * | 
|  | 12 | + * Unless required by applicable law or agreed to in writing, software | 
|  | 13 | + * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 15 | + * See the License for the specific language governing permissions and | 
|  | 16 | + * limitations under the License. | 
|  | 17 | + */ | 
|  | 18 | +package org.apache.hadoop.hbase.quotas; | 
|  | 19 | + | 
|  | 20 | +import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerUserCacheRefresh; | 
|  | 21 | +import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.waitMinuteQuota; | 
|  | 22 | + | 
|  | 23 | +import java.io.IOException; | 
|  | 24 | +import java.util.UUID; | 
|  | 25 | +import java.util.concurrent.TimeUnit; | 
|  | 26 | +import org.apache.hadoop.hbase.HBaseClassTestRule; | 
|  | 27 | +import org.apache.hadoop.hbase.HBaseTestingUtil; | 
|  | 28 | +import org.apache.hadoop.hbase.HConstants; | 
|  | 29 | +import org.apache.hadoop.hbase.TableName; | 
|  | 30 | +import org.apache.hadoop.hbase.client.Admin; | 
|  | 31 | +import org.apache.hadoop.hbase.client.Table; | 
|  | 32 | +import org.apache.hadoop.hbase.security.User; | 
|  | 33 | +import org.apache.hadoop.hbase.testclassification.MediumTests; | 
|  | 34 | +import org.apache.hadoop.hbase.testclassification.RegionServerTests; | 
|  | 35 | +import org.apache.hadoop.hbase.util.Bytes; | 
|  | 36 | +import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; | 
|  | 37 | +import org.junit.After; | 
|  | 38 | +import org.junit.BeforeClass; | 
|  | 39 | +import org.junit.ClassRule; | 
|  | 40 | +import org.junit.Test; | 
|  | 41 | +import org.junit.experimental.categories.Category; | 
|  | 42 | + | 
|  | 43 | +@Category({ RegionServerTests.class, MediumTests.class }) | 
|  | 44 | +public class TestDefaultQuota { | 
|  | 45 | +  @ClassRule | 
|  | 46 | +  public static final HBaseClassTestRule CLASS_RULE = | 
|  | 47 | +    HBaseClassTestRule.forClass(TestDefaultQuota.class); | 
|  | 48 | +  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); | 
|  | 49 | +  private static final TableName TABLE_NAME = TableName.valueOf(UUID.randomUUID().toString()); | 
|  | 50 | +  private static final int REFRESH_TIME = 5000; | 
|  | 51 | +  private static final byte[] FAMILY = Bytes.toBytes("cf"); | 
|  | 52 | +  private static final byte[] QUALIFIER = Bytes.toBytes("q"); | 
|  | 53 | + | 
|  | 54 | +  @After | 
|  | 55 | +  public void tearDown() throws Exception { | 
|  | 56 | +    ThrottleQuotaTestUtil.clearQuotaCache(TEST_UTIL); | 
|  | 57 | +    EnvironmentEdgeManager.reset(); | 
|  | 58 | +    TEST_UTIL.deleteTable(TABLE_NAME); | 
|  | 59 | +    TEST_UTIL.shutdownMiniCluster(); | 
|  | 60 | +  } | 
|  | 61 | + | 
|  | 62 | +  @BeforeClass | 
|  | 63 | +  public static void setUpBeforeClass() throws Exception { | 
|  | 64 | +    // quotas enabled, using block bytes scanned | 
|  | 65 | +    TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true); | 
|  | 66 | +    TEST_UTIL.getConfiguration().setInt(QuotaCache.REFRESH_CONF_KEY, REFRESH_TIME); | 
|  | 67 | +    TEST_UTIL.getConfiguration().setInt(QuotaUtil.QUOTA_DEFAULT_USER_MACHINE_READ_NUM, 1); | 
|  | 68 | + | 
|  | 69 | +    // don't cache blocks to make IO predictable | 
|  | 70 | +    TEST_UTIL.getConfiguration().setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0.0f); | 
|  | 71 | + | 
|  | 72 | +    TEST_UTIL.startMiniCluster(1); | 
|  | 73 | +    TEST_UTIL.waitTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME); | 
|  | 74 | +    TEST_UTIL.createTable(TABLE_NAME, FAMILY); | 
|  | 75 | +    TEST_UTIL.waitTableAvailable(TABLE_NAME); | 
|  | 76 | +    QuotaCache.TEST_FORCE_REFRESH = true; | 
|  | 77 | + | 
|  | 78 | +    try (Admin admin = TEST_UTIL.getAdmin()) { | 
|  | 79 | +      ThrottleQuotaTestUtil.doPuts(1_000, FAMILY, QUALIFIER, | 
|  | 80 | +        admin.getConnection().getTable(TABLE_NAME)); | 
|  | 81 | +    } | 
|  | 82 | +    TEST_UTIL.flush(TABLE_NAME); | 
|  | 83 | +  } | 
|  | 84 | + | 
|  | 85 | +  @Test | 
|  | 86 | +  public void testDefaultUserReadNum() throws Exception { | 
|  | 87 | +    // Should have a strict throttle by default | 
|  | 88 | +    TEST_UTIL.waitFor(60_000, () -> runGetsTest(100) < 100); | 
|  | 89 | + | 
|  | 90 | +    // Add big quota and should be effectively unlimited | 
|  | 91 | +    configureLenientThrottle(); | 
|  | 92 | +    refreshQuotas(); | 
|  | 93 | +    // Should run without error | 
|  | 94 | +    TEST_UTIL.waitFor(60_000, () -> runGetsTest(100) == 100); | 
|  | 95 | + | 
|  | 96 | +    // Remove all the limits, and should revert to strict default | 
|  | 97 | +    unsetQuota(); | 
|  | 98 | +    TEST_UTIL.waitFor(60_000, () -> runGetsTest(100) < 100); | 
|  | 99 | +  } | 
|  | 100 | + | 
|  | 101 | +  private void configureLenientThrottle() throws IOException { | 
|  | 102 | +    try (Admin admin = TEST_UTIL.getAdmin()) { | 
|  | 103 | +      admin.setQuota(QuotaSettingsFactory.throttleUser(getUserName(), ThrottleType.READ_NUMBER, | 
|  | 104 | +        100_000, TimeUnit.SECONDS)); | 
|  | 105 | +    } | 
|  | 106 | +  } | 
|  | 107 | + | 
|  | 108 | +  private static String getUserName() throws IOException { | 
|  | 109 | +    return User.getCurrent().getShortName(); | 
|  | 110 | +  } | 
|  | 111 | + | 
|  | 112 | +  private void refreshQuotas() throws Exception { | 
|  | 113 | +    triggerUserCacheRefresh(TEST_UTIL, false, TABLE_NAME); | 
|  | 114 | +    waitMinuteQuota(); | 
|  | 115 | +  } | 
|  | 116 | + | 
|  | 117 | +  private void unsetQuota() throws Exception { | 
|  | 118 | +    try (Admin admin = TEST_UTIL.getAdmin()) { | 
|  | 119 | +      admin.setQuota(QuotaSettingsFactory.unthrottleUser(getUserName())); | 
|  | 120 | +    } | 
|  | 121 | +    refreshQuotas(); | 
|  | 122 | +  } | 
|  | 123 | + | 
|  | 124 | +  private long runGetsTest(int attempts) throws Exception { | 
|  | 125 | +    refreshQuotas(); | 
|  | 126 | +    try (Table table = getTable()) { | 
|  | 127 | +      return ThrottleQuotaTestUtil.doGets(attempts, FAMILY, QUALIFIER, table); | 
|  | 128 | +    } | 
|  | 129 | +  } | 
|  | 130 | + | 
|  | 131 | +  private Table getTable() throws IOException { | 
|  | 132 | +    TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 100); | 
|  | 133 | +    TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1); | 
|  | 134 | +    return TEST_UTIL.getConnection().getTableBuilder(TABLE_NAME, null).setOperationTimeout(250) | 
|  | 135 | +      .build(); | 
|  | 136 | +  } | 
|  | 137 | + | 
|  | 138 | +} | 
0 commit comments