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