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.master.procedure; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNull; 022import static org.junit.Assert.assertTrue; 023 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.HBaseClassTestRule; 026import org.apache.hadoop.hbase.HBaseTestingUtility; 027import org.apache.hadoop.hbase.NamespaceDescriptor; 028import org.apache.hadoop.hbase.NamespaceNotFoundException; 029import org.apache.hadoop.hbase.client.TableDescriptor; 030import org.apache.hadoop.hbase.constraint.ConstraintException; 031import org.apache.hadoop.hbase.procedure2.Procedure; 032import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 033import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 034import org.apache.hadoop.hbase.testclassification.MasterTests; 035import org.apache.hadoop.hbase.testclassification.MediumTests; 036import org.junit.After; 037import org.junit.AfterClass; 038import org.junit.Before; 039import org.junit.BeforeClass; 040import org.junit.ClassRule; 041import org.junit.Test; 042import org.junit.experimental.categories.Category; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046@Category({MasterTests.class, MediumTests.class}) 047public class TestModifyNamespaceProcedure { 048 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = 051 HBaseClassTestRule.forClass(TestModifyNamespaceProcedure.class); 052 053 private static final Logger LOG = LoggerFactory.getLogger(TestModifyNamespaceProcedure.class); 054 055 protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 056 057 private static void setupConf(Configuration conf) { 058 conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); 059 conf.setInt(MasterProcedureConstants.MASTER_URGENT_PROCEDURE_THREADS, 0); 060 } 061 062 @BeforeClass 063 public static void setupCluster() throws Exception { 064 setupConf(UTIL.getConfiguration()); 065 UTIL.startMiniCluster(1); 066 } 067 068 @AfterClass 069 public static void cleanupTest() throws Exception { 070 try { 071 UTIL.shutdownMiniCluster(); 072 } catch (Exception e) { 073 LOG.warn("failure shutting down cluster", e); 074 } 075 } 076 077 @Before 078 public void setup() throws Exception { 079 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); 080 } 081 082 @After 083 public void tearDown() throws Exception { 084 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); 085 for (TableDescriptor htd: UTIL.getAdmin().listTableDescriptors()) { 086 LOG.info("Tear down, remove table=" + htd.getTableName()); 087 UTIL.deleteTable(htd.getTableName()); 088 } 089 } 090 091 092 @Test 093 public void testModifyNamespace() throws Exception { 094 final NamespaceDescriptor nsd = NamespaceDescriptor.create("testModifyNamespace").build(); 095 final String nsKey1 = "hbase.namespace.quota.maxregions"; 096 final String nsValue1before = "1111"; 097 final String nsValue1after = "9999"; 098 final String nsKey2 = "hbase.namespace.quota.maxtables"; 099 final String nsValue2 = "10"; 100 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 101 102 nsd.setConfiguration(nsKey1, nsValue1before); 103 createNamespaceForTesting(nsd); 104 105 // Before modify 106 NamespaceDescriptor currentNsDescriptor = 107 UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 108 assertEquals(nsValue1before, currentNsDescriptor.getConfigurationValue(nsKey1)); 109 assertNull(currentNsDescriptor.getConfigurationValue(nsKey2)); 110 111 // Update 112 nsd.setConfiguration(nsKey1, nsValue1after); 113 nsd.setConfiguration(nsKey2, nsValue2); 114 115 long procId1 = procExec.submitProcedure( 116 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 117 // Wait the completion 118 ProcedureTestingUtility.waitProcedure(procExec, procId1); 119 ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); 120 121 // Verify the namespace is updated. 122 currentNsDescriptor = 123 UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 124 assertEquals(nsValue1after, nsd.getConfigurationValue(nsKey1)); 125 assertEquals(nsValue2, currentNsDescriptor.getConfigurationValue(nsKey2)); 126 } 127 128 @Test 129 public void testModifyNonExistNamespace() throws Exception { 130 final String namespaceName = "testModifyNonExistNamespace"; 131 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 132 133 try { 134 NamespaceDescriptor nsDescriptor = UTIL.getAdmin().getNamespaceDescriptor(namespaceName); 135 assertNull(nsDescriptor); 136 } catch (NamespaceNotFoundException nsnfe) { 137 // Expected 138 LOG.debug("The namespace " + namespaceName + " does not exist. This is expected."); 139 } 140 141 final NamespaceDescriptor nsd = NamespaceDescriptor.create(namespaceName).build(); 142 143 long procId = procExec.submitProcedure( 144 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 145 // Wait the completion 146 ProcedureTestingUtility.waitProcedure(procExec, procId); 147 148 // Expect fail with NamespaceNotFoundException 149 Procedure<?> result = procExec.getResult(procId); 150 assertTrue(result.isFailed()); 151 LOG.debug("modify namespace failed with exception: " + result.getException()); 152 assertTrue( 153 ProcedureTestingUtility.getExceptionCause(result) instanceof NamespaceNotFoundException); 154 } 155 156 @Test 157 public void testModifyNamespaceWithInvalidRegionCount() throws Exception { 158 final NamespaceDescriptor nsd = 159 NamespaceDescriptor.create("testModifyNamespaceWithInvalidRegionCount").build(); 160 final String nsKey = "hbase.namespace.quota.maxregions"; 161 final String nsValue = "-1"; 162 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 163 164 createNamespaceForTesting(nsd); 165 166 // Modify 167 nsd.setConfiguration(nsKey, nsValue); 168 169 long procId = procExec.submitProcedure( 170 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 171 // Wait the completion 172 ProcedureTestingUtility.waitProcedure(procExec, procId); 173 Procedure<?> result = procExec.getResult(procId); 174 assertTrue(result.isFailed()); 175 LOG.debug("Modify namespace failed with exception: " + result.getException()); 176 assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); 177 } 178 179 @Test 180 public void testModifyNamespaceWithInvalidTableCount() throws Exception { 181 final NamespaceDescriptor nsd = 182 NamespaceDescriptor.create("testModifyNamespaceWithInvalidTableCount").build(); 183 final String nsKey = "hbase.namespace.quota.maxtables"; 184 final String nsValue = "-1"; 185 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 186 187 createNamespaceForTesting(nsd); 188 189 // Modify 190 nsd.setConfiguration(nsKey, nsValue); 191 192 long procId = procExec.submitProcedure( 193 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 194 // Wait the completion 195 ProcedureTestingUtility.waitProcedure(procExec, procId); 196 Procedure<?> result = procExec.getResult(procId); 197 assertTrue(result.isFailed()); 198 LOG.debug("Modify namespace failed with exception: " + result.getException()); 199 assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); 200 } 201 202 @Test 203 public void testRecoveryAndDoubleExecution() throws Exception { 204 final NamespaceDescriptor nsd = 205 NamespaceDescriptor.create("testRecoveryAndDoubleExecution").build(); 206 final String nsKey = "foo"; 207 final String nsValue = "bar"; 208 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 209 210 createNamespaceForTesting(nsd); 211 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 212 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 213 214 // Modify 215 nsd.setConfiguration(nsKey, nsValue); 216 217 // Start the Modify procedure && kill the executor 218 long procId = procExec.submitProcedure( 219 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 220 221 // Restart the executor and execute the step twice 222 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 223 224 ProcedureTestingUtility.assertProcNotFailed(procExec, procId); 225 // Validate 226 NamespaceDescriptor currentNsDescriptor = 227 UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 228 assertEquals(nsValue, currentNsDescriptor.getConfigurationValue(nsKey)); 229 } 230 231 @Test 232 public void testRollbackAndDoubleExecution() throws Exception { 233 final NamespaceDescriptor nsd = 234 NamespaceDescriptor.create("testRollbackAndDoubleExecution").build(); 235 final String nsKey = "foo"; 236 final String nsValue = "bar"; 237 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 238 239 createNamespaceForTesting(nsd); 240 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 241 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 242 243 // Modify 244 nsd.setConfiguration(nsKey, nsValue); 245 246 // Start the Modify procedure && kill the executor 247 long procId = procExec.submitProcedure( 248 new ModifyNamespaceProcedure(procExec.getEnvironment(), nsd)); 249 250 int lastStep = 2; // failing before MODIFY_NAMESPACE_UPDATE_NS_TABLE 251 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(procExec, procId, lastStep); 252 253 // Validate 254 NamespaceDescriptor currentNsDescriptor = 255 UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 256 assertNull(currentNsDescriptor.getConfigurationValue(nsKey)); 257 } 258 259 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() { 260 return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); 261 } 262 263 private void createNamespaceForTesting(NamespaceDescriptor nsDescriptor) throws Exception { 264 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 265 266 long procId = procExec.submitProcedure( 267 new CreateNamespaceProcedure(procExec.getEnvironment(), nsDescriptor)); 268 // Wait the completion 269 ProcedureTestingUtility.waitProcedure(procExec, procId); 270 ProcedureTestingUtility.assertProcNotFailed(procExec, procId); 271 } 272}