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.TableNotDisabledException;
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.EnableTableState;
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 TestEnableTableProcedure {
46    private static final Log LOG = LogFactory.getLog(TestEnableTableProcedure.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 testEnableTable() throws Exception {
85      final TableName tableName = TableName.valueOf("testEnableTable");
86      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
87  
88      MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
89      UTIL.getHBaseAdmin().disableTable(tableName);
90  
91      // Enable the table
92      long procId = procExec.submitProcedure(
93        new EnableTableProcedure(procExec.getEnvironment(), tableName, false));
94      // Wait the completion
95      ProcedureTestingUtility.waitProcedure(procExec, procId);
96      ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
97      MasterProcedureTestingUtility.validateTableIsEnabled(UTIL.getHBaseCluster().getMaster(),
98        tableName);
99    }
100 
101   @Test(timeout=60000, expected=TableNotDisabledException.class)
102   public void testEnableNonDisabledTable() throws Exception {
103     final TableName tableName = TableName.valueOf("testEnableNonExistingTable");
104     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
105 
106     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
107 
108     // Enable the table - expect failure
109     long procId1 = procExec.submitProcedure(
110         new EnableTableProcedure(procExec.getEnvironment(), tableName, false));
111     ProcedureTestingUtility.waitProcedure(procExec, procId1);
112 
113     ProcedureInfo result = procExec.getResult(procId1);
114     assertTrue(result.isFailed());
115     LOG.debug("Enable failed with exception: " + result.getExceptionFullMessage());
116     assertTrue(
117       ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotDisabledException);
118 
119     // Enable the table with skipping table state check flag (simulate recovery scenario)
120     long procId2 = procExec.submitProcedure(
121         new EnableTableProcedure(procExec.getEnvironment(), tableName, true));
122     // Wait the completion
123     ProcedureTestingUtility.waitProcedure(procExec, procId2);
124     ProcedureTestingUtility.assertProcNotFailed(procExec, procId2);
125 
126     // Enable the table - expect failure from ProcedurePrepareLatch
127     final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch();
128     long procId3 = procExec.submitProcedure(
129         new EnableTableProcedure(procExec.getEnvironment(), tableName, false, prepareLatch));
130     prepareLatch.await();
131     Assert.fail("Enable should throw exception through latch.");
132   }
133 
134   @Test(timeout = 60000)
135   public void testRecoveryAndDoubleExecution() throws Exception {
136     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
137     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
138 
139     final byte[][] splitKeys = new byte[][] {
140       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
141     };
142     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
143     UTIL.getHBaseAdmin().disableTable(tableName);
144     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
145     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
146 
147     // Start the Enable procedure && kill the executor
148     long procId = procExec.submitProcedure(
149         new EnableTableProcedure(procExec.getEnvironment(), tableName, false));
150 
151     // Restart the executor and execute the step twice
152     int numberOfSteps = EnableTableState.values().length;
153     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
154       procExec,
155       procId,
156       numberOfSteps,
157       EnableTableState.values());
158     MasterProcedureTestingUtility.validateTableIsEnabled(UTIL.getHBaseCluster().getMaster(),
159       tableName);
160   }
161 
162   @Test(timeout = 60000)
163   public void testRollbackAndDoubleExecution() throws Exception {
164     final TableName tableName = TableName.valueOf("testRollbackAndDoubleExecution");
165     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
166 
167     final byte[][] splitKeys = new byte[][] {
168       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
169     };
170     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
171     UTIL.getHBaseAdmin().disableTable(tableName);
172     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
173     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
174 
175     // Start the Enable procedure && kill the executor
176     long procId = procExec.submitProcedure(
177         new EnableTableProcedure(procExec.getEnvironment(), tableName, false));
178 
179     int numberOfSteps = EnableTableState.values().length - 2; // failing in the middle of proc
180     MasterProcedureTestingUtility.testRollbackAndDoubleExecution(
181       procExec,
182       procId,
183       numberOfSteps,
184       EnableTableState.values());
185     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
186       tableName);
187   }
188 
189   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
190     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
191   }
192 }