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.HConstants;
26  import org.apache.hadoop.hbase.HTableDescriptor;
27  import org.apache.hadoop.hbase.HRegionInfo;
28  import org.apache.hadoop.hbase.ProcedureInfo;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.TableNotDisabledException;
31  import org.apache.hadoop.hbase.TableNotFoundException;
32  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
33  import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
34  import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.DeleteTableState;
35  import org.apache.hadoop.hbase.testclassification.MediumTests;
36  import org.apache.hadoop.hbase.util.Bytes;
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.assertTrue;
45  
46  @Category(MediumTests.class)
47  public class TestDeleteTableProcedure {
48    private static final Log LOG = LogFactory.getLog(TestDeleteTableProcedure.class);
49  
50    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
51  
52    private long nonceGroup = HConstants.NO_NONCE;
53    private long nonce = HConstants.NO_NONCE;
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      nonceGroup =
81          MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
82      nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
83    }
84  
85    @After
86    public void tearDown() throws Exception {
87      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
88      for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
89        LOG.info("Tear down, remove table=" + htd.getTableName());
90        UTIL.deleteTable(htd.getTableName());
91      }
92    }
93  
94    @Test(timeout=60000, expected=TableNotFoundException.class)
95    public void testDeleteNotExistentTable() throws Exception {
96      final TableName tableName = TableName.valueOf("testDeleteNotExistentTable");
97  
98      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
99      ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch();
100     long procId = ProcedureTestingUtility.submitAndWait(procExec,
101         new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch));
102     latch.await();
103   }
104 
105   @Test(timeout=60000, expected=TableNotDisabledException.class)
106   public void testDeleteNotDisabledTable() throws Exception {
107     final TableName tableName = TableName.valueOf("testDeleteNotDisabledTable");
108 
109     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
110     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
111 
112     ProcedurePrepareLatch latch = new ProcedurePrepareLatch.CompatibilityLatch();
113     long procId = ProcedureTestingUtility.submitAndWait(procExec,
114         new DeleteTableProcedure(procExec.getEnvironment(), tableName, latch));
115     latch.await();
116   }
117 
118   @Test(timeout=60000)
119   public void testDeleteDeletedTable() throws Exception {
120     final TableName tableName = TableName.valueOf("testDeleteDeletedTable");
121     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
122 
123     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
124       procExec, tableName, null, "f");
125     UTIL.getHBaseAdmin().disableTable(tableName);
126 
127     // delete the table (that exists)
128     long procId1 = procExec.submitProcedure(
129         new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce);
130     // delete the table (that will no longer exist)
131     long procId2 = procExec.submitProcedure(
132         new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup + 1, nonce + 1);
133 
134     // Wait the completion
135     ProcedureTestingUtility.waitProcedure(procExec, procId1);
136     ProcedureTestingUtility.waitProcedure(procExec, procId2);
137 
138     // First delete should succeed
139     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
140     MasterProcedureTestingUtility.validateTableDeletion(
141       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f");
142 
143     // Second delete should fail with TableNotFound
144     ProcedureInfo result = procExec.getResult(procId2);
145     assertTrue(result.isFailed());
146     LOG.debug("Delete failed with exception: " + result.getExceptionFullMessage());
147     assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotFoundException);
148   }
149 
150   @Test(timeout=60000)
151   public void testDoubleDeletedTableWithSameNonce() throws Exception {
152     final TableName tableName = TableName.valueOf("testDoubleDeletedTableWithSameNonce");
153     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
154 
155     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
156       procExec, tableName, null, "f");
157     UTIL.getHBaseAdmin().disableTable(tableName);
158 
159     // delete the table (that exists)
160     long procId1 = procExec.submitProcedure(
161         new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce);
162     // delete the table (that will no longer exist)
163     long procId2 = procExec.submitProcedure(
164         new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce);
165 
166     // Wait the completion
167     ProcedureTestingUtility.waitProcedure(procExec, procId1);
168     ProcedureTestingUtility.waitProcedure(procExec, procId2);
169 
170     // First delete should succeed
171     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
172     MasterProcedureTestingUtility.validateTableDeletion(
173       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f");
174 
175     // Second delete should not fail, because it is the same delete
176     ProcedureTestingUtility.assertProcNotFailed(procExec, procId2);
177     assertTrue(procId1 == procId2);
178   }
179 
180   @Test(timeout=60000)
181   public void testSimpleDelete() throws Exception {
182     final TableName tableName = TableName.valueOf("testSimpleDelete");
183     final byte[][] splitKeys = null;
184     testSimpleDelete(tableName, splitKeys);
185   }
186 
187   @Test(timeout=60000)
188   public void testSimpleDeleteWithSplits() throws Exception {
189     final TableName tableName = TableName.valueOf("testSimpleDeleteWithSplits");
190     final byte[][] splitKeys = new byte[][] {
191       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
192     };
193     testSimpleDelete(tableName, splitKeys);
194   }
195 
196   private void testSimpleDelete(final TableName tableName, byte[][] splitKeys) throws Exception {
197     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
198       getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
199     UTIL.getHBaseAdmin().disableTable(tableName);
200 
201     // delete the table
202     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
203     long procId = ProcedureTestingUtility.submitAndWait(procExec,
204       new DeleteTableProcedure(procExec.getEnvironment(), tableName));
205     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
206     MasterProcedureTestingUtility.validateTableDeletion(
207       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
208   }
209 
210   @Test(timeout=60000)
211   public void testRecoveryAndDoubleExecution() throws Exception {
212     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
213 
214     // create the table
215     byte[][] splitKeys = null;
216     HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
217       getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
218     UTIL.getHBaseAdmin().disableTable(tableName);
219 
220     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
221     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
222     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
223 
224     // Start the Delete procedure && kill the executor
225     long procId = procExec.submitProcedure(
226       new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce);
227 
228     // Restart the executor and execute the step twice
229     // NOTE: the 6 (number of DeleteTableState steps) is hardcoded,
230     //       so you have to look at this test at least once when you add a new step.
231     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
232       procExec, procId, 6, DeleteTableState.values());
233 
234     MasterProcedureTestingUtility.validateTableDeletion(
235       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
236   }
237 
238   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
239     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
240   }
241 }