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.fs.Path; 022import org.apache.hadoop.hbase.HBaseIOException; 023import org.apache.hadoop.hbase.TableName; 024import org.apache.hadoop.hbase.TableNotDisabledException; 025import org.apache.hadoop.hbase.TableNotEnabledException; 026import org.apache.hadoop.hbase.TableNotFoundException; 027import org.apache.hadoop.hbase.UnknownRegionException; 028import org.apache.hadoop.hbase.client.DoNotRetryRegionException; 029import org.apache.hadoop.hbase.client.RegionInfo; 030import org.apache.hadoop.hbase.client.TableState; 031import org.apache.hadoop.hbase.master.MasterServices; 032import org.apache.hadoop.hbase.master.TableStateManager; 033import org.apache.hadoop.hbase.master.assignment.RegionStateNode; 034import org.apache.hadoop.hbase.procedure2.StateMachineProcedure; 035import org.apache.hadoop.hbase.security.User; 036import org.apache.hadoop.hbase.util.CommonFSUtils; 037import org.apache.yetus.audience.InterfaceAudience; 038 039/** 040 * Base class for all the Table procedures that want to use a StateMachineProcedure. 041 * It provides helpers like basic locking, sync latch, and toStringClassDetails(). 042 */ 043@InterfaceAudience.Private 044public abstract class AbstractStateMachineTableProcedure<TState> 045 extends StateMachineProcedure<MasterProcedureEnv, TState> 046 implements TableProcedureInterface { 047 048 // used for compatibility with old clients 049 private final ProcedurePrepareLatch syncLatch; 050 051 private User user; 052 053 protected AbstractStateMachineTableProcedure() { 054 // Required by the Procedure framework to create the procedure on replay 055 syncLatch = null; 056 } 057 058 protected AbstractStateMachineTableProcedure(final MasterProcedureEnv env) { 059 this(env, null); 060 } 061 062 /** 063 * @param env Uses this to set Procedure Owner at least. 064 */ 065 protected AbstractStateMachineTableProcedure(final MasterProcedureEnv env, 066 final ProcedurePrepareLatch latch) { 067 if (env != null) { 068 this.user = env.getRequestUser(); 069 this.setOwner(user); 070 } 071 // used for compatibility with clients without procedures 072 // they need a sync TableExistsException, TableNotFoundException, TableNotDisabledException, ... 073 this.syncLatch = latch; 074 } 075 076 @Override 077 public abstract TableName getTableName(); 078 079 @Override 080 public abstract TableOperationType getTableOperationType(); 081 082 @Override 083 public void toStringClassDetails(final StringBuilder sb) { 084 sb.append(getClass().getSimpleName()); 085 sb.append(" table="); 086 sb.append(getTableName()); 087 } 088 089 @Override 090 protected boolean waitInitialized(MasterProcedureEnv env) { 091 return env.waitInitialized(this); 092 } 093 094 @Override 095 protected LockState acquireLock(final MasterProcedureEnv env) { 096 if (env.getProcedureScheduler().waitTableExclusiveLock(this, getTableName())) { 097 return LockState.LOCK_EVENT_WAIT; 098 } 099 return LockState.LOCK_ACQUIRED; 100 } 101 102 @Override 103 protected void releaseLock(final MasterProcedureEnv env) { 104 env.getProcedureScheduler().wakeTableExclusiveLock(this, getTableName()); 105 } 106 107 protected User getUser() { 108 return user; 109 } 110 111 protected void setUser(final User user) { 112 this.user = user; 113 } 114 115 protected void releaseSyncLatch() { 116 ProcedurePrepareLatch.releaseLatch(syncLatch, this); 117 } 118 119 /** 120 * Check whether a table is modifiable - exists and either offline or online with config set 121 * @param env MasterProcedureEnv 122 */ 123 protected void checkTableModifiable(final MasterProcedureEnv env) throws IOException { 124 // Checks whether the table exists 125 if (!env.getMasterServices().getTableDescriptors().exists(getTableName())) { 126 throw new TableNotFoundException(getTableName()); 127 } 128 } 129 130 protected final Path getWALRegionDir(MasterProcedureEnv env, RegionInfo region) 131 throws IOException { 132 return CommonFSUtils.getWALRegionDir(env.getMasterConfiguration(), 133 region.getTable(), region.getEncodedName()); 134 } 135 136 /** 137 * Check that cluster is up and master is running. Check table is modifiable. 138 * If <code>enabled</code>, check table is enabled else check it is disabled. 139 * Call in Procedure constructor so can pass any exception to caller. 140 * @param enabled If true, check table is enabled and throw exception if not. If false, do the 141 * inverse. If null, do no table checks. 142 */ 143 protected void preflightChecks(MasterProcedureEnv env, Boolean enabled) throws HBaseIOException { 144 MasterServices master = env.getMasterServices(); 145 if (!master.isClusterUp()) { 146 throw new HBaseIOException("Cluster not up!"); 147 } 148 if (master.isStopping() || master.isStopped()) { 149 throw new HBaseIOException("Master stopping=" + master.isStopping() + 150 ", stopped=" + master.isStopped()); 151 } 152 if (enabled == null) { 153 // Don't do any table checks. 154 return; 155 } 156 try { 157 // Checks table exists and is modifiable. 158 checkTableModifiable(env); 159 TableName tn = getTableName(); 160 TableStateManager tsm = master.getTableStateManager(); 161 TableState ts = tsm.getTableState(tn); 162 if (enabled) { 163 if (!ts.isEnabledOrEnabling()) { 164 throw new TableNotEnabledException(tn); 165 } 166 } else { 167 if (!ts.isDisabledOrDisabling()) { 168 throw new TableNotDisabledException(tn); 169 } 170 } 171 } catch (IOException ioe) { 172 if (ioe instanceof HBaseIOException) { 173 throw (HBaseIOException)ioe; 174 } 175 throw new HBaseIOException(ioe); 176 } 177 } 178 179 protected boolean isTableEnabled(MasterProcedureEnv env) { 180 return env.getMasterServices().getTableStateManager().isTableState(getTableName(), 181 TableState.State.ENABLED); 182 } 183 184 /** 185 * Check region is online. 186 */ 187 protected static void checkOnline(MasterProcedureEnv env, RegionInfo ri) 188 throws DoNotRetryRegionException { 189 RegionStateNode regionNode = 190 env.getAssignmentManager().getRegionStates().getRegionStateNode(ri); 191 if (regionNode == null) { 192 throw new UnknownRegionException("No RegionState found for " + ri.getEncodedName()); 193 } 194 regionNode.checkOnline(); 195 } 196}