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.handler;
20
21 import java.io.IOException;
22 import java.io.InterruptedIOException;
23 import java.security.PrivilegedExceptionAction;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileSystem;
32 import org.apache.hadoop.fs.Path;
33 import org.apache.hadoop.hbase.CoordinatedStateException;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.HTableDescriptor;
37 import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException;
38 import org.apache.hadoop.hbase.Server;
39 import org.apache.hadoop.hbase.TableExistsException;
40 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
41 import org.apache.hadoop.hbase.MetaTableAccessor;
42 import org.apache.hadoop.hbase.executor.EventHandler;
43 import org.apache.hadoop.hbase.executor.EventType;
44 import org.apache.hadoop.hbase.ipc.RequestContext;
45 import org.apache.hadoop.hbase.master.AssignmentManager;
46 import org.apache.hadoop.hbase.master.HMaster;
47 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
48 import org.apache.hadoop.hbase.master.MasterFileSystem;
49 import org.apache.hadoop.hbase.master.MasterServices;
50 import org.apache.hadoop.hbase.master.TableLockManager;
51 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
52 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
53 import org.apache.hadoop.hbase.security.User;
54 import org.apache.hadoop.hbase.security.UserProvider;
55 import org.apache.hadoop.hbase.util.FSTableDescriptors;
56 import org.apache.hadoop.hbase.util.FSUtils;
57 import org.apache.hadoop.hbase.util.ModifyRegionUtils;
58
59
60
61
62 @InterfaceAudience.Private
63 public class CreateTableHandler extends EventHandler {
64 private static final Log LOG = LogFactory.getLog(CreateTableHandler.class);
65 protected final MasterFileSystem fileSystemManager;
66 protected final HTableDescriptor hTableDescriptor;
67 protected final Configuration conf;
68 private final AssignmentManager assignmentManager;
69 private final TableLockManager tableLockManager;
70 private final HRegionInfo [] newRegions;
71 private final TableLock tableLock;
72 private User activeUser;
73
74 public CreateTableHandler(Server server, MasterFileSystem fileSystemManager,
75 HTableDescriptor hTableDescriptor, Configuration conf, HRegionInfo [] newRegions,
76 MasterServices masterServices) {
77 super(server, EventType.C_M_CREATE_TABLE);
78
79 this.fileSystemManager = fileSystemManager;
80 this.hTableDescriptor = hTableDescriptor;
81 this.conf = conf;
82 this.newRegions = newRegions;
83 this.assignmentManager = masterServices.getAssignmentManager();
84 this.tableLockManager = masterServices.getTableLockManager();
85
86 this.tableLock = this.tableLockManager.writeLock(this.hTableDescriptor.getTableName()
87 , EventType.C_M_CREATE_TABLE.toString());
88 }
89
90 @Override
91 public CreateTableHandler prepare()
92 throws NotAllMetaRegionsOnlineException, TableExistsException, IOException {
93 int timeout = conf.getInt("hbase.client.catalog.timeout", 10000);
94
95 try {
96 if (server.getMetaTableLocator().waitMetaRegionLocation(
97 server.getZooKeeper(), timeout) == null) {
98 throw new NotAllMetaRegionsOnlineException();
99 }
100
101
102
103 if (RequestContext.isInRequestContext()) {
104 this.activeUser = RequestContext.getRequestUser();
105 } else {
106 this.activeUser = UserProvider.instantiate(conf).getCurrent();
107 }
108 } catch (InterruptedException e) {
109 LOG.warn("Interrupted waiting for meta availability", e);
110 InterruptedIOException ie = new InterruptedIOException(e.getMessage());
111 ie.initCause(e);
112 throw ie;
113 }
114
115
116 this.tableLock.acquire();
117 boolean success = false;
118 try {
119 TableName tableName = this.hTableDescriptor.getTableName();
120 if (MetaTableAccessor.tableExists(this.server.getConnection(), tableName)) {
121 throw new TableExistsException(tableName);
122 }
123
124 checkAndSetEnablingTable(assignmentManager, tableName);
125 success = true;
126 } finally {
127 if (!success) {
128 releaseTableLock();
129 }
130 }
131 return this;
132 }
133
134 static void checkAndSetEnablingTable(final AssignmentManager assignmentManager,
135 final TableName tableName) throws IOException {
136
137
138
139
140
141
142
143
144
145
146 try {
147 if (!assignmentManager.getTableStateManager().setTableStateIfNotInStates(tableName,
148 ZooKeeperProtos.Table.State.ENABLING,
149 ZooKeeperProtos.Table.State.ENABLING,
150 ZooKeeperProtos.Table.State.ENABLED)) {
151 throw new TableExistsException(tableName);
152 }
153 } catch (CoordinatedStateException e) {
154 throw new IOException("Unable to ensure that the table will be" +
155 " enabling because of a ZooKeeper issue", e);
156 }
157 }
158
159 static void removeEnablingTable(final AssignmentManager assignmentManager,
160 final TableName tableName) {
161
162
163
164
165 try {
166 assignmentManager.getTableStateManager().checkAndRemoveTableState(tableName,
167 ZooKeeperProtos.Table.State.ENABLING, false);
168 } catch (CoordinatedStateException e) {
169
170 LOG.error("Got a keeper exception while removing the ENABLING table znode "
171 + tableName, e);
172 }
173 }
174
175 @Override
176 public String toString() {
177 String name = "UnknownServerName";
178 if(server != null && server.getServerName() != null) {
179 name = server.getServerName().toString();
180 }
181 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
182 this.hTableDescriptor.getTableName();
183 }
184
185 @Override
186 public void process() {
187 TableName tableName = this.hTableDescriptor.getTableName();
188 LOG.info("Create table " + tableName);
189
190 try {
191 final MasterCoprocessorHost cpHost = ((HMaster) this.server).getMasterCoprocessorHost();
192 if (cpHost != null) {
193 cpHost.preCreateTableHandler(this.hTableDescriptor, this.newRegions);
194 }
195 handleCreateTable(tableName);
196 completed(null);
197 if (cpHost != null) {
198 this.activeUser.runAs(new PrivilegedExceptionAction<Void>() {
199 @Override
200 public Void run() throws Exception {
201 cpHost.postCreateTableHandler(hTableDescriptor, newRegions);
202 return null;
203 }
204 });
205 }
206 } catch (Throwable e) {
207 LOG.error("Error trying to create the table " + tableName, e);
208 completed(e);
209 }
210 }
211
212
213
214
215
216 protected void completed(final Throwable exception) {
217 releaseTableLock();
218 String msg = exception == null ? null : exception.getMessage();
219 LOG.info("Table, " + this.hTableDescriptor.getTableName() + ", creation " +
220 msg == null ? "successful" : "failed. " + msg);
221 if (exception != null) {
222 removeEnablingTable(this.assignmentManager, this.hTableDescriptor.getTableName());
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 private void handleCreateTable(TableName tableName)
241 throws IOException, CoordinatedStateException {
242 Path tempdir = fileSystemManager.getTempDir();
243 FileSystem fs = fileSystemManager.getFileSystem();
244
245
246 Path tempTableDir = FSUtils.getTableDir(tempdir, tableName);
247 new FSTableDescriptors(this.conf).createTableDescriptorForTableDirectory(
248 tempTableDir, this.hTableDescriptor, false);
249 Path tableDir = FSUtils.getTableDir(fileSystemManager.getRootDir(), tableName);
250
251
252 List<HRegionInfo> regionInfos = handleCreateHdfsRegions(tempdir, tableName);
253
254 if (!fs.rename(tempTableDir, tableDir)) {
255 throw new IOException("Unable to move table from temp=" + tempTableDir +
256 " to hbase root=" + tableDir);
257 }
258
259 if (regionInfos != null && regionInfos.size() > 0) {
260
261 addRegionsToMeta(regionInfos);
262
263 regionInfos = addReplicas(hTableDescriptor, regionInfos);
264
265
266 ModifyRegionUtils.assignRegions(assignmentManager, regionInfos);
267 }
268
269
270 try {
271 assignmentManager.getTableStateManager().setTableState(tableName,
272 ZooKeeperProtos.Table.State.ENABLED);
273 } catch (CoordinatedStateException e) {
274 throw new IOException("Unable to ensure that " + tableName + " will be" +
275 " enabled because of a ZooKeeper issue", e);
276 }
277
278
279 ((HMaster) this.server).getTableDescriptors().get(tableName);
280 }
281
282
283
284
285
286
287
288
289 protected List<HRegionInfo> addReplicas(HTableDescriptor hTableDescriptor,
290 List<HRegionInfo> regions) {
291 int numRegionReplicas = hTableDescriptor.getRegionReplication() - 1;
292 if (numRegionReplicas <= 0) {
293 return regions;
294 }
295 List<HRegionInfo> hRegionInfos =
296 new ArrayList<HRegionInfo>((numRegionReplicas+1)*regions.size());
297 for (int i = 0; i < regions.size(); i++) {
298 for (int j = 1; j <= numRegionReplicas; j++) {
299 hRegionInfos.add(RegionReplicaUtil.getRegionInfoForReplica(regions.get(i), j));
300 }
301 }
302 hRegionInfos.addAll(regions);
303 return hRegionInfos;
304 }
305
306 private void releaseTableLock() {
307 if (this.tableLock != null) {
308 try {
309 this.tableLock.release();
310 } catch (IOException ex) {
311 LOG.warn("Could not release the table lock", ex);
312 }
313 }
314 }
315
316
317
318
319
320
321
322 protected List<HRegionInfo> handleCreateHdfsRegions(final Path tableRootDir,
323 final TableName tableName)
324 throws IOException {
325 return ModifyRegionUtils.createRegions(conf, tableRootDir,
326 hTableDescriptor, newRegions, null);
327 }
328
329
330
331
332 protected void addRegionsToMeta(final List<HRegionInfo> regionInfos)
333 throws IOException {
334 MetaTableAccessor.addRegionsToMeta(this.server.getConnection(), regionInfos);
335 }
336 }