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 org.apache.hadoop.hbase.CellUtil;
022import org.apache.hadoop.hbase.HConstants;
023import org.apache.hadoop.hbase.TableName;
024import org.apache.hadoop.hbase.client.BufferedMutator;
025import org.apache.hadoop.hbase.client.Connection;
026import org.apache.hadoop.hbase.client.Put;
027import org.apache.hadoop.hbase.client.Result;
028import org.apache.hadoop.hbase.client.ResultScanner;
029import org.apache.hadoop.hbase.client.Scan;
030import org.apache.hadoop.hbase.client.Table;
031import org.apache.hadoop.hbase.client.TableDescriptor;
032import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
033import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
034import org.apache.hadoop.hbase.procedure2.ProcedureUtil;
035import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
036import org.apache.hadoop.hbase.procedure2.StateMachineProcedure;
037import org.apache.hadoop.hbase.util.FSTableDescriptors;
038import org.apache.hadoop.hbase.util.RetryCounter;
039import org.apache.yetus.audience.InterfaceAudience;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.MigrateNamespaceTableProcedureState;
044
045/**
046 * Migrate the namespace data to meta table's namespace family while upgrading
047 */
048@InterfaceAudience.Private
049public class MigrateNamespaceTableProcedure
050  extends StateMachineProcedure<MasterProcedureEnv, MigrateNamespaceTableProcedureState>
051  implements GlobalProcedureInterface {
052
053  private static final Logger LOG = LoggerFactory.getLogger(MigrateNamespaceTableProcedure.class);
054
055  private RetryCounter retryCounter;
056
057  @Override
058  public String getGlobalId() {
059    return getClass().getSimpleName();
060  }
061
062  private void migrate(MasterProcedureEnv env) throws IOException {
063    Connection conn = env.getMasterServices().getConnection();
064    try (Table nsTable = conn.getTable(TableName.NAMESPACE_TABLE_NAME);
065      ResultScanner scanner = nsTable.getScanner(
066        new Scan().addFamily(TableDescriptorBuilder.NAMESPACE_FAMILY_INFO_BYTES).readAllVersions());
067      BufferedMutator mutator = conn.getBufferedMutator(TableName.META_TABLE_NAME)) {
068      for (Result result;;) {
069        result = scanner.next();
070        if (result == null) {
071          break;
072        }
073        Put put = new Put(result.getRow());
074        result
075          .getColumnCells(TableDescriptorBuilder.NAMESPACE_FAMILY_INFO_BYTES,
076            TableDescriptorBuilder.NAMESPACE_COL_DESC_BYTES)
077          .forEach(c -> put.addColumn(HConstants.NAMESPACE_FAMILY,
078            HConstants.NAMESPACE_COL_DESC_QUALIFIER, c.getTimestamp(), CellUtil.cloneValue(c)));
079        mutator.mutate(put);
080      }
081    }
082  }
083
084  @Override
085  protected Flow executeFromState(MasterProcedureEnv env, MigrateNamespaceTableProcedureState state)
086    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
087    try {
088      switch (state) {
089        case MIGRATE_NAMESPACE_TABLE_ADD_FAMILY:
090          TableDescriptor metaTableDesc =
091            env.getMasterServices().getTableDescriptors().get(TableName.META_TABLE_NAME);
092          if (!metaTableDesc.hasColumnFamily(HConstants.NAMESPACE_FAMILY)) {
093            TableDescriptor newMetaTableDesc = TableDescriptorBuilder.newBuilder(metaTableDesc)
094              .setColumnFamily(
095                FSTableDescriptors.getNamespaceFamilyDescForMeta(env.getMasterConfiguration()))
096              .build();
097            addChildProcedure(new ModifyTableProcedure(env, newMetaTableDesc));
098          }
099          setNextState(MigrateNamespaceTableProcedureState.MIGRATE_NAMESPACE_TABLE_MIGRATE_DATA);
100          return Flow.HAS_MORE_STATE;
101        case MIGRATE_NAMESPACE_TABLE_MIGRATE_DATA:
102          migrate(env);
103          setNextState(MigrateNamespaceTableProcedureState.MIGRATE_NAMESPACE_TABLE_DISABLE_TABLE);
104          return Flow.HAS_MORE_STATE;
105        case MIGRATE_NAMESPACE_TABLE_DISABLE_TABLE:
106          addChildProcedure(new DisableTableProcedure(env, TableName.NAMESPACE_TABLE_NAME, false));
107          return Flow.NO_MORE_STATE;
108        default:
109          throw new UnsupportedOperationException("Unhandled state=" + state);
110      }
111    } catch (IOException e) {
112      if (retryCounter == null) {
113        retryCounter = ProcedureUtil.createRetryCounter(env.getMasterConfiguration());
114      }
115      long backoff = retryCounter.getBackoffTimeAndIncrementAttempts();
116      LOG.warn("Failed migrating namespace data, suspend {}secs {}", backoff / 1000, this, e);
117      throw suspend(Math.toIntExact(backoff), true);
118    }
119  }
120
121  @Override
122  protected void rollbackState(MasterProcedureEnv env, MigrateNamespaceTableProcedureState state)
123    throws IOException, InterruptedException {
124  }
125
126  @Override
127  protected MigrateNamespaceTableProcedureState getState(int stateId) {
128    return MigrateNamespaceTableProcedureState.forNumber(stateId);
129  }
130
131  @Override
132  protected int getStateId(MigrateNamespaceTableProcedureState state) {
133    return state.getNumber();
134  }
135
136  @Override
137  protected MigrateNamespaceTableProcedureState getInitialState() {
138    return MigrateNamespaceTableProcedureState.MIGRATE_NAMESPACE_TABLE_ADD_FAMILY;
139  }
140
141  @Override
142  protected void completionCleanup(MasterProcedureEnv env) {
143    env.getMasterServices().getClusterSchema().getTableNamespaceManager().setMigrationDone();
144  }
145}