blob: f56974864d6a2f09110b79c13d9397f7c8a93146 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.namenode.ha;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
import org.apache.hadoop.ha.ServiceFailedException;
import org.apache.hadoop.hdfs.server.namenode.NameNode.OperationCategory;
import org.apache.hadoop.ipc.StandbyException;
import org.apache.hadoop.util.Time;
/**
* Namenode base state to implement state machine pattern.
*/
@InterfaceAudience.Private
abstract public class HAState {
protected final HAServiceState state;
private long lastHATransitionTime;
/**
* Constructor
* @param state HA service state.
*/
public HAState(HAServiceState state) {
this.state = state;
}
/**
* @return the generic service state
*/
public HAServiceState getServiceState() {
return state;
}
/**
* Internal method to move from the existing state to a new state.
* @param context HA context
* @param s new state
* @throws ServiceFailedException on failure to transition to new state.
*/
protected final void setStateInternal(final HAContext context, final HAState s)
throws ServiceFailedException {
prepareToExitState(context);
s.prepareToEnterState(context);
context.writeLock();
try {
exitState(context);
context.setState(s);
s.enterState(context);
s.updateLastHATransitionTime();
} finally {
context.writeUnlock();
}
}
/**
* Gets the most recent HA transition time in milliseconds from the epoch.
*
* @return the most recent HA transition time in milliseconds from the epoch.
*/
public long getLastHATransitionTime() {
return lastHATransitionTime;
}
private void updateLastHATransitionTime() {
lastHATransitionTime = Time.now();
}
/**
* Method to be overridden by subclasses to prepare to enter a state.
* This method is called <em>without</em> the context being locked,
* and after {@link #prepareToExitState(HAContext)} has been called
* for the previous state, but before {@link #exitState(HAContext)}
* has been called for the previous state.
* @param context HA context
* @throws ServiceFailedException on precondition failure
*/
public void prepareToEnterState(final HAContext context)
throws ServiceFailedException {}
/**
* Method to be overridden by subclasses to perform steps necessary for
* entering a state.
* @param context HA context
* @throws ServiceFailedException on failure to enter the state.
*/
public abstract void enterState(final HAContext context)
throws ServiceFailedException;
/**
* Method to be overridden by subclasses to prepare to exit a state.
* This method is called <em>without</em> the context being locked.
* This is used by the standby state to cancel any checkpoints
* that are going on. It can also be used to check any preconditions
* for the state transition.
*
* This method should not make any destructuve changes to the state
* (eg stopping threads) since {@link #prepareToEnterState(HAContext)}
* may subsequently cancel the state transition.
* @param context HA context
* @throws ServiceFailedException on precondition failure
*/
public void prepareToExitState(final HAContext context)
throws ServiceFailedException {}
/**
* Method to be overridden by subclasses to perform steps necessary for
* exiting a state.
* @param context HA context
* @throws ServiceFailedException on failure to enter the state.
*/
public abstract void exitState(final HAContext context)
throws ServiceFailedException;
/**
* Move from the existing state to a new state
* @param context HA context
* @param s new state
* @throws ServiceFailedException on failure to transition to new state.
*/
public void setState(HAContext context, HAState s) throws ServiceFailedException {
if (this == s) { // Aleady in the new state
return;
}
throw new ServiceFailedException("Transtion from state " + this + " to "
+ s + " is not allowed.");
}
/**
* Check if an operation is supported in a given state.
* @param context HA context
* @param op Type of the operation.
* @throws StandbyException if a given type of operation is not
* supported in standby state
*/
public abstract void checkOperation(final HAContext context, final OperationCategory op)
throws StandbyException;
public abstract boolean shouldPopulateReplQueues();
/**
* @return String representation of the service state.
*/
@Override
public String toString() {
return state.toString();
}
}