View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.master.procedure;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.conf.Configuration;
24  import org.apache.hadoop.hbase.HBaseTestingUtility;
25  import org.apache.hadoop.hbase.HTableDescriptor;
26  import org.apache.hadoop.hbase.HRegionInfo;
27  import org.apache.hadoop.hbase.ProcedureInfo;
28  import org.apache.hadoop.hbase.TableName;
29  import org.apache.hadoop.hbase.TableNotDisabledException;
30  import org.apache.hadoop.hbase.TableNotFoundException;
31  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
32  import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
33  import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.DeleteTableState;
34  import org.apache.hadoop.hbase.testclassification.MediumTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  
37  import org.junit.After;
38  import org.junit.AfterClass;
39  import org.junit.Before;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  
44  import static org.junit.Assert.assertEquals;
45  import static org.junit.Assert.assertFalse;
46  import static org.junit.Assert.assertTrue;
47  import static org.junit.Assert.fail;
48  
49  @Category(MediumTests.class)
50  public class TestDeleteTableProcedure {
51    private static final Log LOG = LogFactory.getLog(TestDeleteTableProcedure.class);
52  
53    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
54  
55    private static void setupConf(Configuration conf) {
56      conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
57    }
58  
59    @BeforeClass
60    public static void setupCluster() throws Exception {
61      setupConf(UTIL.getConfiguration());
62      UTIL.startMiniCluster(1);
63    }
64  
65    @AfterClass
66    public static void cleanupTest() throws Exception {
67      try {
68        UTIL.shutdownMiniCluster();
69      } catch (Exception e) {
70        LOG.warn("failure shutting down cluster", e);
71      }
72    }
73  
74    @Before
75    public void setup() throws Exception {
76      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
77      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
78      assertTrue("expected executor to be running", procExec.isRunning());
79    }
80  
81    @After
82    public void tearDown() throws Exception {
83      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
84      for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
85        LOG.info("Tear down, remove table=" + htd.getTableName());
86        UTIL.deleteTable(htd.getTableName());
87      }
88    }
89  
90    @Test(timeout=60000, expected=TableNotFoundException.class)
91    public void testDeleteNotExistentTable() throws Exception {
92      final TableName tableName = TableName.valueOf("testDeleteNotExistentTable");
93  
94      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
95      ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch();
96      long procId = ProcedureTestingUtility.submitAndWait(procExec,
97          new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch));
98      latch.await();
99    }
100 
101   @Test(timeout=60000, expected=TableNotDisabledException.class)
102   public void testDeleteNotDisabledTable() throws Exception {
103     final TableName tableName = TableName.valueOf("testDeleteNotDisabledTable");
104 
105     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
106     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
107 
108     ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch();
109     long procId = ProcedureTestingUtility.submitAndWait(procExec,
110         new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch));
111     latch.await();
112   }
113 
114   @Test(timeout=60000)
115   public void testDeleteDeletedTable() throws Exception {
116     final TableName tableName = TableName.valueOf("testDeleteDeletedTable");
117     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
118 
119     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
120       procExec, tableName, null, "f");
121     UTIL.getHBaseAdmin().disableTable(tableName);
122 
123     // delete the table (that exists)
124     long procId1 = procExec.submitProcedure(
125         new DeleteTableProcedure(procExec.getEnvironment(), tableName));
126     // delete the table (that will no longer exist)
127     long procId2 = procExec.submitProcedure(
128         new DeleteTableProcedure(procExec.getEnvironment(), tableName));
129 
130     // Wait the completion
131     ProcedureTestingUtility.waitProcedure(procExec, procId1);
132     ProcedureTestingUtility.waitProcedure(procExec, procId2);
133 
134     // First delete should succeed
135     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
136     MasterProcedureTestingUtility.validateTableDeletion(
137       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f");
138 
139     // Second delete should fail with TableNotFound
140     ProcedureInfo result = procExec.getResult(procId2);
141     assertTrue(result.isFailed());
142     LOG.debug("Delete failed with exception: " + result.getExceptionFullMessage());
143     assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotFoundException);
144   }
145 
146   @Test(timeout=60000)
147   public void testSimpleDelete() throws Exception {
148     final TableName tableName = TableName.valueOf("testSimpleDelete");
149     final byte[][] splitKeys = null;
150     testSimpleDelete(tableName, splitKeys);
151   }
152 
153   @Test(timeout=60000)
154   public void testSimpleDeleteWithSplits() throws Exception {
155     final TableName tableName = TableName.valueOf("testSimpleDeleteWithSplits");
156     final byte[][] splitKeys = new byte[][] {
157       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
158     };
159     testSimpleDelete(tableName, splitKeys);
160   }
161 
162   private void testSimpleDelete(final TableName tableName, byte[][] splitKeys) throws Exception {
163     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
164       getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
165     UTIL.getHBaseAdmin().disableTable(tableName);
166 
167     // delete the table
168     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
169     long procId = ProcedureTestingUtility.submitAndWait(procExec,
170       new DeleteTableProcedure(procExec.getEnvironment(), tableName));
171     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
172     MasterProcedureTestingUtility.validateTableDeletion(
173       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
174   }
175 
176   @Test(timeout=60000)
177   public void testRecoveryAndDoubleExecution() throws Exception {
178     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
179 
180     // create the table
181     byte[][] splitKeys = null;
182     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
183       getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
184     UTIL.getHBaseAdmin().disableTable(tableName);
185 
186     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
187     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
188     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
189 
190     // Start the Delete procedure && kill the executor
191     long procId = procExec.submitProcedure(
192       new DeleteTableProcedure(procExec.getEnvironment(), tableName));
193 
194     // Restart the executor and execute the step twice
195     // NOTE: the 6 (number of DeleteTableState steps) is hardcoded,
196     //       so you have to look at this test at least once when you add a new step.
197     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
198       procExec, procId, 6, DeleteTableState.values());
199 
200     MasterProcedureTestingUtility.validateTableDeletion(
201       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
202   }
203 
204   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
205     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
206   }
207 }