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.HConstants;
28 import org.apache.hadoop.hbase.HRegionInfo;
29 import org.apache.hadoop.hbase.HTableDescriptor;
30 import org.apache.hadoop.hbase.TableExistsException;
31 import org.apache.hadoop.hbase.TableName;
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.CreateTableState;
35 import org.apache.hadoop.hbase.testclassification.MediumTests;
36 import org.apache.hadoop.hbase.util.Bytes;
37 import org.apache.hadoop.hbase.util.ModifyRegionUtils;
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.assertTrue;
46
47 @Category(MediumTests.class)
48 public class TestCreateTableProcedure {
49 private static final Log LOG = LogFactory.getLog(TestCreateTableProcedure.class);
50
51 protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
52
53 private static long nonceGroup = HConstants.NO_NONCE;
54 private static long nonce = HConstants.NO_NONCE;
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 nonceGroup =
79 MasterProcedureTestingUtility.generateNonceGroup(UTIL.getHBaseCluster().getMaster());
80 nonce = MasterProcedureTestingUtility.generateNonce(UTIL.getHBaseCluster().getMaster());
81 }
82
83 @After
84 public void tearDown() throws Exception {
85 resetProcExecutorTestingKillFlag();
86 for (HTableDescriptor htd: UTIL.getHBaseAdmin().listTables()) {
87 LOG.info("Tear down, remove table=" + htd.getTableName());
88 UTIL.deleteTable(htd.getTableName());
89 }
90 }
91
92 private void resetProcExecutorTestingKillFlag() {
93 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
94 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, false);
95 assertTrue("expected executor to be running", procExec.isRunning());
96 }
97
98 @Test(timeout=60000)
99 public void testSimpleCreate() throws Exception {
100 final TableName tableName = TableName.valueOf("testSimpleCreate");
101 final byte[][] splitKeys = null;
102 testSimpleCreate(tableName, splitKeys);
103 }
104
105 @Test(timeout=60000)
106 public void testSimpleCreateWithSplits() throws Exception {
107 final TableName tableName = TableName.valueOf("testSimpleCreateWithSplits");
108 final byte[][] splitKeys = new byte[][] {
109 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
110 };
111 testSimpleCreate(tableName, splitKeys);
112 }
113
114 private void testSimpleCreate(final TableName tableName, byte[][] splitKeys) throws Exception {
115 HRegionInfo[] regions = MasterProcedureTestingUtility.createTable(
116 getMasterProcedureExecutor(), tableName, splitKeys, "f1", "f2");
117 MasterProcedureTestingUtility.validateTableCreation(
118 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
119 }
120
121 @Test(timeout=60000, expected=TableExistsException.class)
122 public void testCreateExisting() throws Exception {
123 final TableName tableName = TableName.valueOf("testCreateExisting");
124 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
125 final HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f");
126 final HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, null);
127
128
129 long procId1 = procExec.submitProcedure(
130 new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
131
132
133 ProcedurePrepareLatch latch2 = new ProcedurePrepareLatch.CompatibilityLatch();
134 long procId2 = procExec.submitProcedure(
135 new CreateTableProcedure(procExec.getEnvironment(), htd, regions, latch2),
136 nonceGroup + 1,
137 nonce + 1);
138
139 ProcedureTestingUtility.waitProcedure(procExec, procId1);
140 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1));
141
142 ProcedureTestingUtility.waitProcedure(procExec, procId2);
143 latch2.await();
144 }
145
146 @Test(timeout=60000)
147 public void testCreateTwiceWithSameNonce() throws Exception {
148 final TableName tableName = TableName.valueOf("testCreateTwiceWithSameNonce");
149 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
150 final HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f");
151 final HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, null);
152
153
154 long procId1 = procExec.submitProcedure(
155 new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
156
157
158 long procId2 = procExec.submitProcedure(
159 new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
160
161 ProcedureTestingUtility.waitProcedure(procExec, procId1);
162 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId1));
163
164 ProcedureTestingUtility.waitProcedure(procExec, procId2);
165 ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId2));
166 assertTrue(procId1 == procId2);
167 }
168
169 @Test(timeout=60000)
170 public void testRecoveryAndDoubleExecution() throws Exception {
171 final TableName tableName = TableName.valueOf("testRecoveryAndDoubleExecution");
172
173
174 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
175 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
176
177
178 byte[][] splitKeys = null;
179 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
180 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
181 long procId = procExec.submitProcedure(
182 new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
183
184
185
186
187 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(
188 procExec, procId, 6, CreateTableState.values());
189
190 MasterProcedureTestingUtility.validateTableCreation(
191 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
192 }
193
194 @Test(timeout=90000)
195 public void testRollbackAndDoubleExecution() throws Exception {
196 final TableName tableName = TableName.valueOf("testRollbackAndDoubleExecution");
197
198
199 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
200 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
201
202
203 final byte[][] splitKeys = new byte[][] {
204 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
205 };
206 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
207 htd.setRegionReplication(3);
208 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
209 long procId = procExec.submitProcedure(
210 new CreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
211
212
213
214 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(
215 procExec, procId, 4, CreateTableState.values());
216
217 MasterProcedureTestingUtility.validateTableDeletion(
218 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
219
220
221 resetProcExecutorTestingKillFlag();
222 testSimpleCreate(tableName, splitKeys);
223 }
224
225 @Test(timeout=90000)
226 public void testRollbackRetriableFailure() throws Exception {
227 final TableName tableName = TableName.valueOf("testRollbackRetriableFailure");
228
229
230 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
231 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true);
232
233
234 final byte[][] splitKeys = new byte[][] {
235 Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")
236 };
237 HTableDescriptor htd = MasterProcedureTestingUtility.createHTD(tableName, "f1", "f2");
238 HRegionInfo[] regions = ModifyRegionUtils.createHRegionInfos(htd, splitKeys);
239 long procId = procExec.submitProcedure(
240 new FaultyCreateTableProcedure(procExec.getEnvironment(), htd, regions), nonceGroup, nonce);
241
242
243
244 MasterProcedureTestingUtility.testRollbackRetriableFailure(
245 procExec, procId, 4, CreateTableState.values());
246
247 MasterProcedureTestingUtility.validateTableDeletion(
248 UTIL.getHBaseCluster().getMaster(), tableName, regions, "f1", "f2");
249
250
251 resetProcExecutorTestingKillFlag();
252 testSimpleCreate(tableName, splitKeys);
253 }
254
255 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
256 return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
257 }
258
259 public static class FaultyCreateTableProcedure extends CreateTableProcedure {
260 private int retries = 0;
261
262 public FaultyCreateTableProcedure() {
263
264 }
265
266 public FaultyCreateTableProcedure(final MasterProcedureEnv env,
267 final HTableDescriptor hTableDescriptor, final HRegionInfo[] newRegions)
268 throws IOException {
269 super(env, hTableDescriptor, newRegions);
270 }
271
272 @Override
273 protected void rollbackState(final MasterProcedureEnv env, final CreateTableState state)
274 throws IOException {
275 if (retries++ < 3) {
276 LOG.info("inject rollback failure state=" + state);
277 throw new IOException("injected failure number " + retries);
278 } else {
279 super.rollbackState(env, state);
280 retries = 0;
281 }
282 }
283 }
284 }