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 java.util.List;
022import org.apache.hadoop.hbase.HBaseIOException;
023import org.apache.hadoop.hbase.TableName;
024import org.apache.hadoop.hbase.client.TableDescriptor;
025import org.apache.hadoop.hbase.client.TableState;
026import org.apache.hadoop.hbase.procedure2.Procedure;
027import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
028import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
029import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
035import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.RestoreBackupSystemTableState;
036import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription;
037
038@InterfaceAudience.Private
039public class RestoreBackupSystemTableProcedure
040  extends AbstractStateMachineTableProcedure<RestoreBackupSystemTableState> {
041  private static final Logger LOG =
042    LoggerFactory.getLogger(RestoreBackupSystemTableProcedure.class);
043
044  private final SnapshotDescription snapshot;
045  private boolean enableOnRollback = false;
046
047  // Necessary for the procedure framework. Do not remove.
048  public RestoreBackupSystemTableProcedure() {
049    this(null);
050  }
051
052  public RestoreBackupSystemTableProcedure(SnapshotDescription snapshot) {
053    this.snapshot = snapshot;
054  }
055
056  @Override
057  public TableName getTableName() {
058    return TableName.valueOf(snapshot.getTable());
059  }
060
061  @Override
062  public TableOperationType getTableOperationType() {
063    return TableOperationType.RESTORE_BACKUP_SYSTEM_TABLE;
064  }
065
066  @Override
067  protected Flow executeFromState(MasterProcedureEnv env, RestoreBackupSystemTableState state)
068    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
069    LOG.info("{} execute state={}", this, state);
070
071    try {
072      switch (state) {
073        case RESTORE_BACKUP_SYSTEM_TABLE_PREPARE:
074          prepare(env);
075          return moreState(RestoreBackupSystemTableState.RESTORE_BACKUP_SYSTEM_TABLE_DISABLE);
076        case RESTORE_BACKUP_SYSTEM_TABLE_DISABLE:
077          TableState tableState =
078            env.getMasterServices().getTableStateManager().getTableState(getTableName());
079          if (tableState.isEnabled()) {
080            addChildProcedure(createDisableTableProcedure(env));
081          }
082          return moreState(RestoreBackupSystemTableState.RESTORE_BACKUP_SYSTEM_TABLE_RESTORE);
083        case RESTORE_BACKUP_SYSTEM_TABLE_RESTORE:
084          addChildProcedure(createRestoreSnapshotProcedure(env));
085          return moreState(RestoreBackupSystemTableState.RESTORE_BACKUP_SYSTEM_TABLE_ENABLE);
086        case RESTORE_BACKUP_SYSTEM_TABLE_ENABLE:
087          addChildProcedure(createEnableTableProcedure(env));
088          return Flow.NO_MORE_STATE;
089        default:
090          throw new UnsupportedOperationException("unhandled state=" + state);
091      }
092    } catch (Exception e) {
093      setFailure("restore-backup-system-table", e);
094      LOG.warn("unexpected exception while execute {}. Mark procedure Failed.", this, e);
095      return Flow.NO_MORE_STATE;
096    }
097  }
098
099  @Override
100  protected void rollbackState(MasterProcedureEnv env, RestoreBackupSystemTableState state)
101    throws IOException, InterruptedException {
102    switch (state) {
103      case RESTORE_BACKUP_SYSTEM_TABLE_DISABLE:
104      case RESTORE_BACKUP_SYSTEM_TABLE_PREPARE:
105        return;
106      case RESTORE_BACKUP_SYSTEM_TABLE_RESTORE:
107      case RESTORE_BACKUP_SYSTEM_TABLE_ENABLE:
108        if (enableOnRollback) {
109          addChildProcedure(createEnableTableProcedure(env));
110        }
111        return;
112      default:
113        throw new UnsupportedOperationException("unhandled state=" + state);
114    }
115  }
116
117  @Override
118  protected RestoreBackupSystemTableState getState(int stateId) {
119    return RestoreBackupSystemTableState.forNumber(stateId);
120  }
121
122  @Override
123  protected int getStateId(RestoreBackupSystemTableState state) {
124    return state.getNumber();
125  }
126
127  @Override
128  protected RestoreBackupSystemTableState getInitialState() {
129    return RestoreBackupSystemTableState.RESTORE_BACKUP_SYSTEM_TABLE_PREPARE;
130  }
131
132  private Flow moreState(RestoreBackupSystemTableState next) {
133    setNextState(next);
134    return Flow.HAS_MORE_STATE;
135  }
136
137  private Procedure<MasterProcedureEnv>[] createDisableTableProcedure(MasterProcedureEnv env)
138    throws HBaseIOException {
139    DisableTableProcedure disableTableProcedure =
140      new DisableTableProcedure(env, getTableName(), true);
141    return new DisableTableProcedure[] { disableTableProcedure };
142  }
143
144  private Procedure<MasterProcedureEnv>[] createEnableTableProcedure(MasterProcedureEnv env) {
145    EnableTableProcedure enableTableProcedure = new EnableTableProcedure(env, getTableName());
146    return new EnableTableProcedure[] { enableTableProcedure };
147  }
148
149  private Procedure<MasterProcedureEnv>[] createRestoreSnapshotProcedure(MasterProcedureEnv env)
150    throws IOException {
151    TableDescriptor desc = env.getMasterServices().getTableDescriptors().get(getTableName());
152    RestoreSnapshotProcedure restoreSnapshotProcedure =
153      new RestoreSnapshotProcedure(env, desc, snapshot);
154    return new RestoreSnapshotProcedure[] { restoreSnapshotProcedure };
155  }
156
157  private void prepare(MasterProcedureEnv env) throws IOException {
158    List<SnapshotDescription> snapshots =
159      env.getMasterServices().getSnapshotManager().getCompletedSnapshots();
160    boolean exists = snapshots.stream().anyMatch(s -> s.getName().equals(snapshot.getName()));
161    if (!exists) {
162      throw new SnapshotDoesNotExistException(ProtobufUtil.createSnapshotDesc(snapshot));
163    }
164
165    TableState tableState =
166      env.getMasterServices().getTableStateManager().getTableState(getTableName());
167    if (tableState.isEnabled()) {
168      enableOnRollback = true;
169    }
170  }
171}