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  
16  import java.io.IOException;
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.concurrent.TimeUnit;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.HBaseTestingUtility;
26  import org.apache.hadoop.hbase.HConstants;
27  import org.apache.hadoop.hbase.TableName;
28  import org.apache.hadoop.hbase.client.Connection;
29  import org.apache.hadoop.hbase.client.ConnectionFactory;
30  import org.apache.hadoop.hbase.client.Put;
31  import org.apache.hadoop.hbase.client.Result;
32  import org.apache.hadoop.hbase.client.ResultScanner;
33  import org.apache.hadoop.hbase.client.Table;
34  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
35  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
36  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Throttle;
37  import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
38  import org.apache.hadoop.hbase.testclassification.MediumTests;
39  import org.junit.After;
40  import org.junit.AfterClass;
41  import org.junit.Before;
42  import org.junit.BeforeClass;
43  import org.junit.Rule;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  import org.junit.rules.TestName;
47  
48  /**
49   * Test the quota table helpers (e.g. CRUD operations)
50   */
51  @Category({ MediumTests.class })
52  public class TestQuotaTableUtil {
53    final Log LOG = LogFactory.getLog(getClass());
54  
55    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
56    private Connection connection;
57    private int tableNameCounter;
58  
59    @Rule
60    public TestName testName = new TestName();
61  
62    @BeforeClass
63    public static void setUpBeforeClass() throws Exception {
64      TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
65      TEST_UTIL.getConfiguration().setInt(QuotaCache.REFRESH_CONF_KEY, 2000);
66      TEST_UTIL.getConfiguration().setInt("hbase.hstore.compactionThreshold", 10);
67      TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
68      TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
69      TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
70      TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true);
71      TEST_UTIL.startMiniCluster(1);
72      TEST_UTIL.waitTableAvailable(QuotaTableUtil.QUOTA_TABLE_NAME);
73    }
74  
75    @AfterClass
76    public static void tearDownAfterClass() throws Exception {
77      TEST_UTIL.shutdownMiniCluster();
78    }
79  
80    @Before
81    public void before() throws IOException {
82      this.connection = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
83      this.tableNameCounter = 0;
84    }
85  
86    @After
87    public void after() throws IOException {
88      this.connection.close();
89    }
90  
91    @Test
92    public void testTableQuotaUtil() throws Exception {
93      final TableName table = TableName.valueOf("testTableQuotaUtilTable");
94  
95      Quotas quota =
96          Quotas
97              .newBuilder()
98              .setThrottle(
99                Throttle
100                   .newBuilder()
101                   .setReqNum(ProtobufUtil.toTimedQuota(1000, TimeUnit.SECONDS, QuotaScope.MACHINE))
102                   .setWriteNum(ProtobufUtil.toTimedQuota(600, TimeUnit.SECONDS, QuotaScope.MACHINE))
103                   .setReadSize(
104                     ProtobufUtil.toTimedQuota(8192, TimeUnit.SECONDS, QuotaScope.MACHINE)).build())
105             .build();
106 
107     // Add user quota and verify it
108     QuotaUtil.addTableQuota(this.connection, table, quota);
109     Quotas resQuota = QuotaUtil.getTableQuota(this.connection, table);
110     assertEquals(quota, resQuota);
111 
112     // Remove user quota and verify it
113     QuotaUtil.deleteTableQuota(this.connection, table);
114     resQuota = QuotaUtil.getTableQuota(this.connection, table);
115     assertEquals(null, resQuota);
116   }
117 
118   @Test
119   public void testNamespaceQuotaUtil() throws Exception {
120     final String namespace = "testNamespaceQuotaUtilNS";
121 
122     Quotas quota =
123         Quotas
124             .newBuilder()
125             .setThrottle(
126               Throttle
127                   .newBuilder()
128                   .setReqNum(ProtobufUtil.toTimedQuota(1000, TimeUnit.SECONDS, QuotaScope.MACHINE))
129                   .setWriteNum(ProtobufUtil.toTimedQuota(600, TimeUnit.SECONDS, QuotaScope.MACHINE))
130                   .setReadSize(
131                     ProtobufUtil.toTimedQuota(8192, TimeUnit.SECONDS, QuotaScope.MACHINE)).build())
132             .build();
133 
134     // Add user quota and verify it
135     QuotaUtil.addNamespaceQuota(this.connection, namespace, quota);
136     Quotas resQuota = QuotaUtil.getNamespaceQuota(this.connection, namespace);
137     assertEquals(quota, resQuota);
138 
139     // Remove user quota and verify it
140     QuotaUtil.deleteNamespaceQuota(this.connection, namespace);
141     resQuota = QuotaUtil.getNamespaceQuota(this.connection, namespace);
142     assertEquals(null, resQuota);
143   }
144 
145   @Test
146   public void testUserQuotaUtil() throws Exception {
147     final TableName table = TableName.valueOf("testUserQuotaUtilTable");
148     final String namespace = "testNS";
149     final String user = "testUser";
150 
151     Quotas quotaNamespace =
152         Quotas
153             .newBuilder()
154             .setThrottle(
155               Throttle
156                   .newBuilder()
157                   .setReqNum(ProtobufUtil.toTimedQuota(50000, TimeUnit.SECONDS, QuotaScope.MACHINE))
158                   .build()).build();
159     Quotas quotaTable =
160         Quotas
161             .newBuilder()
162             .setThrottle(
163               Throttle
164                   .newBuilder()
165                   .setReqNum(ProtobufUtil.toTimedQuota(1000, TimeUnit.SECONDS, QuotaScope.MACHINE))
166                   .setWriteNum(ProtobufUtil.toTimedQuota(600, TimeUnit.SECONDS, QuotaScope.MACHINE))
167                   .setReadSize(
168                     ProtobufUtil.toTimedQuota(10000, TimeUnit.SECONDS, QuotaScope.MACHINE)).build())
169             .build();
170     Quotas quota =
171         Quotas
172             .newBuilder()
173             .setThrottle(
174               Throttle
175                   .newBuilder()
176                   .setReqSize(ProtobufUtil.toTimedQuota(8192, TimeUnit.SECONDS, QuotaScope.MACHINE))
177                   .setWriteSize(
178                     ProtobufUtil.toTimedQuota(4096, TimeUnit.SECONDS, QuotaScope.MACHINE))
179                   .setReadNum(ProtobufUtil.toTimedQuota(1000, TimeUnit.SECONDS, QuotaScope.MACHINE))
180                   .build()).build();
181 
182     // Add user global quota
183     QuotaUtil.addUserQuota(this.connection, user, quota);
184     Quotas resQuota = QuotaUtil.getUserQuota(this.connection, user);
185     assertEquals(quota, resQuota);
186 
187     // Add user quota for table
188     QuotaUtil.addUserQuota(this.connection, user, table, quotaTable);
189     Quotas resQuotaTable = QuotaUtil.getUserQuota(this.connection, user, table);
190     assertEquals(quotaTable, resQuotaTable);
191 
192     // Add user quota for namespace
193     QuotaUtil.addUserQuota(this.connection, user, namespace, quotaNamespace);
194     Quotas resQuotaNS = QuotaUtil.getUserQuota(this.connection, user, namespace);
195     assertEquals(quotaNamespace, resQuotaNS);
196 
197     // Delete user global quota
198     QuotaUtil.deleteUserQuota(this.connection, user);
199     resQuota = QuotaUtil.getUserQuota(this.connection, user);
200     assertEquals(null, resQuota);
201 
202     // Delete user quota for table
203     QuotaUtil.deleteUserQuota(this.connection, user, table);
204     resQuotaTable = QuotaUtil.getUserQuota(this.connection, user, table);
205     assertEquals(null, resQuotaTable);
206 
207     // Delete user quota for namespace
208     QuotaUtil.deleteUserQuota(this.connection, user, namespace);
209     resQuotaNS = QuotaUtil.getUserQuota(this.connection, user, namespace);
210     assertEquals(null, resQuotaNS);
211   }
212 
213   @Test
214   public void testSerDeViolationPolicies() throws Exception {
215     final TableName tn1 = getUniqueTableName();
216     final SpaceQuotaSnapshot violation1 = new SpaceQuotaSnapshot(new SpaceQuotaStatus(SpaceViolationPolicy.DISABLE), 512L, 1024L);
217     final TableName tn2 = getUniqueTableName();
218     final SpaceQuotaSnapshot violation2 = new SpaceQuotaSnapshot(new SpaceQuotaStatus(SpaceViolationPolicy.NO_INSERTS), 512L, 1024L);
219     final TableName tn3 = getUniqueTableName();
220     final SpaceQuotaSnapshot violation3 = new SpaceQuotaSnapshot(new SpaceQuotaStatus(SpaceViolationPolicy.NO_WRITES), 512L, 1024L);
221     List<Put> puts = new ArrayList<>();
222     puts.add(QuotaTableUtil.putSpaceSnapshot(tn1, violation1));
223     puts.add(QuotaTableUtil.putSpaceSnapshot(tn2, violation2));
224     puts.add(QuotaTableUtil.putSpaceSnapshot(tn3, violation3));
225     final Map<TableName,SpaceQuotaSnapshot> expectedPolicies = new HashMap<>();
226     expectedPolicies.put(tn1, violation1);
227     expectedPolicies.put(tn2, violation2);
228     expectedPolicies.put(tn3, violation3);
229 
230     final Map<TableName,SpaceQuotaSnapshot> actualPolicies = new HashMap<>();
231     try (Table quotaTable = connection.getTable(QuotaUtil.QUOTA_TABLE_NAME)) {
232       quotaTable.put(puts);
233       ResultScanner scanner = quotaTable.getScanner(QuotaTableUtil.makeQuotaSnapshotScan());
234       for (Result r : scanner) {
235         QuotaTableUtil.extractQuotaSnapshot(r, actualPolicies);
236       }
237       scanner.close();
238     }
239 
240     assertEquals(expectedPolicies, actualPolicies);
241   }
242 
243   private TableName getUniqueTableName() {
244     return TableName.valueOf(testName.getMethodName() + "_" + tableNameCounter++);
245   }
246 }