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 java.util.Random;
22  import java.util.List;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.hbase.HBaseTestingUtility;
28  import org.apache.hadoop.hbase.HConstants;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.ProcedureInfo;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
34  import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
35  import org.apache.hadoop.hbase.protobuf.generated.ProcedureProtos.ProcedureState;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.junit.After;
38  import org.junit.AfterClass;
39  import org.junit.Before;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  import org.junit.experimental.categories.Category;
43  
44  import static org.junit.Assert.*;
45  
46  @Category(MediumTests.class)
47  public class TestProcedureAdmin {
48    private static final Log LOG = LogFactory.getLog(TestProcedureAdmin.class);
49  
50    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
51  
52    private long nonceGroup = HConstants.NO_NONCE;
53    private long nonce = HConstants.NO_NONCE;
54  
55    private static void setupConf(Configuration conf) {
56      conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
57    }
58  
59    @BeforeClass
60    public static void setupCluster() throws Exception {
61      setupConf(UTIL.getConfiguration());
62      UTIL.startMiniCluster(1);
63    }
64  
65    @AfterClass
66    public static void cleanupTest() throws Exception {
67      try {
68        UTIL.shutdownMiniCluster();
69      } catch (Exception e) {
70        LOG.warn("failure shutting down cluster", e);
71      }
72    }
73  
74    @Before
75    public void setup() throws Exception {
76      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
77      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
78      assertTrue("expected executor to be running", procExec.isRunning());
79  
80      nonceGroup =
81          MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
82      nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
83    }
84  
85    @After
86    public void tearDown() throws Exception {
87      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false);
88      for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
89        LOG.info("Tear down, remove table=" + htd.getTableName());
90        UTIL.deleteTable(htd.getTableName());
91      }
92    }
93  
94    @Test(timeout=60000)
95    public void testAbortProcedureSuccess() throws Exception {
96      final TableName tableName = TableName.valueOf("testAbortProcedureSuccess");
97      final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
98  
99      MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
100     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
101     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
102     // Submit an abortable procedure
103     long procId = procExec.submitProcedure(
104         new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
105 
106     boolean abortResult = procExec.abort(procId, true);
107     assertTrue(abortResult);
108 
109     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
110     ProcedureTestingUtility.restart(procExec);
111     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
112     // Validate the disable table procedure was aborted successfully
113     MasterProcedureTestingUtility.validateTableIsEnabled(
114       UTIL.getHBaseCluster().getMaster(),
115       tableName);
116   }
117 
118   @Test(timeout=60000)
119   public void testAbortProcedureFailure() throws Exception {
120     final TableName tableName = TableName.valueOf("testAbortProcedureFailure");
121     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
122 
123     HRegionInfo[] regions =
124         MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
125     UTIL.getHBaseAdmin().disableTable(tableName);
126     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
127     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
128     // Submit an un-abortable procedure
129     long procId = procExec.submitProcedure(
130         new DeleteTableProcedure(procExec.getEnvironment(), tableName), nonceGroup, nonce);
131 
132     boolean abortResult = procExec.abort(procId, true);
133     assertFalse(abortResult);
134 
135     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
136     ProcedureTestingUtility.restart(procExec);
137     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
138     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
139     // Validate the delete table procedure was not aborted
140     MasterProcedureTestingUtility.validateTableDeletion(
141       UTIL.getHBaseCluster().getMaster(), tableName, regions, "f");
142   }
143 
144   @Test(timeout=60000)
145   public void testAbortProcedureInterruptedNotAllowed() throws Exception {
146     final TableName tableName = TableName.valueOf("testAbortProcedureInterruptedNotAllowed");
147     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
148 
149     HRegionInfo[] regions =
150         MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
151     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
152     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
153     // Submit a procedure
154     long procId = procExec.submitProcedure(
155         new DisableTableProcedure(procExec.getEnvironment(), tableName, true), nonceGroup, nonce);
156     // Wait for one step to complete
157     ProcedureTestingUtility.waitProcedure(procExec, procId);
158 
159     // Set the mayInterruptIfRunning flag to false
160     boolean abortResult = procExec.abort(procId, false);
161     assertFalse(abortResult);
162 
163     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
164     ProcedureTestingUtility.restart(procExec);
165     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
166     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
167     // Validate the delete table procedure was not aborted
168     MasterProcedureTestingUtility.validateTableIsDisabled(
169       UTIL.getHBaseCluster().getMaster(), tableName);
170   }
171 
172   @Test(timeout=60000)
173   public void testAbortNonExistProcedure() throws Exception {
174     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
175     Random randomGenerator = new Random();
176     long procId;
177     // Generate a non-existing procedure
178     do {
179       procId = randomGenerator.nextLong();
180     } while (procExec.getResult(procId) != null);
181 
182     boolean abortResult = procExec.abort(procId, true);
183     assertFalse(abortResult);
184   }
185 
186   @Test(timeout=60000)
187   public void testListProcedure() throws Exception {
188     final TableName tableName = TableName.valueOf("testListProcedure");
189     final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
190 
191     MasterProcedureTestingUtility.createTable(procExec, tableName, null, "f");
192     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
193     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
194 
195     long procId = procExec.submitProcedure(
196       new DisableTableProcedure(procExec.getEnvironment(), tableName, false), nonceGroup, nonce);
197 
198     List<ProcedureInfo> listProcedures = procExec.listProcedures();
199     assertTrue(listProcedures.size() >= 1);
200     boolean found = false;
201     for (ProcedureInfo procInfo: listProcedures) {
202       if (procInfo.getProcId() == procId) {
203         assertTrue(procInfo.getProcState() == ProcedureState.RUNNABLE);
204         found = true;
205       } else {
206         assertTrue(procInfo.getProcState() == ProcedureState.FINISHED);
207       }
208     }
209     assertTrue(found);
210 
211     ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
212     ProcedureTestingUtility.restart(procExec);
213     ProcedureTestingUtility.waitNoProcedureRunning(procExec);
214     ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
215     listProcedures = procExec.listProcedures();
216     for (ProcedureInfo procInfo: listProcedures) {
217       assertTrue(procInfo.getProcState() == ProcedureState.FINISHED);
218     }
219   }
220 
221   private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
222     return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
223   }
224 }