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