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.TableNotEnabledException;
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.DisableTableState;
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 TestDisableTableProcedure {
47    private static final Log LOG = LogFactory.getLog(TestDisableTableProcedure.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 testDisableTable() throws Exception {
92      final TableName tableName = TableName.valueOf("testDisableTable");
93      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
94  
95      MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
96  
97      // Disable the table
98      long procId = procExec.submitProcedure(
99        new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
100     // Wait the completion
101     ProcedureTestingUtility.waitProcedure(procExec, procId);
102     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
103     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
104       tableName);
105   }
106 
107   @Test(timeout = 60000)
108   public void testDisableTableMultipleTimes() throws Exception {
109     final TableName tableName = TableName.valueOf("testDisableTableMultipleTimes");
110     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
111 
112     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
113 
114     // Disable the table
115     long procId1 = procExec.submitProcedure(new DisableTableProcedure(
116         procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
117     // Wait the completion
118     ProcedureTestingUtility.waitProcedure(procExec, procId1);
119     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
120     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
121       tableName);
122 
123     // Disable the table again - expect failure
124     long procId2 = procExec.submitProcedure(new DisableTableProcedure(
125         procExec.getEnvironment(), tableName, false), nonceGroup + 1, nonce + 1);
126     // Wait the completion
127     ProcedureTestingUtility.waitProcedure(procExec, procId2);
128     ProcedureInfo result = procExec.getResult(procId2);
129     assertTrue(result.isFailed());
130     LOG.debug("Disable failed with exception: " + result.getExceptionFullMessage());
131     assertTrue(
132       ProcedureTestingUtility.getExceptionCause(result) instanceof TableNotEnabledException);
133 
134     // Disable the table - expect failure from ProcedurePrepareLatch
135     try {
136       final ProcedurePrepareLatch prepareLatch = new ProcedurePrepareLatch.CompatibilityLatch();
137 
138       long procId3 = procExec.submitProcedure(new DisableTableProcedure(
139           procExec.getEnvironment(), tableName, false, prepareLatch), nonceGroup + 2, nonce + 2);
140       prepareLatch.await();
141       Assert.fail("Disable should throw exception through latch.");
142     } catch (TableNotEnabledException tnee) {
143       // Expected
144       LOG.debug("Disable failed with expected exception.");
145     }
146 
147     // Disable the table again with skipping table state check flag (simulate recovery scenario)
148     long procId4 = procExec.submitProcedure(new DisableTableProcedure(
149         procExec.getEnvironment(), tableName, true));
150     // Wait the completion
151     ProcedureTestingUtility.waitProcedure(procExec, procId4);
152     ProcedureTestingUtility.assertProcNotFailed(procExec, procId4);
153     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
154       tableName);
155   }
156 
157   @Test(timeout = 60000)
158   public void testDisableTableTwiceWithSameNonce() throws Exception {
159     final TableName tableName = TableName.valueOf("testDisableTableTwiceWithSameNonce");
160     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
161 
162     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f1", "f2");
163 
164     // Disable the table
165     long procId1 = procExec.submitProcedure(new DisableTableProcedure(
166         procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
167     long procId2 = procExec.submitProcedure(new DisableTableProcedure(
168       procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
169     // Wait the completion
170     ProcedureTestingUtility.waitProcedure(procExec, procId1);
171     ProcedureTestingUtility.assertProcNotFailed(procExec, procId1);
172     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
173       tableName);
174 
175     ProcedureTestingUtility.waitProcedure(procExec, procId2);
176     ProcedureTestingUtility.assertProcNotFailed(procExec, procId2);
177     assertTrue(procId1 == procId2);
178   }
179 
180   @Test(timeout=60000)
181   public void testRecoveryAndDoubleExecution() throws Exception {
182     final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
183     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
184 
185     final byte[][] splitKeys = new byte[][] {
186       Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
187     };
188     MasterProcedureTestingUtility.createTable(procExec, tableName, splitKeys, "f1", "f2");
189 
190     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
191 
192     // Start the Disable procedure && kill the executor
193     long procId = procExec.submitProcedure(
194       new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
195 
196     // Restart the executor and execute the step twice
197     int numberOfSteps = DisableTableState.values().length;
198     MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
199       procExec,
200       procId,
201       numberOfSteps,
202       DisableTableState.values());
203     MasterProcedureTestingUtility.validateTableIsDisabled(UTIL.getHBaseCluster().getMaster(),
204       tableName);
205   }
206 
207   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
208     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
209   }
210 }