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.assertNotNull; 021import static org.junit.jupiter.api.Assertions.assertNull; 022import static org.junit.jupiter.api.Assertions.assertThrows; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024 025import java.util.ArrayList; 026import java.util.List; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.hadoop.hbase.TableNotDisabledException; 029import org.apache.hadoop.hbase.TableNotFoundException; 030import org.apache.hadoop.hbase.client.RegionInfo; 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.apache.hadoop.hbase.util.Bytes; 037import org.junit.jupiter.api.AfterAll; 038import org.junit.jupiter.api.BeforeAll; 039import org.junit.jupiter.api.BeforeEach; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042import org.junit.jupiter.api.TestInfo; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046@Tag(MasterTests.TAG) 047@Tag(MediumTests.TAG) 048public class TestDeleteTableProcedure extends TestTableDDLProcedureBase { 049 050 private static final Logger LOG = LoggerFactory.getLogger(TestDeleteTableProcedure.class); 051 private String testMethodName; 052 053 @BeforeAll 054 public static void setupCluster() throws Exception { 055 TestTableDDLProcedureBase.setupCluster(); 056 } 057 058 @AfterAll 059 public static void cleanupTest() throws Exception { 060 TestTableDDLProcedureBase.cleanupTest(); 061 } 062 063 @BeforeEach 064 public void setTestMethod(TestInfo testInfo) { 065 testMethodName = testInfo.getTestMethod().get().getName(); 066 } 067 068 @Test 069 public void testDeleteNotExistentTable() throws Exception { 070 final TableName tableName = TableName.valueOf(testMethodName); 071 072 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 073 assertThrows(TableNotFoundException.class, () -> { 074 ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch(); 075 ProcedureTestingUtility.submitAndWait(procExec, 076 new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch)); 077 latch.await(); 078 }); 079 } 080 081 @Test 082 public void testDeleteNotDisabledTable() throws Exception { 083 final TableName tableName = TableName.valueOf(testMethodName); 084 085 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 086 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f"); 087 088 assertThrows(TableNotDisabledException.class, () -> { 089 ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch(); 090 ProcedureTestingUtility.submitAndWait(procExec, 091 new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch)); 092 latch.await(); 093 }); 094 } 095 096 @Test 097 public void testDeleteDeletedTable() throws Exception { 098 final TableName tableName = TableName.valueOf(testMethodName); 099 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 100 101 RegionInfo[] regions = 102 MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f"); 103 UTIL.getAdmin().disableTable(tableName); 104 105 // delete the table (that exists) 106 long procId1 = 107 procExec.submitProcedure(new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 108 // delete the table (that will no longer exist) 109 long procId2 = 110 procExec.submitProcedure(new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 111 112 // Wait the completion 113 ProcedureTestingUtility.waitProcedure(procExec, procId1); 114 ProcedureTestingUtility.waitProcedure(procExec, procId2); 115 116 // First delete should succeed 117 ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); 118 MasterProcedureTestingUtility.validateTableDeletion(getMaster(), tableName); 119 120 // Second delete should fail with TableNotFound 121 Procedure<?> result = procExec.getResult(procId2); 122 assertTrue(result.isFailed()); 123 LOG.debug("Delete failed with exception: " + result.getException()); 124 assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotFoundException); 125 } 126 127 @Test 128 public void testSimpleDelete() throws Exception { 129 final TableName tableName = TableName.valueOf(testMethodName); 130 final byte[][] splitKeys = null; 131 testSimpleDelete(tableName, splitKeys); 132 } 133 134 @Test 135 public void testSimpleDeleteWithSplits() throws Exception { 136 final TableName tableName = TableName.valueOf(testMethodName); 137 final byte[][] splitKeys = 138 new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c") }; 139 testSimpleDelete(tableName, splitKeys); 140 } 141 142 @Test 143 public void testDeleteFromMeta() throws Exception { 144 final TableName tableName = TableName.valueOf(testMethodName); 145 RegionInfo[] regions = MasterProcedureTestingUtility.createTable(getMasterProcedureExecutor(), 146 tableName, null, "f1", "f2"); 147 List<RegionInfo> regionsList = new ArrayList<>(); 148 UTIL.getAdmin().disableTable(tableName); 149 MasterProcedureEnv procedureEnv = getMasterProcedureExecutor().getEnvironment(); 150 assertNotNull(procedureEnv.getMasterServices().getTableDescriptors().get(tableName), 151 "Table should be on TableDescriptors cache."); 152 DeleteTableProcedure.deleteFromMeta(procedureEnv, tableName, regionsList); 153 assertNull(procedureEnv.getMasterServices().getTableDescriptors().get(tableName), 154 "Table shouldn't be on TableDescriptors anymore."); 155 } 156 157 private void testSimpleDelete(final TableName tableName, byte[][] splitKeys) throws Exception { 158 RegionInfo[] regions = MasterProcedureTestingUtility.createTable(getMasterProcedureExecutor(), 159 tableName, splitKeys, "f1", "f2"); 160 UTIL.getAdmin().disableTable(tableName); 161 162 // delete the table 163 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 164 long procId = ProcedureTestingUtility.submitAndWait(procExec, 165 new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 166 ProcedureTestingUtility.assertProcNotFailed(procExec, procId); 167 MasterProcedureTestingUtility.validateTableDeletion(getMaster(), tableName); 168 } 169 170 @Test 171 public void testRecoveryAndDoubleExecution() throws Exception { 172 final TableName tableName = TableName.valueOf(testMethodName); 173 174 // create the table 175 byte[][] splitKeys = null; 176 RegionInfo[] regions = MasterProcedureTestingUtility.createTable(getMasterProcedureExecutor(), 177 tableName, splitKeys, "f1", "f2"); 178 UTIL.getAdmin().disableTable(tableName); 179 180 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 181 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 182 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 183 184 // Start the Delete procedure && kill the executor 185 long procId = 186 procExec.submitProcedure(new DeleteTableProcedure(procExec.getEnvironment(), tableName)); 187 188 // Restart the executor and execute the step twice 189 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 190 191 MasterProcedureTestingUtility.validateTableDeletion(getMaster(), tableName); 192 } 193}