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.TableName;
22  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
23  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
24  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Throttle;
25  import org.apache.hadoop.hbase.testclassification.SmallTests;
26  import org.junit.Test;
27  import org.junit.experimental.categories.Category;
28  
29  @Category({ SmallTests.class })
30  public class TestQuotaState {
31    private static final TableName UNKNOWN_TABLE_NAME = TableName.valueOf("unknownTable");
32  
33    @Test(timeout = 60000)
34    public void testQuotaStateBypass() {
35      QuotaState quotaInfo = new QuotaState();
36      assertTrue(quotaInfo.isBypass());
37      assertNoopLimiter(quotaInfo.getGlobalLimiter());
38  
39      UserQuotaState userQuotaState = new UserQuotaState();
40      assertTrue(userQuotaState.isBypass());
41      assertNoopLimiter(userQuotaState.getTableLimiter(UNKNOWN_TABLE_NAME));
42    }
43  
44    @Test(timeout = 60000)
45    public void testSimpleQuotaStateOperation() {
46      final TableName table = TableName.valueOf("testSimpleQuotaStateOperationTable");
47      final int NUM_GLOBAL_THROTTLE = 3;
48      final int NUM_TABLE_THROTTLE = 2;
49  
50      UserQuotaState quotaInfo = new UserQuotaState();
51      assertTrue(quotaInfo.isBypass());
52  
53      // Set global quota
54      quotaInfo.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE));
55      assertFalse(quotaInfo.isBypass());
56  
57      // Set table quota
58      quotaInfo.setQuotas(table, buildReqNumThrottle(NUM_TABLE_THROTTLE));
59      assertFalse(quotaInfo.isBypass());
60      assertTrue(quotaInfo.getGlobalLimiter() == quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
61      assertThrottleException(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME), NUM_GLOBAL_THROTTLE);
62      assertThrottleException(quotaInfo.getTableLimiter(table), NUM_TABLE_THROTTLE);
63    }
64  
65    @Test(timeout = 60000)
66    public void testQuotaStateUpdateBypassThrottle() {
67      final long LAST_UPDATE = 10;
68  
69      UserQuotaState quotaInfo = new UserQuotaState();
70      assertEquals(0, quotaInfo.getLastUpdate());
71      assertTrue(quotaInfo.isBypass());
72  
73      UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE);
74      assertEquals(LAST_UPDATE, otherQuotaState.getLastUpdate());
75      assertTrue(otherQuotaState.isBypass());
76  
77      quotaInfo.update(otherQuotaState);
78      assertEquals(LAST_UPDATE, quotaInfo.getLastUpdate());
79      assertTrue(quotaInfo.isBypass());
80      assertTrue(quotaInfo.getGlobalLimiter() == quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
81      assertNoopLimiter(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
82    }
83  
84    @Test(timeout = 60000)
85    public void testQuotaStateUpdateGlobalThrottle() {
86      final int NUM_GLOBAL_THROTTLE_1 = 3;
87      final int NUM_GLOBAL_THROTTLE_2 = 11;
88      final long LAST_UPDATE_1 = 10;
89      final long LAST_UPDATE_2 = 20;
90      final long LAST_UPDATE_3 = 30;
91  
92      QuotaState quotaInfo = new QuotaState();
93      assertEquals(0, quotaInfo.getLastUpdate());
94      assertTrue(quotaInfo.isBypass());
95  
96      // Add global throttle
97      QuotaState otherQuotaState = new QuotaState(LAST_UPDATE_1);
98      otherQuotaState.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE_1));
99      assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
100     assertFalse(otherQuotaState.isBypass());
101 
102     quotaInfo.update(otherQuotaState);
103     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
104     assertFalse(quotaInfo.isBypass());
105     assertThrottleException(quotaInfo.getGlobalLimiter(), NUM_GLOBAL_THROTTLE_1);
106 
107     // Update global Throttle
108     otherQuotaState = new QuotaState(LAST_UPDATE_2);
109     otherQuotaState.setQuotas(buildReqNumThrottle(NUM_GLOBAL_THROTTLE_2));
110     assertEquals(LAST_UPDATE_2, otherQuotaState.getLastUpdate());
111     assertFalse(otherQuotaState.isBypass());
112 
113     quotaInfo.update(otherQuotaState);
114     assertEquals(LAST_UPDATE_2, quotaInfo.getLastUpdate());
115     assertFalse(quotaInfo.isBypass());
116     assertThrottleException(quotaInfo.getGlobalLimiter(), NUM_GLOBAL_THROTTLE_2
117         - NUM_GLOBAL_THROTTLE_1);
118 
119     // Remove global throttle
120     otherQuotaState = new QuotaState(LAST_UPDATE_3);
121     assertEquals(LAST_UPDATE_3, otherQuotaState.getLastUpdate());
122     assertTrue(otherQuotaState.isBypass());
123 
124     quotaInfo.update(otherQuotaState);
125     assertEquals(LAST_UPDATE_3, quotaInfo.getLastUpdate());
126     assertTrue(quotaInfo.isBypass());
127     assertNoopLimiter(quotaInfo.getGlobalLimiter());
128   }
129 
130   @Test(timeout = 60000)
131   public void testQuotaStateUpdateTableThrottle() {
132     final TableName TABLE_A = TableName.valueOf("TableA");
133     final TableName TABLE_B = TableName.valueOf("TableB");
134     final TableName TABLE_C = TableName.valueOf("TableC");
135     final int TABLE_A_THROTTLE_1 = 3;
136     final int TABLE_A_THROTTLE_2 = 11;
137     final int TABLE_B_THROTTLE = 4;
138     final int TABLE_C_THROTTLE = 5;
139     final long LAST_UPDATE_1 = 10;
140     final long LAST_UPDATE_2 = 20;
141     final long LAST_UPDATE_3 = 30;
142 
143     UserQuotaState quotaInfo = new UserQuotaState();
144     assertEquals(0, quotaInfo.getLastUpdate());
145     assertTrue(quotaInfo.isBypass());
146 
147     // Add A B table limiters
148     UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE_1);
149     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_1));
150     otherQuotaState.setQuotas(TABLE_B, buildReqNumThrottle(TABLE_B_THROTTLE));
151     assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
152     assertFalse(otherQuotaState.isBypass());
153 
154     quotaInfo.update(otherQuotaState);
155     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
156     assertFalse(quotaInfo.isBypass());
157     assertThrottleException(quotaInfo.getTableLimiter(TABLE_A), TABLE_A_THROTTLE_1);
158     assertThrottleException(quotaInfo.getTableLimiter(TABLE_B), TABLE_B_THROTTLE);
159     assertNoopLimiter(quotaInfo.getTableLimiter(TABLE_C));
160 
161     // Add C, Remove B, Update A table limiters
162     otherQuotaState = new UserQuotaState(LAST_UPDATE_2);
163     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_2));
164     otherQuotaState.setQuotas(TABLE_C, buildReqNumThrottle(TABLE_C_THROTTLE));
165     assertEquals(LAST_UPDATE_2, otherQuotaState.getLastUpdate());
166     assertFalse(otherQuotaState.isBypass());
167 
168     quotaInfo.update(otherQuotaState);
169     assertEquals(LAST_UPDATE_2, quotaInfo.getLastUpdate());
170     assertFalse(quotaInfo.isBypass());
171     assertThrottleException(quotaInfo.getTableLimiter(TABLE_A), TABLE_A_THROTTLE_2
172         - TABLE_A_THROTTLE_1);
173     assertThrottleException(quotaInfo.getTableLimiter(TABLE_C), TABLE_C_THROTTLE);
174     assertNoopLimiter(quotaInfo.getTableLimiter(TABLE_B));
175 
176     // Remove table limiters
177     otherQuotaState = new UserQuotaState(LAST_UPDATE_3);
178     assertEquals(LAST_UPDATE_3, otherQuotaState.getLastUpdate());
179     assertTrue(otherQuotaState.isBypass());
180 
181     quotaInfo.update(otherQuotaState);
182     assertEquals(LAST_UPDATE_3, quotaInfo.getLastUpdate());
183     assertTrue(quotaInfo.isBypass());
184     assertNoopLimiter(quotaInfo.getTableLimiter(UNKNOWN_TABLE_NAME));
185   }
186 
187   @Test(timeout = 60000)
188   public void testTableThrottleWithBatch() {
189     final TableName TABLE_A = TableName.valueOf("TableA");
190     final int TABLE_A_THROTTLE_1 = 3;
191     final long LAST_UPDATE_1 = 10;
192 
193     UserQuotaState quotaInfo = new UserQuotaState();
194     assertEquals(0, quotaInfo.getLastUpdate());
195     assertTrue(quotaInfo.isBypass());
196 
197     // Add A table limiters
198     UserQuotaState otherQuotaState = new UserQuotaState(LAST_UPDATE_1);
199     otherQuotaState.setQuotas(TABLE_A, buildReqNumThrottle(TABLE_A_THROTTLE_1));
200     assertEquals(LAST_UPDATE_1, otherQuotaState.getLastUpdate());
201     assertFalse(otherQuotaState.isBypass());
202 
203     quotaInfo.update(otherQuotaState);
204     assertEquals(LAST_UPDATE_1, quotaInfo.getLastUpdate());
205     assertFalse(quotaInfo.isBypass());
206     QuotaLimiter limiter = quotaInfo.getTableLimiter(TABLE_A);
207     try {
208       limiter.checkQuota(TABLE_A_THROTTLE_1 + 1, TABLE_A_THROTTLE_1 + 1, 0, 0);
209       fail("Should have thrown ThrottlingException");
210     } catch (ThrottlingException e) {
211       // expected
212     }
213   }
214 
215   private Quotas buildReqNumThrottle(final long limit) {
216     return Quotas
217         .newBuilder()
218         .setThrottle(
219           Throttle.newBuilder()
220               .setReqNum(ProtobufUtil.toTimedQuota(limit, TimeUnit.MINUTES, QuotaScope.MACHINE))
221               .build()).build();
222   }
223 
224   private void assertThrottleException(final QuotaLimiter limiter, final int availReqs) {
225     assertNoThrottleException(limiter, availReqs);
226     try {
227       limiter.checkQuota(1, 1, 0, 0);
228       fail("Should have thrown ThrottlingException");
229     } catch (ThrottlingException e) {
230       // expected
231     }
232   }
233 
234   private void assertNoThrottleException(final QuotaLimiter limiter, final int availReqs) {
235     for (int i = 0; i < availReqs; ++i) {
236       try {
237         limiter.checkQuota(1, 1, 0, 0);
238       } catch (ThrottlingException e) {
239         fail("Unexpected ThrottlingException after " + i + " requests. limit=" + availReqs);
240       }
241       limiter.grabQuota(1, 1, 0, 0);
242     }
243   }
244 
245   private void assertNoopLimiter(final QuotaLimiter limiter) {
246     assertTrue(limiter == NoopQuotaLimiter.get());
247     assertNoThrottleException(limiter, 100);
248   }
249 }