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 static org.junit.Assert.assertTrue;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.ProcedureInfo;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.TableNotEnabledException;
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.DisableTableState;
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.Assert;
40  import org.junit.Before;
41  import org.junit.BeforeClass;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  @Category(MediumTests.class)
46  public class TestDisableTableProcedure {
47    private static final Log LOG = LogFactory.getLog(TestDisableTableProcedure.class);
48  
49    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
50  
51    private static void setupConf(Configuration conf) {
52      conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
53    }
54  
55    @BeforeClass
56    public static void setupCluster() throws Exception {
57      setupConf(UTIL.getConfiguration());
58      UTIL.startMiniCluster(1);
59    }
60  
61    @AfterClass
62    public static void cleanupTest() throws Exception {
63      try {
64        UTIL.shutdownMiniCluster();
65      } catch (Exception e) {
66        LOG.warn("failure shutting down cluster", e);
67      }
68    }
69  
70    @Before
71    public void setup() throws Exception {
72      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
73    }
74  
75    @After
76    public void tearDown() throws Exception {
77      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
78      for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
79        LOG.info("Tear down, remove table=" + htd.getTableName());
80        UTIL.deleteTable(htd.getTableName());
81      }
82    }
83  
84    @Test(timeout = 60000)
85    public void testDisableTable() throws Exception {
86      final TableName tableName = TableName.valueOf("testDisableTable");
87      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
88  
89      MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
90  
91      // Disable the table
92      long procId = procExec.submitProcedure(
93        new DisableTableProcedure(procExec.getEnvironment(), tableName, false));
94      // Wait the completion
95      ProcedureTestingUtility.waitProcedure(procExec, procId);
96      ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
97      MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
98        tableName);
99    }
100 
101   @Test(timeout = 60000)
102   public void testDisableTableMultipleTimes() throws Exception {
103     final TableName tableName = TableName.valueOf("testDisableTableMultipleTimes");
104     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
105 
106     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
107 
108     // Disable the table
109     long procId1 = procExec.submitProcedure(new DisableTableProcedure(
110         procExec.getEnvironment(), tableName, false));
111     // Wait the completion
112     ProcedureTestingUtility.waitProcedure(procExec, procId1);
113     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
114     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
115       tableName);
116 
117     // Disable the table again - expect failure
118     long procId2 = procExec.submitProcedure(new DisableTableProcedure(
119         procExec.getEnvironment(), tableName, false));
120     // Wait the completion
121     ProcedureTestingUtility.waitProcedure(procExec, procId2);
122     ProcedureInfo result = procExec.getResult(procId2);
123     assertTrue(result.isFailed());
124     LOG.debug("Disable failed with exception: " + result.getExceptionFullMessage());
125     assertTrue(
126       ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotEnabledException);
127 
128     // Disable the table - expect failure from ProcedurePrepareLatch
129     try {
130       final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch();
131 
132       long procId3 = procExec.submitProcedure(new DisableTableProcedure(
133           procExec.getEnvironment(), tableName, false, prepareLatch));
134       prepareLatch.await();
135       Assert.fail("Disable should throw exception through latch.");
136     } catch (TableNotEnabledException tnee) {
137       // Expected
138       LOG.debug("Disable failed with expected exception.");
139     }
140 
141     // Disable the table again with skipping table state check flag (simulate recovery scenario)
142     long procId4 = procExec.submitProcedure(new DisableTableProcedure(
143         procExec.getEnvironment(), tableName, true));
144     // Wait the completion
145     ProcedureTestingUtility.waitProcedure(procExec, procId4);
146     ProcedureTestingUtility.assertProcNotFailed(procExec, procId4);
147     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
148       tableName);
149   }
150 
151   @Test(timeout=60000)
152   public void testRecoveryAndDoubleExecution() throws Exception {
153     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
154     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
155 
156     final byte[][] splitKeys = new byte[][] {
157       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
158     };
159     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
160 
161     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
162 
163     // Start the Disable procedure && kill the executor
164     long procId =
165         procExec.submitProcedure(new DisableTableProcedure(procExec.getEnvironment(), tableName,
166             false));
167 
168     // Restart the executor and execute the step twice
169     int numberOfSteps = DisableTableState.values().length;
170     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
171       procExec,
172       procId,
173       numberOfSteps,
174       DisableTableState.values());
175     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
176       tableName);
177   }
178 
179   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
180     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
181   }
182 }