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