View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
8    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
9    * for the specific language governing permissions and limitations under the License.
10   */
11  
12  package org.apache.hadoop.hbase.quotas;
13  
14  import static org.junit.Assert.assertEquals;
15  import static org.junit.Assert.assertFalse;
16  import static org.junit.Assert.assertTrue;
17  import static org.junit.Assert.fail;
18  
19  import java.util.concurrent.TimeUnit;
20  
21  import org.apache.hadoop.hbase.HBaseIOException;
22  import org.apache.hadoop.hbase.TableName;
23  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
24  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
25  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Throttle;
26  import org.apache.hadoop.hbase.testclassification.SmallTests;
27  import org.junit.Test;
28  import org.junit.experimental.categories.Category;
29  
30  @Category({ SmallTests.class })
31  public class TestQuotaState {
32    private static final TableName UNKNOWN_TABLE_NAME = TableName.valueOf("unknownTable");
33  
34    @Test(timeout = 60000)
35    public void testQuotaStateBypass() {
36      QuotaState quotaInfo = new QuotaState();
37      assertTrue(quotaInfo.isBypass());
38      assertNoopLimiter(quotaInfo.getGlobalLimiter());
39  
40      UserQuotaState userQuotaState = new UserQuotaState();
41      assertTrue(userQuotaState.isBypass());
42      assertNoopLimiter(userQuotaState.getTableLimiter(UNKNOWN_TABLE_NAME));
43    }
44  
45    @Test(timeout = 60000)
46    public void testSimpleQuotaStateOperation() {
47      final TableName table = TableName.valueOf("testSimpleQuotaStateOperationTable");
48      final int NUM_GLOBAL_THROTTLE = 3;
49      final int NUM_TABLE_THROTTLE = 2;
50  
51      UserQuotaState quotaInfo = new UserQuotaState();
52      assertTrue(quotaInfo.isBypass());
53  
54      // Set global quota
55      quotaInfo.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE));
56      assertFalse(quotaInfo.isBypass());
57  
58      // Set table quota
59      quotaInfo.setQuotas(table, buildReqNumThrottle(NUM_TABLE_THROTTLE));
60      assertFalse(quotaInfo.isBypass());
61      assertTrue(quotaInfo.getGlobalLimiter() == quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
62      assertThrottleException(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME), NUM_GLOBAL_THROTTLE);
63      assertThrottleException(quotaInfo.getTableLimiter(table), NUM_TABLE_THROTTLE);
64    }
65  
66    @Test(timeout = 60000)
67    public void testQuotaStateUpdateBypassThrottle() {
68      final long LAST_UPDATE = 10;
69  
70      UserQuotaState quotaInfo = new UserQuotaState();
71      assertEquals(0, quotaInfo.getLastUpdate());
72      assertTrue(quotaInfo.isBypass());
73  
74      UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE);
75      assertEquals(LAST_UPDATE, otherQuotaState.getLastUpdate());
76      assertTrue(otherQuotaState.isBypass());
77  
78      quotaInfo.update(otherQuotaState);
79      assertEquals(LAST_UPDATE, quotaInfo.getLastUpdate());
80      assertTrue(quotaInfo.isBypass());
81      assertTrue(quotaInfo.getGlobalLimiter() == quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
82      assertNoopLimiter(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
83    }
84  
85    @Test(timeout = 60000)
86    public void testQuotaStateUpdateGlobalThrottle() {
87      final int NUM_GLOBAL_THROTTLE_1 = 3;
88      final int NUM_GLOBAL_THROTTLE_2 = 11;
89      final long LAST_UPDATE_1 = 10;
90      final long LAST_UPDATE_2 = 20;
91      final long LAST_UPDATE_3 = 30;
92  
93      QuotaState quotaInfo = new QuotaState();
94      assertEquals(0, quotaInfo.getLastUpdate());
95      assertTrue(quotaInfo.isBypass());
96  
97      // Add global throttle
98      QuotaState otherQuotaState = new QuotaState(LAST_UPDATE_1);
99      otherQuotaState.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE_1));
100     assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
101     assertFalse(otherQuotaState.isBypass());
102 
103     quotaInfo.update(otherQuotaState);
104     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
105     assertFalse(quotaInfo.isBypass());
106     assertThrottleException(quotaInfo.getGlobalLimiter(), NUM_GLOBAL_THROTTLE_1);
107 
108     // Update global Throttle
109     otherQuotaState = new QuotaState(LAST_UPDATE_2);
110     otherQuotaState.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE_2));
111     assertEquals(LAST_UPDATE_2, otherQuotaState.getLastUpdate());
112     assertFalse(otherQuotaState.isBypass());
113 
114     quotaInfo.update(otherQuotaState);
115     assertEquals(LAST_UPDATE_2, quotaInfo.getLastUpdate());
116     assertFalse(quotaInfo.isBypass());
117     assertThrottleException(quotaInfo.getGlobalLimiter(), NUM_GLOBAL_THROTTLE_2
118         - NUM_GLOBAL_THROTTLE_1);
119 
120     // Remove global throttle
121     otherQuotaState = new QuotaState(LAST_UPDATE_3);
122     assertEquals(LAST_UPDATE_3, otherQuotaState.getLastUpdate());
123     assertTrue(otherQuotaState.isBypass());
124 
125     quotaInfo.update(otherQuotaState);
126     assertEquals(LAST_UPDATE_3, quotaInfo.getLastUpdate());
127     assertTrue(quotaInfo.isBypass());
128     assertNoopLimiter(quotaInfo.getGlobalLimiter());
129   }
130 
131   @Test(timeout = 60000)
132   public void testQuotaStateUpdateTableThrottle() {
133     final TableName TABLE_A = TableName.valueOf("TableA");
134     final TableName TABLE_B = TableName.valueOf("TableB");
135     final TableName TABLE_C = TableName.valueOf("TableC");
136     final int TABLE_A_THROTTLE_1 = 3;
137     final int TABLE_A_THROTTLE_2 = 11;
138     final int TABLE_B_THROTTLE = 4;
139     final int TABLE_C_THROTTLE = 5;
140     final long LAST_UPDATE_1 = 10;
141     final long LAST_UPDATE_2 = 20;
142     final long LAST_UPDATE_3 = 30;
143 
144     UserQuotaState quotaInfo = new UserQuotaState();
145     assertEquals(0, quotaInfo.getLastUpdate());
146     assertTrue(quotaInfo.isBypass());
147 
148     // Add A B table limiters
149     UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE_1);
150     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_1));
151     otherQuotaState.setQuotas(TABLE_B, buildReqNumThrottle(TABLE_B_THROTTLE));
152     assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
153     assertFalse(otherQuotaState.isBypass());
154 
155     quotaInfo.update(otherQuotaState);
156     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
157     assertFalse(quotaInfo.isBypass());
158     assertThrottleException(quotaInfo.getTableLimiter(TABLE_A), TABLE_A_THROTTLE_1);
159     assertThrottleException(quotaInfo.getTableLimiter(TABLE_B), TABLE_B_THROTTLE);
160     assertNoopLimiter(quotaInfo.getTableLimiter(TABLE_C));
161 
162     // Add C, Remove B, Update A table limiters
163     otherQuotaState = new UserQuotaState(LAST_UPDATE_2);
164     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_2));
165     otherQuotaState.setQuotas(TABLE_C, buildReqNumThrottle(TABLE_C_THROTTLE));
166     assertEquals(LAST_UPDATE_2, otherQuotaState.getLastUpdate());
167     assertFalse(otherQuotaState.isBypass());
168 
169     quotaInfo.update(otherQuotaState);
170     assertEquals(LAST_UPDATE_2, quotaInfo.getLastUpdate());
171     assertFalse(quotaInfo.isBypass());
172     assertThrottleException(quotaInfo.getTableLimiter(TABLE_A), TABLE_A_THROTTLE_2
173         - TABLE_A_THROTTLE_1);
174     assertThrottleException(quotaInfo.getTableLimiter(TABLE_C), TABLE_C_THROTTLE);
175     assertNoopLimiter(quotaInfo.getTableLimiter(TABLE_B));
176 
177     // Remove table limiters
178     otherQuotaState = new UserQuotaState(LAST_UPDATE_3);
179     assertEquals(LAST_UPDATE_3, otherQuotaState.getLastUpdate());
180     assertTrue(otherQuotaState.isBypass());
181 
182     quotaInfo.update(otherQuotaState);
183     assertEquals(LAST_UPDATE_3, quotaInfo.getLastUpdate());
184     assertTrue(quotaInfo.isBypass());
185     assertNoopLimiter(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
186   }
187 
188   @Test(timeout = 60000)
189   public void testTableThrottleWithBatch() {
190     final TableName TABLE_A = TableName.valueOf("TableA");
191     final int TABLE_A_THROTTLE_1 = 3;
192     final long LAST_UPDATE_1 = 10;
193 
194     UserQuotaState quotaInfo = new UserQuotaState();
195     assertEquals(0, quotaInfo.getLastUpdate());
196     assertTrue(quotaInfo.isBypass());
197 
198     // Add A table limiters
199     UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE_1);
200     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_1));
201     assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
202     assertFalse(otherQuotaState.isBypass());
203 
204     quotaInfo.update(otherQuotaState);
205     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
206     assertFalse(quotaInfo.isBypass());
207     QuotaLimiter limiter = quotaInfo.getTableLimiter(TABLE_A);
208     try {
209       limiter.checkQuota(TABLE_A_THROTTLE_1 + 1, TABLE_A_THROTTLE_1 + 1, 0, 0, 1, 0);
210       fail("Should have thrown RpcThrottlingException");
211     } catch (HBaseIOException e) {
212       // expected
213     }
214   }
215 
216   private Quotas buildReqNumThrottle(final long limit) {
217     return Quotas
218         .newBuilder()
219         .setThrottle(
220           Throttle.newBuilder()
221               .setReqNum(ProtobufUtil.toTimedQuota(limit, TimeUnit.MINUTES, QuotaScope.MACHINE))
222               .build()).build();
223   }
224 
225   private void assertThrottleException(final QuotaLimiter limiter, final int availReqs) {
226     assertNoThrottleException(limiter, availReqs);
227     try {
228       limiter.checkQuota(1, 1, 0, 0, 1, 0);
229       fail("Should have thrown RpcThrottlingException");
230     } catch (HBaseIOException e) {
231       // expected
232     }
233   }
234 
235   private void assertNoThrottleException(final QuotaLimiter limiter, final int availReqs) {
236     for (int i = 0; i < availReqs; ++i) {
237       try {
238         limiter.checkQuota(1, 1, 0, 0, 1, 0);
239       } catch (HBaseIOException e) {
240         fail("Unexpected RpcThrottlingException after " + i + " requests. limit=" + availReqs);
241       }
242       limiter.grabQuota(1, 1, 0, 0, 1, 0);
243     }
244   }
245 
246   private void assertNoopLimiter(final QuotaLimiter limiter) {
247     assertTrue(limiter == NoopQuotaLimiter.get());
248     assertNoThrottleException(limiter, 100);
249   }
250 }