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.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.util.HashMap; 025import java.util.Map; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.HBaseConfiguration; 028import org.apache.hadoop.hbase.testclassification.RegionServerTests; 029import org.apache.hadoop.hbase.testclassification.SmallTests; 030import org.junit.jupiter.api.Tag; 031import org.junit.jupiter.api.Test; 032 033import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 034import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos; 035 036/** 037 * Tests of QuotaCache that don't require a minicluster, unlike in TestQuotaCache 038 */ 039@Tag(RegionServerTests.TAG) 040@Tag(SmallTests.TAG) 041public class TestQuotaCache2 { 042 043 private static final Configuration conf = HBaseConfiguration.create(); 044 045 @Test 046 public void testPreserveLimiterAvailability() throws Exception { 047 // establish old cache with a limiter for 100 read bytes per second 048 QuotaState oldState = new QuotaState(); 049 Map<String, QuotaState> oldCache = new HashMap<>(); 050 oldCache.put("my_table", oldState); 051 QuotaProtos.Throttle throttle1 = QuotaProtos.Throttle.newBuilder() 052 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 053 .setSoftLimit(100).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 054 .build(); 055 QuotaLimiter limiter1 = TimeBasedLimiter.fromThrottle(conf, throttle1); 056 oldState.setGlobalLimiter(limiter1); 057 058 // consume one byte from the limiter, so 99 will be left 059 limiter1.consumeRead(1, 1, false); 060 061 // establish new cache, also with a limiter for 100 read bytes per second 062 QuotaState newState = new QuotaState(); 063 Map<String, QuotaState> newCache = new HashMap<>(); 064 newCache.put("my_table", newState); 065 QuotaProtos.Throttle throttle2 = QuotaProtos.Throttle.newBuilder() 066 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 067 .setSoftLimit(100).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 068 .build(); 069 QuotaLimiter limiter2 = TimeBasedLimiter.fromThrottle(conf, throttle2); 070 newState.setGlobalLimiter(limiter2); 071 072 // update new cache from old cache 073 QuotaCache.updateNewCacheFromOld(oldCache, newCache); 074 075 // verify that the 99 available bytes from the limiter was carried over 076 TimeBasedLimiter updatedLimiter = 077 (TimeBasedLimiter) newCache.get("my_table").getGlobalLimiter(); 078 assertEquals(99, updatedLimiter.getReadAvailable()); 079 } 080 081 @Test 082 public void testClobberLimiterLimit() throws Exception { 083 // establish old cache with a limiter for 100 read bytes per second 084 QuotaState oldState = new QuotaState(); 085 Map<String, QuotaState> oldCache = new HashMap<>(); 086 oldCache.put("my_table", oldState); 087 QuotaProtos.Throttle throttle1 = QuotaProtos.Throttle.newBuilder() 088 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 089 .setSoftLimit(100).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 090 .build(); 091 QuotaLimiter limiter1 = TimeBasedLimiter.fromThrottle(conf, throttle1); 092 oldState.setGlobalLimiter(limiter1); 093 094 // establish new cache, also with a limiter for 100 read bytes per second 095 QuotaState newState = new QuotaState(); 096 Map<String, QuotaState> newCache = new HashMap<>(); 097 newCache.put("my_table", newState); 098 QuotaProtos.Throttle throttle2 = QuotaProtos.Throttle.newBuilder() 099 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 100 .setSoftLimit(50).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 101 .build(); 102 QuotaLimiter limiter2 = TimeBasedLimiter.fromThrottle(conf, throttle2); 103 newState.setGlobalLimiter(limiter2); 104 105 // update new cache from old cache 106 QuotaCache.updateNewCacheFromOld(oldCache, newCache); 107 108 // verify that the 99 available bytes from the limiter was carried over 109 TimeBasedLimiter updatedLimiter = 110 (TimeBasedLimiter) newCache.get("my_table").getGlobalLimiter(); 111 assertEquals(50, updatedLimiter.getReadLimit()); 112 } 113 114 @Test 115 public void testForgetsDeletedQuota() { 116 QuotaState oldState = new QuotaState(); 117 Map<String, QuotaState> oldCache = new HashMap<>(); 118 oldCache.put("my_table1", oldState); 119 120 QuotaState newState = new QuotaState(); 121 Map<String, QuotaState> newCache = new HashMap<>(); 122 newCache.put("my_table2", newState); 123 124 QuotaCache.updateNewCacheFromOld(oldCache, newCache); 125 126 assertTrue(newCache.containsKey("my_table2")); 127 assertFalse(newCache.containsKey("my_table1")); 128 } 129 130 @Test 131 public void testLearnsNewQuota() { 132 Map<String, QuotaState> oldCache = new HashMap<>(); 133 134 QuotaState newState = new QuotaState(); 135 Map<String, QuotaState> newCache = new HashMap<>(); 136 newCache.put("my_table1", newState); 137 138 QuotaCache.updateNewCacheFromOld(oldCache, newCache); 139 140 assertTrue(newCache.containsKey("my_table1")); 141 } 142 143 @Test 144 public void testUserSpecificOverridesDefaultNewQuota() { 145 // establish old cache with a limiter for 100 read bytes per second 146 QuotaState oldState = new QuotaState(); 147 Map<String, QuotaState> oldCache = new HashMap<>(); 148 oldCache.put("my_table", oldState); 149 QuotaProtos.Throttle throttle1 = QuotaProtos.Throttle.newBuilder() 150 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 151 .setSoftLimit(100).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 152 .build(); 153 QuotaLimiter limiter1 = TimeBasedLimiter.fromThrottle(conf, throttle1); 154 oldState.setGlobalLimiter(limiter1); 155 156 // establish new cache, with a limiter for 999 read bytes per second 157 QuotaState newState = new QuotaState(); 158 Map<String, QuotaState> newCache = new HashMap<>(); 159 newCache.put("my_table", newState); 160 QuotaProtos.Throttle throttle2 = QuotaProtos.Throttle.newBuilder() 161 .setReadSize(QuotaProtos.TimedQuota.newBuilder().setTimeUnit(HBaseProtos.TimeUnit.SECONDS) 162 .setSoftLimit(999).setScope(QuotaProtos.QuotaScope.MACHINE).build()) 163 .build(); 164 QuotaLimiter limiter2 = TimeBasedLimiter.fromThrottle(conf, throttle2); 165 newState.setGlobalLimiter(limiter2); 166 167 // update new cache from old cache 168 QuotaCache.updateNewCacheFromOld(oldCache, newCache); 169 170 // verify that the 999 available bytes from the limiter was carried over 171 TimeBasedLimiter updatedLimiter = 172 (TimeBasedLimiter) newCache.get("my_table").getGlobalLimiter(); 173 assertEquals(999, updatedLimiter.getReadAvailable()); 174 } 175}