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 */ 018package org.apache.hadoop.hbase.master.procedure; 019 020import java.io.IOException; 021import org.apache.hadoop.hbase.NamespaceDescriptor; 022import org.apache.hadoop.hbase.NamespaceExistException; 023import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 024import org.apache.yetus.audience.InterfaceAudience; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 029import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos; 030import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CreateNamespaceState; 031 032/** 033 * The procedure to create a new namespace. 034 */ 035@InterfaceAudience.Private 036public class CreateNamespaceProcedure 037 extends AbstractStateMachineNamespaceProcedure<CreateNamespaceState> { 038 private static final Logger LOG = LoggerFactory.getLogger(CreateNamespaceProcedure.class); 039 040 private NamespaceDescriptor nsDescriptor; 041 042 public CreateNamespaceProcedure() { 043 } 044 045 public CreateNamespaceProcedure(final MasterProcedureEnv env, 046 final NamespaceDescriptor nsDescriptor) { 047 this(env, nsDescriptor, null); 048 } 049 050 public CreateNamespaceProcedure(final MasterProcedureEnv env, 051 final NamespaceDescriptor nsDescriptor, ProcedurePrepareLatch latch) { 052 super(env, latch); 053 this.nsDescriptor = nsDescriptor; 054 } 055 056 @Override 057 protected Flow executeFromState(final MasterProcedureEnv env, final CreateNamespaceState state) 058 throws InterruptedException { 059 LOG.trace("{} execute state={}", this, state); 060 try { 061 switch (state) { 062 case CREATE_NAMESPACE_PREPARE: 063 boolean success = prepareCreate(env); 064 releaseSyncLatch(); 065 if (!success) { 066 assert isFailed() : "createNamespace should have an exception here"; 067 return Flow.NO_MORE_STATE; 068 } 069 setNextState(CreateNamespaceState.CREATE_NAMESPACE_CREATE_DIRECTORY); 070 break; 071 case CREATE_NAMESPACE_CREATE_DIRECTORY: 072 createDirectory(env, nsDescriptor); 073 setNextState(CreateNamespaceState.CREATE_NAMESPACE_INSERT_INTO_NS_TABLE); 074 break; 075 case CREATE_NAMESPACE_INSERT_INTO_NS_TABLE: 076 addOrUpdateNamespace(env, nsDescriptor); 077 setNextState(CreateNamespaceState.CREATE_NAMESPACE_SET_NAMESPACE_QUOTA); 078 break; 079 case CREATE_NAMESPACE_UPDATE_ZK: 080 // not used any more 081 setNextState(CreateNamespaceState.CREATE_NAMESPACE_SET_NAMESPACE_QUOTA); 082 break; 083 case CREATE_NAMESPACE_SET_NAMESPACE_QUOTA: 084 setNamespaceQuota(env, nsDescriptor); 085 return Flow.NO_MORE_STATE; 086 default: 087 throw new UnsupportedOperationException(this + " unhandled state=" + state); 088 } 089 } catch (IOException e) { 090 if (isRollbackSupported(state)) { 091 setFailure("master-create-namespace", e); 092 } else { 093 LOG.warn("Retriable error trying to create namespace=" + nsDescriptor.getName() 094 + " (in state=" + state + ")", e); 095 } 096 } 097 return Flow.HAS_MORE_STATE; 098 } 099 100 @Override 101 protected void rollbackState(final MasterProcedureEnv env, final CreateNamespaceState state) 102 throws IOException { 103 if (state == CreateNamespaceState.CREATE_NAMESPACE_PREPARE) { 104 // nothing to rollback, pre-create is just state checks. 105 // TODO: coprocessor rollback semantic is still undefined. 106 releaseSyncLatch(); 107 return; 108 } 109 // The procedure doesn't have a rollback. The execution will succeed, at some point. 110 throw new UnsupportedOperationException("unhandled state=" + state); 111 } 112 113 @Override 114 protected boolean isRollbackSupported(final CreateNamespaceState state) { 115 switch (state) { 116 case CREATE_NAMESPACE_PREPARE: 117 return true; 118 default: 119 return false; 120 } 121 } 122 123 @Override 124 protected CreateNamespaceState getState(final int stateId) { 125 return CreateNamespaceState.forNumber(stateId); 126 } 127 128 @Override 129 protected int getStateId(final CreateNamespaceState state) { 130 return state.getNumber(); 131 } 132 133 @Override 134 protected CreateNamespaceState getInitialState() { 135 return CreateNamespaceState.CREATE_NAMESPACE_PREPARE; 136 } 137 138 @Override 139 protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException { 140 super.serializeStateData(serializer); 141 142 MasterProcedureProtos.CreateNamespaceStateData.Builder createNamespaceMsg = 143 MasterProcedureProtos.CreateNamespaceStateData.newBuilder() 144 .setNamespaceDescriptor(ProtobufUtil.toProtoNamespaceDescriptor(this.nsDescriptor)); 145 serializer.serialize(createNamespaceMsg.build()); 146 } 147 148 @Override 149 protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException { 150 super.deserializeStateData(serializer); 151 152 MasterProcedureProtos.CreateNamespaceStateData createNamespaceMsg = 153 serializer.deserialize(MasterProcedureProtos.CreateNamespaceStateData.class); 154 nsDescriptor = ProtobufUtil.toNamespaceDescriptor(createNamespaceMsg.getNamespaceDescriptor()); 155 } 156 157 @Override 158 protected boolean waitInitialized(MasterProcedureEnv env) { 159 return env.waitInitialized(this); 160 } 161 162 @Override 163 protected LockState acquireLock(final MasterProcedureEnv env) { 164 if (env.getProcedureScheduler().waitNamespaceExclusiveLock(this, getNamespaceName())) { 165 return LockState.LOCK_EVENT_WAIT; 166 } 167 return LockState.LOCK_ACQUIRED; 168 } 169 170 @Override 171 public TableOperationType getTableOperationType() { 172 return TableOperationType.EDIT; 173 } 174 175 @Override 176 protected String getNamespaceName() { 177 return nsDescriptor.getName(); 178 } 179 180 /** 181 * Action before any real action of creating namespace. 182 * @param env MasterProcedureEnv 183 */ 184 private boolean prepareCreate(final MasterProcedureEnv env) throws IOException { 185 if (getTableNamespaceManager(env).doesNamespaceExist(nsDescriptor.getName())) { 186 setFailure("master-create-namespace", 187 new NamespaceExistException("Namespace " + nsDescriptor.getName() + " already exists")); 188 return false; 189 } 190 getTableNamespaceManager(env).validateTableAndRegionCount(nsDescriptor); 191 checkNamespaceRSGroup(env, nsDescriptor); 192 return true; 193 } 194 195 /** 196 * Set quota for the namespace 197 * @param env MasterProcedureEnv 198 * @param nsDescriptor NamespaceDescriptor 199 **/ 200 private static void setNamespaceQuota(final MasterProcedureEnv env, 201 final NamespaceDescriptor nsDescriptor) throws IOException { 202 if (env.getMasterServices().isInitialized()) { 203 env.getMasterServices().getMasterQuotaManager().setNamespaceQuota(nsDescriptor); 204 } 205 } 206}