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