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