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