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.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import java.io.IOException; 024import java.util.Set; 025import java.util.concurrent.TimeUnit; 026import java.util.concurrent.atomic.AtomicLong; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.HColumnDescriptor; 031import org.apache.hadoop.hbase.HTableDescriptor; 032import org.apache.hadoop.hbase.NamespaceDescriptor; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.client.Admin; 035import org.apache.hadoop.hbase.client.Connection; 036import org.apache.hadoop.hbase.master.HMaster; 037import org.apache.hadoop.hbase.master.MasterCoprocessorHost; 038import org.apache.hadoop.hbase.testclassification.MediumTests; 039import org.junit.AfterClass; 040import org.junit.Before; 041import org.junit.BeforeClass; 042import org.junit.ClassRule; 043import org.junit.Rule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.junit.rules.TestName; 047 048/** 049 * Test class for {@link MasterQuotasObserver}. 050 */ 051@Category(MediumTests.class) 052public class TestMasterQuotasObserver { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestMasterQuotasObserver.class); 057 058 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 059 private static SpaceQuotaHelperForTests helper; 060 061 @Rule 062 public TestName testName = new TestName(); 063 064 @BeforeClass 065 public static void setUp() throws Exception { 066 Configuration conf = TEST_UTIL.getConfiguration(); 067 conf.setBoolean(QuotaUtil.QUOTA_CONF_KEY, true); 068 TEST_UTIL.startMiniCluster(1); 069 } 070 071 @AfterClass 072 public static void tearDown() throws Exception { 073 TEST_UTIL.shutdownMiniCluster(); 074 } 075 076 @Before 077 public void removeAllQuotas() throws Exception { 078 if (helper == null) { 079 helper = new SpaceQuotaHelperForTests(TEST_UTIL, testName, new AtomicLong()); 080 } 081 final Connection conn = TEST_UTIL.getConnection(); 082 // Wait for the quota table to be created 083 if (!conn.getAdmin().tableExists(QuotaUtil.QUOTA_TABLE_NAME)) { 084 helper.waitForQuotaTable(conn); 085 } else { 086 // Or, clean up any quotas from previous test runs. 087 helper.removeAllQuotas(conn); 088 assertEquals(0, helper.listNumDefinedQuotas(conn)); 089 } 090 } 091 092 @Test 093 public void testTableSpaceQuotaRemoved() throws Exception { 094 final Connection conn = TEST_UTIL.getConnection(); 095 final Admin admin = conn.getAdmin(); 096 final TableName tn = TableName.valueOf(testName.getMethodName()); 097 // Drop the table if it somehow exists 098 if (admin.tableExists(tn)) { 099 dropTable(admin, tn); 100 } 101 createTable(admin, tn); 102 assertEquals(0, getNumSpaceQuotas()); 103 104 // Set space quota 105 QuotaSettings settings = QuotaSettingsFactory.limitTableSpace( 106 tn, 1024L, SpaceViolationPolicy.NO_INSERTS); 107 admin.setQuota(settings); 108 assertEquals(1, getNumSpaceQuotas()); 109 110 // Drop the table and observe the Space quota being automatically deleted as well 111 dropTable(admin, tn); 112 assertEquals(0, getNumSpaceQuotas()); 113 } 114 115 @Test 116 public void testTableRPCQuotaRemoved() throws Exception { 117 final Connection conn = TEST_UTIL.getConnection(); 118 final Admin admin = conn.getAdmin(); 119 final TableName tn = TableName.valueOf(testName.getMethodName()); 120 // Drop the table if it somehow exists 121 if (admin.tableExists(tn)) { 122 dropTable(admin, tn); 123 } 124 125 createTable(admin, tn); 126 assertEquals(0, getThrottleQuotas()); 127 128 // Set RPC quota 129 QuotaSettings settings = 130 QuotaSettingsFactory.throttleTable(tn, ThrottleType.REQUEST_SIZE, 2L, TimeUnit.HOURS); 131 admin.setQuota(settings); 132 133 assertEquals(1, getThrottleQuotas()); 134 135 // Delete the table and observe the RPC quota being automatically deleted as well 136 dropTable(admin, tn); 137 assertEquals(0, getThrottleQuotas()); 138 } 139 140 @Test 141 public void testTableSpaceAndRPCQuotaRemoved() throws Exception { 142 final Connection conn = TEST_UTIL.getConnection(); 143 final Admin admin = conn.getAdmin(); 144 final TableName tn = TableName.valueOf(testName.getMethodName()); 145 // Drop the table if it somehow exists 146 if (admin.tableExists(tn)) { 147 dropTable(admin, tn); 148 } 149 150 createTable(admin, tn); 151 assertEquals(0, getNumSpaceQuotas()); 152 assertEquals(0, getThrottleQuotas()); 153 154 // Set Both quotas 155 QuotaSettings settings = 156 QuotaSettingsFactory.limitTableSpace(tn, 1024L, SpaceViolationPolicy.NO_INSERTS); 157 admin.setQuota(settings); 158 159 settings = 160 QuotaSettingsFactory.throttleTable(tn, ThrottleType.REQUEST_SIZE, 2L, TimeUnit.HOURS); 161 admin.setQuota(settings); 162 163 assertEquals(1, getNumSpaceQuotas()); 164 assertEquals(1, getThrottleQuotas()); 165 166 // Delete the table and observe the quotas being automatically deleted as well 167 dropTable(admin, tn); 168 assertEquals(0, getNumSpaceQuotas()); 169 assertEquals(0, getThrottleQuotas()); 170 } 171 172 @Test 173 public void testNamespaceSpaceQuotaRemoved() throws Exception { 174 final Connection conn = TEST_UTIL.getConnection(); 175 final Admin admin = conn.getAdmin(); 176 final String ns = testName.getMethodName(); 177 // Drop the ns if it somehow exists 178 if (namespaceExists(ns)) { 179 admin.deleteNamespace(ns); 180 } 181 182 // Create the ns 183 NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build(); 184 admin.createNamespace(desc); 185 assertEquals(0, getNumSpaceQuotas()); 186 187 // Set a quota 188 QuotaSettings settings = QuotaSettingsFactory.limitNamespaceSpace( 189 ns, 1024L, SpaceViolationPolicy.NO_INSERTS); 190 admin.setQuota(settings); 191 assertEquals(1, getNumSpaceQuotas()); 192 193 // Delete the namespace and observe the quota being automatically deleted as well 194 admin.deleteNamespace(ns); 195 assertEquals(0, getNumSpaceQuotas()); 196 } 197 198 @Test 199 public void testNamespaceRPCQuotaRemoved() throws Exception { 200 final Connection conn = TEST_UTIL.getConnection(); 201 final Admin admin = conn.getAdmin(); 202 final String ns = testName.getMethodName(); 203 // Drop the ns if it somehow exists 204 if (namespaceExists(ns)) { 205 admin.deleteNamespace(ns); 206 } 207 208 // Create the ns 209 NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build(); 210 admin.createNamespace(desc); 211 assertEquals(0, getThrottleQuotas()); 212 213 // Set a quota 214 QuotaSettings settings = 215 QuotaSettingsFactory.throttleNamespace(ns, ThrottleType.REQUEST_SIZE, 2L, TimeUnit.HOURS); 216 admin.setQuota(settings); 217 assertEquals(1, getThrottleQuotas()); 218 219 // Delete the namespace and observe the quota being automatically deleted as well 220 admin.deleteNamespace(ns); 221 assertEquals(0, getThrottleQuotas()); 222 } 223 224 @Test 225 public void testNamespaceSpaceAndRPCQuotaRemoved() throws Exception { 226 final Connection conn = TEST_UTIL.getConnection(); 227 final Admin admin = conn.getAdmin(); 228 final TableName tn = TableName.valueOf(testName.getMethodName()); 229 final String ns = testName.getMethodName(); 230 // Drop the ns if it somehow exists 231 if (namespaceExists(ns)) { 232 admin.deleteNamespace(ns); 233 } 234 235 // Create the ns 236 NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build(); 237 admin.createNamespace(desc); 238 assertEquals(0, getNumSpaceQuotas()); 239 assertEquals(0, getThrottleQuotas()); 240 241 // Set Both quotas 242 QuotaSettings settings = 243 QuotaSettingsFactory.limitNamespaceSpace(ns, 1024L, SpaceViolationPolicy.NO_INSERTS); 244 admin.setQuota(settings); 245 246 settings = 247 QuotaSettingsFactory.throttleNamespace(ns, ThrottleType.REQUEST_SIZE, 2L, TimeUnit.HOURS); 248 admin.setQuota(settings); 249 250 assertEquals(1, getNumSpaceQuotas()); 251 assertEquals(1, getThrottleQuotas()); 252 253 // Delete the namespace and observe the quotas being automatically deleted as well 254 admin.deleteNamespace(ns); 255 assertEquals(0, getNumSpaceQuotas()); 256 assertEquals(0, getThrottleQuotas()); 257 } 258 259 @Test 260 public void testObserverAddedByDefault() throws Exception { 261 final HMaster master = TEST_UTIL.getHBaseCluster().getMaster(); 262 final MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost(); 263 Set<String> coprocessorNames = cpHost.getCoprocessors(); 264 assertTrue( 265 "Did not find MasterQuotasObserver in list of CPs: " + coprocessorNames, 266 coprocessorNames.contains(MasterQuotasObserver.class.getSimpleName())); 267 } 268 269 public boolean namespaceExists(String ns) throws IOException { 270 NamespaceDescriptor[] descs = TEST_UTIL.getAdmin().listNamespaceDescriptors(); 271 for (NamespaceDescriptor desc : descs) { 272 if (ns.equals(desc.getName())) { 273 return true; 274 } 275 } 276 return false; 277 } 278 279 public int getNumSpaceQuotas() throws Exception { 280 QuotaRetriever scanner = QuotaRetriever.open(TEST_UTIL.getConfiguration()); 281 int numSpaceQuotas = 0; 282 for (QuotaSettings quotaSettings : scanner) { 283 if (quotaSettings.getQuotaType() == QuotaType.SPACE) { 284 numSpaceQuotas++; 285 } 286 } 287 return numSpaceQuotas; 288 } 289 290 public int getThrottleQuotas() throws Exception { 291 QuotaRetriever scanner = QuotaRetriever.open(TEST_UTIL.getConfiguration()); 292 int throttleQuotas = 0; 293 for (QuotaSettings quotaSettings : scanner) { 294 if (quotaSettings.getQuotaType() == QuotaType.THROTTLE) { 295 throttleQuotas++; 296 } 297 } 298 return throttleQuotas; 299 } 300 301 private void createTable(Admin admin, TableName tn) throws Exception { 302 // Create a table 303 HTableDescriptor tableDesc = new HTableDescriptor(tn); 304 tableDesc.addFamily(new HColumnDescriptor("F1")); 305 admin.createTable(tableDesc); 306 } 307 308 private void dropTable(Admin admin, TableName tn) throws Exception { 309 admin.disableTable(tn); 310 admin.deleteTable(tn); 311 } 312}