1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.procedure;
20
21 import java.io.IOException;
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.HRegionInfo;
28 import org.apache.hadoop.hbase.HTableDescriptor;
29 import org.apache.hadoop.hbase.TableExistsException;
30 import org.apache.hadoop.hbase.TableName;
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.CreateTableState;
34 import org.apache.hadoop.hbase.testclassification.MediumTests;
35 import org.apache.hadoop.hbase.util.Bytes;
36 import org.apache.hadoop.hbase.util.ModifyRegionUtils;
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.assertTrue;
45
46 @Category(MediumTests.class)
47 public class TestCreateTableProcedure {
48 private static final Log LOG = LogFactory.getLog(TestCreateTableProcedure.class);
49
50 protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
51
52 private static void setupConf(Configuration conf) {
53 conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
54 }
55
56 @BeforeClass
57 public static void setupCluster() throws Exception {
58 setupConf(UTIL.getConfiguration());
59 UTIL.startMiniCluster(1);
60 }
61
62 @AfterClass
63 public static void cleanupTest() throws Exception {
64 try {
65 UTIL.shutdownMiniCluster();
66 } catch (Exception e) {
67 LOG.warn("failure shutting down cluster", e);
68 }
69 }
70
71 @Before
72 public void setup() throws Exception {
73 resetProcExecutorTestingKillFlag();
74 }
75
76 @After
77 public void tearDown() throws Exception {
78 resetProcExecutorTestingKillFlag();
79 for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
80 LOG.info("Tear down, remove table=" + htd.getTableName());
81 UTIL.deleteTable(htd.getTableName());
82 }
83 }
84
85 private void resetProcExecutorTestingKillFlag() {
86 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
87 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
88 assertTrue("expected executor to be running", procExec.isRunning());
89 }
90
91 @Test(timeout=60000)
92 public void testSimpleCreate() throws Exception {
93 final TableName tableName = TableName.valueOf("testSimpleCreate");
94 final byte[][] splitKeys = null;
95 testSimpleCreate(tableName, splitKeys);
96 }
97
98 @Test(timeout=60000)
99 public void testSimpleCreateWithSplits() throws Exception {
100 final TableName tableName = TableName.valueOf("testSimpleCreateWithSplits");
101 final byte[][] splitKeys = new byte[][] {
102 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
103 };
104 testSimpleCreate(tableName, splitKeys);
105 }
106
107 private void testSimpleCreate(final TableName tableName, byte[][] splitKeys) throws Exception {
108 HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
109 getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
110 MasterProcedureTestingUtility.validateTableCreation(
111 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
112 }
113
114 @Test(timeout=60000, expected=TableExistsException.class)
115 public void testCreateExisting() throws Exception {
116 final TableName tableName = TableName.valueOf("testCreateExisting");
117 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
118 final HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f");
119 final HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, null);
120
121
122 long procId1 = procExec.submitProcedure(
123 new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
124
125
126 ProcedurePrepareLatch latch2 = new ProcedurePrepareLatch.CompatibilityLatch();
127 long procId2 = procExec.submitProcedure(
128 new CreateTableProcedure(procExec.getEnvironment(), htd, regions, latch2));
129
130 ProcedureTestingUtility.waitProcedure(procExec, procId1);
131 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1));
132
133 ProcedureTestingUtility.waitProcedure(procExec, procId2);
134 latch2.await();
135 }
136
137 @Test(timeout=60000)
138 public void testRecoveryAndDoubleExecution() throws Exception {
139 final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
140
141
142 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
143 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
144
145
146 byte[][] splitKeys = null;
147 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
148 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
149 long procId = procExec.submitProcedure(
150 new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
151
152
153
154
155 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
156 procExec, procId, 6, CreateTableState.values());
157
158 MasterProcedureTestingUtility.validateTableCreation(
159 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
160 }
161
162 @Test(timeout=90000)
163 public void testRollbackAndDoubleExecution() throws Exception {
164 final TableName tableName = TableName.valueOf("testRollbackAndDoubleExecution");
165 testRollbackAndDoubleExecution(MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2"));
166 }
167
168 @Test(timeout=90000)
169 public void testRollbackAndDoubleExecutionOnMobTable() throws Exception {
170 final TableName tableName = TableName.valueOf("testRollbackAndDoubleExecutionOnMobTable");
171 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
172 htd.getFamily(Bytes.toBytes("f1")).setMobEnabled(true);
173 testRollbackAndDoubleExecution(htd);
174 }
175
176 @Test(timeout=90000)
177 public void testRollbackRetriableFailure() throws Exception {
178 final TableName tableName = TableName.valueOf("testRollbackRetriableFailure");
179
180
181 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
182 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
183
184
185 final byte[][] splitKeys = new byte[][] {
186 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
187 };
188 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
189 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
190 long procId = procExec.submitProcedure(
191 new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
192
193
194
195 MasterProcedureTestingUtility.testRollbackRetriableFailure(
196 procExec, procId, 4, CreateTableState.values());
197
198 MasterProcedureTestingUtility.validateTableDeletion(
199 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
200
201
202 resetProcExecutorTestingKillFlag();
203 testSimpleCreate(tableName, splitKeys);
204 }
205
206 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
207 return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
208 }
209
210 public static class FaultyCreateTableProcedure extends CreateTableProcedure {
211 private int retries = 0;
212
213 public FaultyCreateTableProcedure() {
214
215 }
216
217 public FaultyCreateTableProcedure(final MasterProcedureEnv env,
218 final HTableDescriptor hTableDescriptor, final HRegionInfo[] newRegions)
219 throws IOException {
220 super(env, hTableDescriptor, newRegions);
221 }
222
223 @Override
224 protected void rollbackState(final MasterProcedureEnv env, final CreateTableState state)
225 throws IOException {
226 if (retries++ < 3) {
227 LOG.info("inject rollback failure state=" + state);
228 throw new IOException("injected failure number " + retries);
229 } else {
230 super.rollbackState(env, state);
231 retries = 0;
232 }
233 }
234 }
235
236 private void testRollbackAndDoubleExecution(HTableDescriptor htd) throws Exception {
237
238 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
239 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
240
241
242 final byte[][] splitKeys = new byte[][] {
243 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
244 };
245 htd.setRegionReplication(3);
246 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
247 long procId = procExec.submitProcedure(
248 new CreateTableProcedure(procExec.getEnvironment(), htd, regions));
249
250
251
252 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(
253 procExec, procId, 4, CreateTableState.values());
254 TableName tableName = htd.getTableName();
255 MasterProcedureTestingUtility.validateTableDeletion(
256 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
257
258
259 resetProcExecutorTestingKillFlag();
260 testSimpleCreate(tableName, splitKeys);
261 }
262 }