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.HConstants;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.RegionInfoBuilder;
034import org.apache.hadoop.hbase.client.TableDescriptor;
035import org.apache.hadoop.hbase.master.assignment.TransitRegionStateProcedure;
036import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer;
037import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
038import org.apache.hadoop.hbase.procedure2.ProcedureUtil;
039import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
040import org.apache.hadoop.hbase.regionserver.HRegion;
041import org.apache.hadoop.hbase.util.CommonFSUtils;
042import org.apache.hadoop.hbase.util.FSTableDescriptors;
043import org.apache.hadoop.hbase.util.RetryCounter;
044import org.apache.yetus.audience.InterfaceAudience;
045import org.slf4j.Logger;
046import org.slf4j.LoggerFactory;
047
048import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.InitMetaState;
049import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.InitMetaStateData;
050import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
051
052/**
053 * This procedure is used to initialize meta table for a new hbase deploy. It will just schedule an
054 * {@link TransitRegionStateProcedure} to assign meta.
055 */
056@InterfaceAudience.Private
057public class InitMetaProcedure extends AbstractStateMachineTableProcedure<InitMetaState> {
058
059  private static final Logger LOG = LoggerFactory.getLogger(InitMetaProcedure.class);
060
061  private CountDownLatch latch = new CountDownLatch(1);
062
063  private RetryCounter retryCounter;
064
065  @Override
066  public TableName getTableName() {
067    return TableName.META_TABLE_NAME;
068  }
069
070  @Override
071  public TableOperationType getTableOperationType() {
072    return TableOperationType.CREATE;
073  }
074
075  private static void writeFsLayout(Path rootDir, Configuration conf) 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    FSTableDescriptors.tryUpdateMetaTableDescriptor(conf, fs, rootDir,
087      builder -> builder.setRegionReplication(
088        conf.getInt(HConstants.META_REPLICAS_NUM, HConstants.DEFAULT_META_REPLICA_NUM)));
089    TableDescriptor metaDescriptor = new FSTableDescriptors(conf).get(TableName.META_TABLE_NAME);
090    HRegion
091      .createHRegion(RegionInfoBuilder.FIRST_META_REGIONINFO, rootDir, conf, metaDescriptor, null)
092      .close();
093  }
094
095  @Override
096  protected Flow executeFromState(MasterProcedureEnv env, InitMetaState state)
097    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
098    LOG.debug("Execute {}", this);
099    try {
100      switch (state) {
101        case INIT_META_WRITE_FS_LAYOUT:
102          Configuration conf = env.getMasterConfiguration();
103          Path rootDir = CommonFSUtils.getRootDir(conf);
104          writeFsLayout(rootDir, conf);
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}