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