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 static org.apache.hadoop.hbase.NamespaceDescriptor.DEFAULT_NAMESPACE; 021import static org.apache.hadoop.hbase.NamespaceDescriptor.SYSTEM_NAMESPACE; 022import static org.apache.hadoop.hbase.master.TableNamespaceManager.insertNamespaceToMeta; 023import static org.apache.hadoop.hbase.master.procedure.AbstractStateMachineNamespaceProcedure.createDirectory; 024 025import java.io.IOException; 026import java.util.Arrays; 027import java.util.concurrent.CountDownLatch; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.fs.FileSystem; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.client.RegionInfoBuilder; 033import org.apache.hadoop.hbase.client.TableDescriptor; 034import org.apache.hadoop.hbase.master.assignment.TransitRegionStateProcedure; 035import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 036import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException; 037import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 038import org.apache.hadoop.hbase.procedure2.ProcedureYieldException; 039import org.apache.hadoop.hbase.regionserver.HRegion; 040import org.apache.hadoop.hbase.util.CommonFSUtils; 041import org.apache.hadoop.hbase.util.FSTableDescriptors; 042import org.apache.hadoop.hbase.util.RetryCounter; 043import org.apache.yetus.audience.InterfaceAudience; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.InitMetaState; 048import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.InitMetaStateData; 049import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos; 050 051/** 052 * This procedure is used to initialize meta table for a new hbase deploy. It will just schedule an 053 * {@link TransitRegionStateProcedure} to assign meta. 054 */ 055@InterfaceAudience.Private 056public class InitMetaProcedure extends AbstractStateMachineTableProcedure<InitMetaState> { 057 058 private static final Logger LOG = LoggerFactory.getLogger(InitMetaProcedure.class); 059 060 private CountDownLatch latch = new CountDownLatch(1); 061 062 private RetryCounter retryCounter; 063 064 @Override 065 public TableName getTableName() { 066 return TableName.META_TABLE_NAME; 067 } 068 069 @Override 070 public TableOperationType getTableOperationType() { 071 return TableOperationType.CREATE; 072 } 073 074 private static TableDescriptor writeFsLayout(Path rootDir, Configuration conf) 075 throws IOException { 076 LOG.info("BOOTSTRAP: creating hbase:meta region"); 077 FileSystem fs = rootDir.getFileSystem(conf); 078 Path tableDir = CommonFSUtils.getTableDir(rootDir, TableName.META_TABLE_NAME); 079 if (fs.exists(tableDir) && !fs.delete(tableDir, true)) { 080 LOG.warn("Can not delete partial created meta table, continue..."); 081 } 082 // Bootstrapping, make sure blockcache is off. Else, one will be 083 // created here in bootstrap and it'll need to be cleaned up. Better to 084 // not make it in first place. Turn off block caching for bootstrap. 085 // Enable after. 086 TableDescriptor metaDescriptor = 087 FSTableDescriptors.tryUpdateAndGetMetaTableDescriptor(conf, fs, rootDir); 088 HRegion 089 .createHRegion(RegionInfoBuilder.FIRST_META_REGIONINFO, rootDir, conf, metaDescriptor, null) 090 .close(); 091 return metaDescriptor; 092 } 093 094 @Override 095 protected Flow executeFromState(MasterProcedureEnv env, InitMetaState state) 096 throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException { 097 LOG.debug("Execute {}", this); 098 try { 099 switch (state) { 100 case INIT_META_WRITE_FS_LAYOUT: 101 Configuration conf = env.getMasterConfiguration(); 102 Path rootDir = CommonFSUtils.getRootDir(conf); 103 TableDescriptor td = writeFsLayout(rootDir, conf); 104 env.getMasterServices().getTableDescriptors().update(td, true); 105 setNextState(InitMetaState.INIT_META_ASSIGN_META); 106 return Flow.HAS_MORE_STATE; 107 case INIT_META_ASSIGN_META: 108 LOG.info("Going to assign meta"); 109 addChildProcedure(env.getAssignmentManager() 110 .createAssignProcedures(Arrays.asList(RegionInfoBuilder.FIRST_META_REGIONINFO))); 111 setNextState(InitMetaState.INIT_META_CREATE_NAMESPACES); 112 return Flow.HAS_MORE_STATE; 113 case INIT_META_CREATE_NAMESPACES: 114 LOG.info("Going to create {} and {} namespaces", DEFAULT_NAMESPACE, SYSTEM_NAMESPACE); 115 createDirectory(env, DEFAULT_NAMESPACE); 116 createDirectory(env, SYSTEM_NAMESPACE); 117 // here the TableNamespaceManager has not been initialized yet, so we have to insert the 118 // record directly into meta table, later the TableNamespaceManager will load these two 119 // namespaces when starting. 120 insertNamespaceToMeta(env.getMasterServices().getConnection(), DEFAULT_NAMESPACE); 121 insertNamespaceToMeta(env.getMasterServices().getConnection(), SYSTEM_NAMESPACE); 122 123 return Flow.NO_MORE_STATE; 124 default: 125 throw new UnsupportedOperationException("unhandled state=" + state); 126 } 127 } catch (IOException e) { 128 if (retryCounter == null) { 129 retryCounter = ProcedureUtil.createRetryCounter(env.getMasterConfiguration()); 130 } 131 long backoff = retryCounter.getBackoffTimeAndIncrementAttempts(); 132 LOG.warn("Failed to init meta, suspend {}secs", backoff, e); 133 setTimeout(Math.toIntExact(backoff)); 134 setState(ProcedureProtos.ProcedureState.WAITING_TIMEOUT); 135 skipPersistence(); 136 throw new ProcedureSuspendedException(); 137 } 138 } 139 140 @Override 141 protected boolean waitInitialized(MasterProcedureEnv env) { 142 // we do not need to wait for master initialized, we are part of the initialization. 143 return false; 144 } 145 146 @Override 147 protected synchronized boolean setTimeoutFailure(MasterProcedureEnv env) { 148 setState(ProcedureProtos.ProcedureState.RUNNABLE); 149 env.getProcedureScheduler().addFront(this); 150 return false; 151 } 152 153 @Override 154 protected void rollbackState(MasterProcedureEnv env, InitMetaState state) 155 throws IOException, InterruptedException { 156 throw new UnsupportedOperationException(); 157 } 158 159 @Override 160 protected InitMetaState getState(int stateId) { 161 return InitMetaState.forNumber(stateId); 162 } 163 164 @Override 165 protected int getStateId(InitMetaState state) { 166 return state.getNumber(); 167 } 168 169 @Override 170 protected InitMetaState getInitialState() { 171 return InitMetaState.INIT_META_WRITE_FS_LAYOUT; 172 } 173 174 @Override 175 protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException { 176 super.serializeStateData(serializer); 177 serializer.serialize(InitMetaStateData.getDefaultInstance()); 178 } 179 180 @Override 181 protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException { 182 super.deserializeStateData(serializer); 183 serializer.deserialize(InitMetaStateData.class); 184 } 185 186 @Override 187 protected void completionCleanup(MasterProcedureEnv env) { 188 latch.countDown(); 189 } 190 191 public void await() throws InterruptedException { 192 latch.await(); 193 } 194}