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