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}