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   private Quotas buildReqNumThrottle(final long limit) {
188     return Quotas
189         .newBuilder()
190         .setThrottle(
191           Throttle.newBuilder()
192               .setReqNum(ProtobufUtil.toTimedQuota(limit, TimeUnit.MINUTES, QuotaScope.MACHINE))
193               .build()).build();
194   }
195 
196   private void assertThrottleException(final QuotaLimiter limiter, final int availReqs) {
197     assertNoThrottleException(limiter, availReqs);
198     try {
199       limiter.checkQuota(1, 1);
200       fail("Should have thrown ThrottlingException");
201     } catch (ThrottlingException e) {
202       // expected
203     }
204   }
205 
206   private void assertNoThrottleException(final QuotaLimiter limiter, final int availReqs) {
207     for (int i = 0; i < availReqs; ++i) {
208       try {
209         limiter.checkQuota(1, 1);
210       } catch (ThrottlingException e) {
211         fail("Unexpected ThrottlingException after " + i + " requests. limit=" + availReqs);
212       }
213       limiter.grabQuota(1, 1);
214     }
215   }
216 
217   private void assertNoopLimiter(final QuotaLimiter limiter) {
218     assertTrue(limiter == NoopQuotaLimiter.get());
219     assertNoThrottleException(limiter, 100);
220   }
221 }