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.HConstants;
28  import org.apache.hadoop.hbase.HTableDescriptor;
29  import org.apache.hadoop.hbase.ProcedureInfo;
30  import org.apache.hadoop.hbase.TableName;
31  import org.apache.hadoop.hbase.TableNotDisabledException;
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.EnableTableState;
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.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 TestEnableTableProcedure {
47    private static final Log LOG = LogFactory.getLog(TestEnableTableProcedure.class);
48  
49    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
50  
51    private static long nonceGroup = HConstants.NO_NONCE;
52    private static long nonce = HConstants.NO_NONCE;
53  
54    private static void setupConf(Configuration conf) {
55      conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
56    }
57  
58    @BeforeClass
59    public static void setupCluster() throws Exception {
60      setupConf(UTIL.getConfiguration());
61      UTIL.startMiniCluster(1);
62    }
63  
64    @AfterClass
65    public static void cleanupTest() throws Exception {
66      try {
67        UTIL.shutdownMiniCluster();
68      } catch (Exception e) {
69        LOG.warn("failure shutting down cluster", e);
70      }
71    }
72  
73    @Before
74    public void setup() throws Exception {
75      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
76      nonceGroup =
77          MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
78      nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
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)
91    public void testEnableTable() throws Exception {
92      final TableName tableName = TableName.valueOf("testEnableTable");
93      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
94  
95      MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
96      UTIL.getHBaseAdmin().disableTable(tableName);
97  
98      // Enable the table
99      long procId = procExec.submitProcedure(
100       new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
101     // Wait the completion
102     ProcedureTestingUtility.waitProcedure(procExec, procId);
103     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
104     MasterProcedureTestingUtility.validateTableIsEnabled(UTIL.getHBaseCluster().getMaster(),
105       tableName);
106   }
107 
108   @Test(timeout = 60000)
109   public void testEnableTableTwiceWithSameNonce() throws Exception {
110     final TableName tableName = TableName.valueOf("testEnableTableTwiceWithSameNonce");
111     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
112 
113     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
114     UTIL.getHBaseAdmin().disableTable(tableName);
115 
116     // Enable the table
117     long procId1 = procExec.submitProcedure(
118       new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
119     long procId2 = procExec.submitProcedure(
120       new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
121 
122     // Wait the completion
123     ProcedureTestingUtility.waitProcedure(procExec, procId1);
124     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
125     // The second proc should succeed too - because it is the same proc.
126     ProcedureTestingUtility.waitProcedure(procExec, procId2);
127     ProcedureTestingUtility.assertProcNotFailed(procExec, procId2);
128     assertTrue(procId1 == procId2);
129   }
130 
131   @Test(timeout=60000, expected=TableNotDisabledException.class)
132   public void testEnableNonDisabledTable() throws Exception {
133     final TableName tableName = TableName.valueOf("testEnableNonExistingTable");
134     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
135 
136     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
137 
138     // Enable the table - expect failure
139     long procId1 = procExec.submitProcedure(
140         new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
141     ProcedureTestingUtility.waitProcedure(procExec, procId1);
142 
143     ProcedureInfo result = procExec.getResult(procId1);
144     assertTrue(result.isFailed());
145     LOG.debug("Enable failed with exception: " + result.getExceptionFullMessage());
146     assertTrue(
147       ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotDisabledException);
148 
149     // Enable the table with skipping table state check flag (simulate recovery scenario)
150     long procId2 = procExec.submitProcedure(
151         new EnableTableProcedure(procExec.getEnvironment(), tableName, true),
152         nonceGroup + 1,
153         nonce + 1);
154     // Wait the completion
155     ProcedureTestingUtility.waitProcedure(procExec, procId2);
156     ProcedureTestingUtility.assertProcNotFailed(procExec, procId2);
157 
158     // Enable the table - expect failure from ProcedurePrepareLatch
159     final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch();
160     long procId3 = procExec.submitProcedure(
161         new EnableTableProcedure(procExec.getEnvironment(), tableName, false, prepareLatch),
162         nonceGroup + 2,
163         nonce + 2);
164     prepareLatch.await();
165     Assert.fail("Enable should throw exception through latch.");
166   }
167 
168   @Test(timeout = 60000)
169   public void testRecoveryAndDoubleExecution() throws Exception {
170     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
171     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
172 
173     final byte[][] splitKeys = new byte[][] {
174       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
175     };
176     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
177     UTIL.getHBaseAdmin().disableTable(tableName);
178     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
179     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
180 
181     // Start the Enable procedure && kill the executor
182     long procId = procExec.submitProcedure(
183         new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
184 
185     // Restart the executor and execute the step twice
186     int numberOfSteps = EnableTableState.values().length;
187     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
188       procExec,
189       procId,
190       numberOfSteps,
191       EnableTableState.values());
192     MasterProcedureTestingUtility.validateTableIsEnabled(UTIL.getHBaseCluster().getMaster(),
193       tableName);
194   }
195 
196   @Test(timeout = 60000)
197   public void testRollbackAndDoubleExecution() throws Exception {
198     final TableName tableName = TableName.valueOf("testRollbackAndDoubleExecution");
199     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
200 
201     final byte[][] splitKeys = new byte[][] {
202       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
203     };
204     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
205     UTIL.getHBaseAdmin().disableTable(tableName);
206     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
207     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
208 
209     // Start the Enable procedure && kill the executor
210     long procId = procExec.submitProcedure(
211         new EnableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
212 
213     int numberOfSteps = EnableTableState.values().length - 2; // failing in the middle of proc
214     MasterProcedureTestingUtility.testRollbackAndDoubleExecution(
215       procExec,
216       procId,
217       numberOfSteps,
218       EnableTableState.values());
219     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
220       tableName);
221   }
222 
223   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
224     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
225   }
226 }