001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.master.procedure; 020 021import java.io.IOException; 022 023import org.apache.hadoop.hbase.NamespaceDescriptor; 024import org.apache.hadoop.hbase.NamespaceExistException; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028import org.apache.hadoop.hbase.master.MasterFileSystem; 029import org.apache.hadoop.hbase.master.TableNamespaceManager; 030import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 031import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 032import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos; 033import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CreateNamespaceState; 034import org.apache.hadoop.hbase.util.FSUtils; 035 036/** 037 * The procedure to create a new namespace. 038 */ 039@InterfaceAudience.Private 040public class CreateNamespaceProcedure 041 extends AbstractStateMachineNamespaceProcedure<CreateNamespaceState> { 042 private static final Logger LOG = LoggerFactory.getLogger(CreateNamespaceProcedure.class); 043 044 private NamespaceDescriptor nsDescriptor; 045 private Boolean traceEnabled; 046 047 public CreateNamespaceProcedure() { 048 this.traceEnabled = null; 049 } 050 051 public CreateNamespaceProcedure(final MasterProcedureEnv env, 052 final NamespaceDescriptor nsDescriptor) { 053 this(env, nsDescriptor, null); 054 } 055 056 public CreateNamespaceProcedure(final MasterProcedureEnv env, 057 final NamespaceDescriptor nsDescriptor, ProcedurePrepareLatch latch) { 058 super(env, latch); 059 this.nsDescriptor = nsDescriptor; 060 this.traceEnabled = null; 061 } 062 063 @Override 064 protected Flow executeFromState(final MasterProcedureEnv env, final CreateNamespaceState state) 065 throws InterruptedException { 066 if (isTraceEnabled()) { 067 LOG.trace(this + " execute state=" + state); 068 } 069 try { 070 switch (state) { 071 case CREATE_NAMESPACE_PREPARE: 072 boolean success = prepareCreate(env); 073 releaseSyncLatch(); 074 if (!success) { 075 assert isFailed() : "createNamespace should have an exception here"; 076 return Flow.NO_MORE_STATE; 077 } 078 setNextState(CreateNamespaceState.CREATE_NAMESPACE_CREATE_DIRECTORY); 079 break; 080 case CREATE_NAMESPACE_CREATE_DIRECTORY: 081 createDirectory(env, nsDescriptor); 082 setNextState(CreateNamespaceState.CREATE_NAMESPACE_INSERT_INTO_NS_TABLE); 083 break; 084 case CREATE_NAMESPACE_INSERT_INTO_NS_TABLE: 085 insertIntoNSTable(env, nsDescriptor); 086 setNextState(CreateNamespaceState.CREATE_NAMESPACE_UPDATE_ZK); 087 break; 088 case CREATE_NAMESPACE_UPDATE_ZK: 089 updateZKNamespaceManager(env, nsDescriptor); 090 setNextState(CreateNamespaceState.CREATE_NAMESPACE_SET_NAMESPACE_QUOTA); 091 break; 092 case CREATE_NAMESPACE_SET_NAMESPACE_QUOTA: 093 setNamespaceQuota(env, nsDescriptor); 094 return Flow.NO_MORE_STATE; 095 default: 096 throw new UnsupportedOperationException(this + " unhandled state=" + state); 097 } 098 } catch (IOException e) { 099 if (isRollbackSupported(state)) { 100 setFailure("master-create-namespace", e); 101 } else { 102 LOG.warn("Retriable error trying to create namespace=" + nsDescriptor.getName() + 103 " (in state=" + state + ")", e); 104 } 105 } 106 return Flow.HAS_MORE_STATE; 107 } 108 109 @Override 110 protected void rollbackState(final MasterProcedureEnv env, final CreateNamespaceState state) 111 throws IOException { 112 if (state == CreateNamespaceState.CREATE_NAMESPACE_PREPARE) { 113 // nothing to rollback, pre-create is just state checks. 114 // TODO: coprocessor rollback semantic is still undefined. 115 releaseSyncLatch(); 116 return; 117 } 118 // The procedure doesn't have a rollback. The execution will succeed, at some point. 119 throw new UnsupportedOperationException("unhandled state=" + state); 120 } 121 122 @Override 123 protected boolean isRollbackSupported(final CreateNamespaceState state) { 124 switch (state) { 125 case CREATE_NAMESPACE_PREPARE: 126 return true; 127 default: 128 return false; 129 } 130 } 131 132 @Override 133 protected CreateNamespaceState getState(final int stateId) { 134 return CreateNamespaceState.forNumber(stateId); 135 } 136 137 @Override 138 protected int getStateId(final CreateNamespaceState state) { 139 return state.getNumber(); 140 } 141 142 @Override 143 protected CreateNamespaceState getInitialState() { 144 return CreateNamespaceState.CREATE_NAMESPACE_PREPARE; 145 } 146 147 @Override 148 protected void serializeStateData(ProcedureStateSerializer serializer) 149 throws IOException { 150 super.serializeStateData(serializer); 151 152 MasterProcedureProtos.CreateNamespaceStateData.Builder createNamespaceMsg = 153 MasterProcedureProtos.CreateNamespaceStateData.newBuilder().setNamespaceDescriptor( 154 ProtobufUtil.toProtoNamespaceDescriptor(this.nsDescriptor)); 155 serializer.serialize(createNamespaceMsg.build()); 156 } 157 158 @Override 159 protected void deserializeStateData(ProcedureStateSerializer serializer) 160 throws IOException { 161 super.deserializeStateData(serializer); 162 163 MasterProcedureProtos.CreateNamespaceStateData createNamespaceMsg = 164 serializer.deserialize(MasterProcedureProtos.CreateNamespaceStateData.class); 165 nsDescriptor = ProtobufUtil.toNamespaceDescriptor(createNamespaceMsg.getNamespaceDescriptor()); 166 } 167 168 private boolean isBootstrapNamespace() { 169 return nsDescriptor.equals(NamespaceDescriptor.DEFAULT_NAMESPACE) || 170 nsDescriptor.equals(NamespaceDescriptor.SYSTEM_NAMESPACE); 171 } 172 173 @Override 174 protected boolean waitInitialized(MasterProcedureEnv env) { 175 // Namespace manager might not be ready if master is not fully initialized, 176 // return false to reject user namespace creation; return true for default 177 // and system namespace creation (this is part of master initialization). 178 if (isBootstrapNamespace()) { 179 return false; 180 } 181 return env.waitInitialized(this); 182 } 183 184 @Override 185 protected LockState acquireLock(final MasterProcedureEnv env) { 186 if (env.getProcedureScheduler().waitNamespaceExclusiveLock(this, getNamespaceName())) { 187 return LockState.LOCK_EVENT_WAIT; 188 } 189 return LockState.LOCK_ACQUIRED; 190 } 191 192 @Override 193 public TableOperationType getTableOperationType() { 194 return TableOperationType.EDIT; 195 } 196 197 @Override 198 protected String getNamespaceName() { 199 return nsDescriptor.getName(); 200 } 201 202 /** 203 * Action before any real action of creating namespace. 204 * @param env MasterProcedureEnv 205 * @throws IOException 206 */ 207 private boolean prepareCreate(final MasterProcedureEnv env) throws IOException { 208 if (getTableNamespaceManager(env).doesNamespaceExist(nsDescriptor.getName())) { 209 setFailure("master-create-namespace", 210 new NamespaceExistException("Namespace " + nsDescriptor.getName() + " already exists")); 211 return false; 212 } 213 getTableNamespaceManager(env).validateTableAndRegionCount(nsDescriptor); 214 return true; 215 } 216 217 /** 218 * Create the namespace directory 219 * @param env MasterProcedureEnv 220 * @param nsDescriptor NamespaceDescriptor 221 * @throws IOException 222 */ 223 protected static void createDirectory( 224 final MasterProcedureEnv env, 225 final NamespaceDescriptor nsDescriptor) throws IOException { 226 MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem(); 227 mfs.getFileSystem().mkdirs( 228 FSUtils.getNamespaceDir(mfs.getRootDir(), nsDescriptor.getName())); 229 } 230 231 /** 232 * Insert the row into ns table 233 * @param env MasterProcedureEnv 234 * @param nsDescriptor NamespaceDescriptor 235 * @throws IOException 236 */ 237 protected static void insertIntoNSTable( 238 final MasterProcedureEnv env, 239 final NamespaceDescriptor nsDescriptor) throws IOException { 240 getTableNamespaceManager(env).insertIntoNSTable(nsDescriptor); 241 } 242 243 /** 244 * Update ZooKeeper. 245 * @param env MasterProcedureEnv 246 * @param nsDescriptor NamespaceDescriptor 247 * @throws IOException 248 */ 249 protected static void updateZKNamespaceManager( 250 final MasterProcedureEnv env, 251 final NamespaceDescriptor nsDescriptor) throws IOException { 252 getTableNamespaceManager(env).updateZKNamespaceManager(nsDescriptor); 253 } 254 255 /** 256 * Set quota for the namespace 257 * @param env MasterProcedureEnv 258 * @param nsDescriptor NamespaceDescriptor 259 * @throws IOException 260 **/ 261 protected static void setNamespaceQuota( 262 final MasterProcedureEnv env, 263 final NamespaceDescriptor nsDescriptor) throws IOException { 264 if (env.getMasterServices().isInitialized()) { 265 env.getMasterServices().getMasterQuotaManager().setNamespaceQuota(nsDescriptor); 266 } 267 } 268 269 private static TableNamespaceManager getTableNamespaceManager(final MasterProcedureEnv env) { 270 return env.getMasterServices().getClusterSchema().getTableNamespaceManager(); 271 } 272 273 /** 274 * The procedure could be restarted from a different machine. If the variable is null, we need to 275 * retrieve it. 276 * @return traceEnabled 277 */ 278 private Boolean isTraceEnabled() { 279 if (traceEnabled == null) { 280 traceEnabled = LOG.isTraceEnabled(); 281 } 282 return traceEnabled; 283 } 284 285 @Override 286 protected boolean shouldWaitClientAck(MasterProcedureEnv env) { 287 // hbase and default namespaces are created on bootstrap internally by the system 288 // the client does not know about this procedures. 289 return !isBootstrapNamespace(); 290 } 291}