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