/**
* 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;
import com.google.common.annotations.VisibleForTesting;
import io.hops.security.Users;
import io.hops.exception.StorageException;
import io.hops.leaderElection.HdfsLeDescriptorFactory;
import io.hops.leaderElection.LeaderElection;
import io.hops.leader_election.node.ActiveNode;
import io.hops.leader_election.node.SortedActiveNodeList;
import io.hops.metadata.HdfsStorageFactory;
import io.hops.metadata.HdfsVariables;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Trash;
import org.apache.hadoop.ha.ServiceFailedException;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.DFSUtil;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.protocol.ClientProtocol;
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
import org.apache.hadoop.hdfs.server.blockmanagement.BRTrackingService;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
import org.apache.hadoop.hdfs.server.common.StorageInfo;
import org.apache.hadoop.hdfs.server.datanode.BRLoadBalancingException;
import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
import org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol;
import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol;
import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols;
import org.apache.hadoop.hdfs.server.protocol.NamenodeRegistration;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.net.NetUtils;
import org.apache.hadoop.security.RefreshUserMappingsProtocol;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol;
import org.apache.hadoop.tools.GetUserMappingsProtocol;
import org.apache.hadoop.util.ExitUtil.ExitException;
import org.apache.hadoop.util.ServicePlugin;
import org.apache.hadoop.util.StringUtils;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.List;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_DEFAULT;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_PLUGINS_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_RPC_ADDRESS_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_STARTUP_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_DEFAULT;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_USER_NAME_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT;
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.FS_DEFAULT_NAME_KEY;
import static org.apache.hadoop.hdfs.DFSConfigKeys.FS_TRASH_INTERVAL_DEFAULT;
import static org.apache.hadoop.hdfs.DFSConfigKeys.FS_TRASH_INTERVAL_KEY;
import static org.apache.hadoop.util.ExitUtil.terminate;
/**
* ********************************************************
* NameNode serves as both directory namespace manager and "inode table" for
* the
* Hadoop DFS. There is a single NameNode running in any DFS deployment. (Well,
* except when there is a second backup/failover NameNode, or when using
* federated NameNodes.)
* <p/>
* The NameNode controls two critical tables: 1) filename->blocksequence
* (namespace) 2) block->machinelist ("inodes")
* <p/>
* The first table is stored on disk and is very precious. The second table is
* rebuilt every time the NameNode comes up.
* <p/>
* 'NameNode' refers to both this class as well as the 'NameNode server'. The
* 'FSNamesystem' class actually performs most of the filesystem management.
* The
* majority of the 'NameNode' class itself is concerned with exposing the IPC
* interface and the HTTP server to the outside world, plus some configuration
* management.
* <p/>
* NameNode implements the
* {@link org.apache.hadoop.hdfs.protocol.ClientProtocol} interface, which
* allows clients to ask for DFS services.
* {@link org.apache.hadoop.hdfs.protocol.ClientProtocol} is not designed for
* direct use by authors of DFS client code. End-users should instead use the
* {@link org.apache.hadoop.fs.FileSystem} class.
* <p/>
* NameNode also implements the
* {@link org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol} interface,
* used by DataNodes that actually store DFS data blocks. These methods are
* invoked repeatedly and automatically by all the DataNodes in a DFS
* deployment.
* <p/>
* NameNode also implements the
* {@link org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol} interface,
* used by secondary namenodes or rebalancing processes to get partial NameNode
* state, for example partial blocksMap etc.
* ********************************************************
*/
@InterfaceAudience.Private
public class NameNode {
static {
HdfsConfiguration.init();
}
/**
* HDFS configuration can have three types of parameters:
* <ol>
* <li>Parameters that are common for all the name services in the
* cluster.</li>
* <li>Parameters that are specific to a name service. These keys are
* suffixed with nameserviceId in the configuration. For example,
* "dfs.namenode.rpc-address.nameservice1".</li>
* <li>Parameters that are specific to a single name node. These keys are
* suffixed with nameserviceId and namenodeId in the configuration. for
* example, "dfs.namenode.rpc-address.nameservice1.namenode1"</li>
* </ol>
* <p/>
* In the latter cases, operators may specify the configuration without any
* suffix, with a nameservice suffix, or with a nameservice and namenode
* suffix. The more specific suffix will take precedence.
* <p/>
* These keys are specific to a given namenode, and thus may be configured
* globally, for a nameservice, or for a specific namenode within a
* nameservice.
*/
public static final String[] NAMENODE_SPECIFIC_KEYS =
{DFS_NAMENODE_RPC_ADDRESS_KEY, DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY,
DFS_NAMENODE_HTTP_ADDRESS_KEY, DFS_NAMENODE_KEYTAB_FILE_KEY,
DFS_NAMENODE_USER_NAME_KEY};
private static final String USAGE =
"Usage: java NameNode [" +
//StartupOption.BACKUP.getName() + "] | [" +
//StartupOption.CHECKPOINT.getName() + "] | [" +
StartupOption.FORMAT.getName() + " [" +
StartupOption.CLUSTERID.getName() + " cid ] | [" +
StartupOption.FORCE.getName() + "] [" +
StartupOption.NONINTERACTIVE.getName() + "] ] | [" +
//StartupOption.UPGRADE.getName() + "] | [" +
//StartupOption.ROLLBACK.getName() + "] | [" +
//StartupOption.FINALIZE.getName() + "] | [" +
//StartupOption.IMPORT.getName() + "] | [" +
//StartupOption.INITIALIZESHAREDEDITS.getName() + "] | [" +
//StartupOption.BOOTSTRAPSTANDBY.getName() + "] | [" +
//StartupOption.RECOVER.getName() + " [ " +
//StartupOption.FORCE.getName() + " ] ] | [ "+
StartupOption.SET_BLOCK_REPORT_PROCESS_SIZE.getName() + " noOfBlks ] | [" +
StartupOption.FORMAT_ALL.getName() + " ] | [" +
StartupOption.DROP_AND_CREATE_DB.getName() + "]" ;
public long getProtocolVersion(String protocol, long clientVersion)
throws IOException {
if (protocol.equals(ClientProtocol.class.getName())) {
return ClientProtocol.versionID;
} else if (protocol.equals(DatanodeProtocol.class.getName())) {
return DatanodeProtocol.versionID;
} else if (protocol.equals(NamenodeProtocol.class.getName())) {
return NamenodeProtocol.versionID;
} else if (protocol
.equals(RefreshAuthorizationPolicyProtocol.class.getName())) {
return RefreshAuthorizationPolicyProtocol.versionID;
} else if (protocol.equals(RefreshUserMappingsProtocol.class.getName())) {
return RefreshUserMappingsProtocol.versionID;
} else if (protocol.equals(GetUserMappingsProtocol.class.getName())) {
return GetUserMappingsProtocol.versionID;
} else {
throw new IOException("Unknown protocol to name node: " + protocol);
}
}
public static final int DEFAULT_PORT = 8020;
public static final Log LOG = LogFactory.getLog(NameNode.class.getName());
public static final Log stateChangeLog =
LogFactory.getLog("org.apache.hadoop.hdfs.StateChange");
public static final Log blockStateChangeLog =
LogFactory.getLog("BlockStateChange");
protected FSNamesystem namesystem;
protected final Configuration conf;
/**
* httpServer
*/
protected NameNodeHttpServer httpServer;
private Thread emptier;
/**
* only used for testing purposes
*/
protected boolean stopRequested = false;
/**
* Registration information of this name-node
*/
protected NamenodeRegistration nodeRegistration;
/**
* Activated plug-ins.
*/
private List<ServicePlugin> plugins;
private NameNodeRpcServer rpcServer;
protected LeaderElection leaderElection;
/**
* for block report load balancing
*/
private BRTrackingService brTrackingService;
/**
* Format a new filesystem. Destroys any filesystem that may already exist
* at this location. *
*/
public static void format(Configuration conf) throws IOException {
formatHdfs(conf, false, true);
}
static NameNodeMetrics metrics;
/**
* Return the {@link FSNamesystem} object.
*
* @return {@link FSNamesystem} object.
*/
public FSNamesystem getNamesystem() {
return namesystem;
}
public NamenodeProtocols getRpcServer() {
return rpcServer;
}
static void initMetrics(Configuration conf, NamenodeRole role) {
metrics = NameNodeMetrics.create(conf, role);
}
public static NameNodeMetrics getNameNodeMetrics() {
return metrics;
}
public static InetSocketAddress getAddress(String address) {
return NetUtils.createSocketAddr(address, DEFAULT_PORT);
}
/**
* Set the configuration property for the service rpc address to address
*/
public static void setServiceAddress(Configuration conf, String address) {
LOG.info("Setting ADDRESS " + address);
conf.set(DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY, address);
}
/**
* Fetches the address for services to use when connecting to namenode based
* on the value of fallback returns null if the special address is not
* specified or returns the default namenode address to be used by both
* clients and services. Services here are datanodes, backup node, any non
* client connection
*/
public static InetSocketAddress getServiceAddress(Configuration conf,
boolean fallback) {
String addr = conf.get(DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY);
if (addr == null || addr.isEmpty()) {
return fallback ? getAddress(conf) : null;
}
return getAddress(addr);
}
public static InetSocketAddress getAddress(Configuration conf) {
URI filesystemURI = FileSystem.getDefaultUri(conf);
return getAddress(filesystemURI);
}
/**
* TODO:FEDERATION
*
* @param filesystemURI
* @return address of file system
*/
public static InetSocketAddress getAddress(URI filesystemURI) {
String authority = filesystemURI.getAuthority();
if (authority == null) {
throw new IllegalArgumentException(String.format(
"Invalid URI for NameNode address (check %s): %s has no authority.",
FileSystem.FS_DEFAULT_NAME_KEY, filesystemURI.toString()));
}
if (!HdfsConstants.HDFS_URI_SCHEME
.equalsIgnoreCase(filesystemURI.getScheme())) {
throw new IllegalArgumentException(String.format(
"Invalid URI for NameNode address (check %s): %s is not of scheme '%s'.",
FileSystem.FS_DEFAULT_NAME_KEY, filesystemURI.toString(),
HdfsConstants.HDFS_URI_SCHEME));
}
return getAddress(authority);
}
public static URI getUri(InetSocketAddress namenode) {
int port = namenode.getPort();
String portString = port == DEFAULT_PORT ? "" : (":" + port);
return URI.create(
HdfsConstants.HDFS_URI_SCHEME + "://" + namenode.getHostName() +
portString);
}
//
// Common NameNode methods implementation for the active name-node role.
//
public NamenodeRole getRole() {
if (leaderElection != null && leaderElection.isLeader()) {
return NamenodeRole.LEADER_NAMENODE;
}
return NamenodeRole.NAMENODE;
}
boolean isRole(NamenodeRole that) {
NamenodeRole currentRole = getRole();
return currentRole.equals(that);
}
/**
* Given a configuration get the address of the service rpc server If the
* service rpc is not configured returns null
*/
protected InetSocketAddress getServiceRpcServerAddress(Configuration conf) {
return NameNode.getServiceAddress(conf, false);
}
protected InetSocketAddress getRpcServerAddress(Configuration conf) {
return getAddress(conf);
}
/**
* Modifies the configuration passed to contain the service rpc address
* setting
*/
protected void setRpcServiceServerAddress(Configuration conf,
InetSocketAddress serviceRPCAddress) {
setServiceAddress(conf, NetUtils.getHostPortString(serviceRPCAddress));
}
protected void setRpcServerAddress(Configuration conf,
InetSocketAddress rpcAddress) {
FileSystem.setDefaultUri(conf, getUri(rpcAddress));
}
protected InetSocketAddress getHttpServerAddress(Configuration conf) {
return getHttpAddress(conf);
}
/**
* @return the NameNode HTTP address set in the conf.
*/
public static InetSocketAddress getHttpAddress(Configuration conf) {
return NetUtils.createSocketAddr(conf.get(DFS_NAMENODE_HTTP_ADDRESS_KEY,
DFS_NAMENODE_HTTP_ADDRESS_DEFAULT));
}
protected void setHttpServerAddress(Configuration conf) {
String hostPort = NetUtils.getHostPortString(getHttpAddress());
conf.set(DFS_NAMENODE_HTTP_ADDRESS_KEY, hostPort);
LOG.info("Web-server up at: " + hostPort);
}
protected void loadNamesystem(Configuration conf) throws IOException {
this.namesystem = FSNamesystem.loadFromDisk(conf, this);
}
NamenodeRegistration getRegistration() {
return nodeRegistration;
}
NamenodeRegistration setRegistration() throws IOException {
nodeRegistration = new NamenodeRegistration(
NetUtils.getHostPortString(rpcServer.getRpcAddress()),
NetUtils.getHostPortString(getHttpAddress()),
StorageInfo.getStorageInfoFromDB(),
getRole()); //HOP change. previous code was getFSImage().getStorage()
return nodeRegistration;
}
/**
* Login as the configured user for the NameNode.
*/
void loginAsNameNodeUser(Configuration conf) throws IOException {
InetSocketAddress socAddr = getRpcServerAddress(conf);
SecurityUtil
.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY, DFS_NAMENODE_USER_NAME_KEY,
socAddr.getHostName());
}
/**
* Initialize name-node.
*
* @param conf
* the configuration
*/
protected void initialize(Configuration conf) throws IOException {
UserGroupInformation.setConfiguration(conf);
loginAsNameNodeUser(conf);
HdfsStorageFactory.setConfiguration(conf);
this.brTrackingService = new BRTrackingService(conf.getLong(DFSConfigKeys.DFS_BR_LB_DB_VAR_UPDATE_THRESHOLD,
DFSConfigKeys.DFS_BR_LB_DB_VAR_UPDATE_THRESHOLD_DEFAULT),
conf.getLong(DFSConfigKeys.DFS_BR_LB_TIME_WINDOW_SIZE,
DFSConfigKeys.DFS_BR_LB_TIME_WINDOW_SIZE_DEFAULT));
String fsOwnerShortUserName = UserGroupInformation.getCurrentUser()
.getShortUserName();
String superGroup = conf.get(DFS_PERMISSIONS_SUPERUSERGROUP_KEY,
DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT);
Users.addUserToGroup(fsOwnerShortUserName, superGroup);
NameNode.initMetrics(conf, this.getRole());
loadNamesystem(conf);
rpcServer = createRpcServer(conf);
try {
validateConfigurationSettings(conf);
} catch (IOException e) {
LOG.fatal(e.toString());
throw e;
}
startCommonServices(conf);
}
/**
* Create the RPC server implementation. Used as an extension point for the
* BackupNode.
*/
protected NameNodeRpcServer createRpcServer(Configuration conf)
throws IOException {
return new NameNodeRpcServer(conf, this);
}
/**
* Verifies that the final Configuration Settings look ok for the NameNode
* to properly start up Things to check for include: - HTTP Server Port does
* not equal the RPC Server Port
*
* @param conf
* @throws IOException
*/
protected void validateConfigurationSettings(final Configuration conf)
throws IOException {
// check to make sure the web port and rpc port do not match
if (getHttpServerAddress(conf).getPort() ==
getRpcServerAddress(conf).getPort()) {
String errMsg =
"dfs.namenode.rpc-address " + "(" + getRpcServerAddress(conf) +
") and " + "dfs.namenode.http-address (" +
getHttpServerAddress(conf) + ") " +
"configuration keys are bound to the same port, unable to start " +
"NameNode. Port: " + getRpcServerAddress(conf).getPort();
throw new IOException(errMsg);
}
}
/**
* Start the services common to active and standby states
*/
private void startCommonServices(Configuration conf) throws IOException {
startHttpServer(conf);
startLeaderElectionService();
namesystem.startCommonServices(conf);
rpcServer.start();
plugins = conf.getInstances(DFS_NAMENODE_PLUGINS_KEY, ServicePlugin.class);
for (ServicePlugin p : plugins) {
try {
p.start(this);
} catch (Throwable t) {
LOG.warn("ServicePlugin " + p + " could not be started", t);
}
}
LOG.info(getRole() + " RPC up at: " + rpcServer.getRpcAddress());
if (rpcServer.getServiceRpcAddress() != null) {
LOG.info(getRole() + " service RPC up at: " +
rpcServer.getServiceRpcAddress());
}
}
private void stopCommonServices() {
if (namesystem != null) {
namesystem.close();
}
if (rpcServer != null) {
rpcServer.stop();
}
if (leaderElection != null && leaderElection.isRunning()) {
leaderElection.stopElectionThread();
}
if (plugins != null) {
for (ServicePlugin p : plugins) {
try {
p.stop();
} catch (Throwable t) {
LOG.warn("ServicePlugin " + p + " could not be stopped", t);
}
}
}
stopHttpServer();
}
private void startTrashEmptier(final Configuration conf) throws IOException {
long trashInterval =
conf.getLong(FS_TRASH_INTERVAL_KEY, FS_TRASH_INTERVAL_DEFAULT);
if (trashInterval == 0) {
return;
} else if (trashInterval < 0) {
throw new IOException(
"Cannot start tresh emptier with negative interval." + " Set " +
FS_TRASH_INTERVAL_KEY + " to a positive value.");
}
// This may be called from the transitionToActive code path, in which
// case the current user is the administrator, not the NN. The trash
// emptier needs to run as the NN. See HDFS-3972.
FileSystem fs =
SecurityUtil.doAsLoginUser(new PrivilegedExceptionAction<FileSystem>() {
@Override
public FileSystem run() throws IOException {
return FileSystem.get(conf);
}
});
this.emptier =
new Thread(new Trash(fs, conf).getEmptier(), "Trash Emptier");
this.emptier.setDaemon(true);
this.emptier.start();
}
private void stopTrashEmptier() {
if (this.emptier != null) {
emptier.interrupt();
emptier = null;
}
}
private void startHttpServer(final Configuration conf) throws IOException {
httpServer = new NameNodeHttpServer(conf, this, getHttpServerAddress(conf));
httpServer.start();
setHttpServerAddress(conf);
}
private void stopHttpServer() {
try {
if (httpServer != null) {
httpServer.stop();
}
} catch (Exception e) {
LOG.error("Exception while stopping httpserver", e);
}
}
/**
* Start NameNode.
* <p/>
* The name-node can be started with one of the following startup options:
* <ul>
* <li>{@link StartupOption#REGULAR REGULAR} - normal name node startup</li>
* <li>{@link StartupOption#FORMAT FORMAT} - format name node</li>
* @param conf
* confirguration
* @throws IOException
*/
public NameNode(Configuration conf) throws IOException {
this(conf, NamenodeRole.NAMENODE);
}
protected NameNode(Configuration conf, NamenodeRole role) throws IOException {
this.conf = conf;
try {
initializeGenericKeys(conf);
initialize(conf);
enterActiveState();
} catch (IOException e) {
this.stop();
throw e;
} catch (HadoopIllegalArgumentException e) {
this.stop();
throw e;
}
}
/**
* Wait for service to finish. (Normally, it runs forever.)
*/
public void join() {
try {
rpcServer.join();
} catch (InterruptedException ie) {
LOG.info("Caught interrupted exception ", ie);
}
}
/**
* Stop all NameNode threads and wait for all to finish.
*/
public void stop() {
synchronized (this) {
if (stopRequested) {
return;
}
stopRequested = true;
}
try {
exitActiveServices();
} catch (ServiceFailedException e) {
LOG.warn("Encountered exception while exiting state ", e);
} finally {
stopCommonServices();
if (metrics != null) {
metrics.shutdown();
}
if (namesystem != null) {
namesystem.shutdown();
}
}
}
synchronized boolean isStopRequested() {
return stopRequested;
}
/**
* Is the cluster currently in safe mode?
*/
public boolean isInSafeMode() throws IOException {
return namesystem.isInSafeMode();
}
/**
* @return NameNode RPC address
*/
public InetSocketAddress getNameNodeAddress() {
return rpcServer.getRpcAddress();
}
/**
* @return NameNode RPC address in "host:port" string form
*/
public String getNameNodeAddressHostPortString() {
return NetUtils.getHostPortString(rpcServer.getRpcAddress());
}
/**
* @return NameNode service RPC address if configured, the NameNode RPC
* address otherwise
*/
public InetSocketAddress getServiceRpcAddress() {
final InetSocketAddress serviceAddr = rpcServer.getServiceRpcAddress();
return serviceAddr == null ? rpcServer.getRpcAddress() : serviceAddr;
}
/**
* @return NameNode HTTP address, used by the Web UI, image transfer, and
* HTTP-based file system clients like Hftp and WebHDFS
*/
public InetSocketAddress getHttpAddress() {
return httpServer.getHttpAddress();
}
/**
* Verify that configured directories exist, then Interactively confirm that
* formatting is desired for each existing directory and format them.
*
* @param conf
* @param force
* @return true if formatting was aborted, false otherwise
* @throws IOException
*/
private static boolean formatHdfs(Configuration conf, boolean force,
boolean isInteractive) throws IOException {
initializeGenericKeys(conf);
checkAllowFormat(conf);
if (UserGroupInformation.isSecurityEnabled()) {
InetSocketAddress socAddr = getAddress(conf);
SecurityUtil
.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY, DFS_NAMENODE_USER_NAME_KEY,
socAddr.getHostName());
}
// if clusterID is not provided - see if you can find the current one
String clusterId = StartupOption.FORMAT.getClusterId();
if (clusterId == null || clusterId.equals("")) {
//Generate a new cluster id
clusterId = StorageInfo.newClusterID();
}
System.out.println("Formatting using clusterid: " + clusterId);
try {
HdfsStorageFactory.setConfiguration(conf);
if (force) {
HdfsStorageFactory.formatHdfsStorageNonTransactional();
} else {
HdfsStorageFactory.formatHdfsStorage();
}
StorageInfo
.storeStorageInfoToDB(clusterId); //this adds new row to the db
} catch (StorageException e) {
throw new RuntimeException(e.getMessage());
}
return false;
}
@VisibleForTesting
public static boolean formatAll(Configuration conf) throws IOException {
System.out.println("Formatting HopsFS and HopsYarn");
initializeGenericKeys(conf);
if (UserGroupInformation.isSecurityEnabled()) {
InetSocketAddress socAddr = getAddress(conf);
SecurityUtil
.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY, DFS_NAMENODE_USER_NAME_KEY,
socAddr.getHostName());
}
// if clusterID is not provided - see if you can find the current one
String clusterId = StartupOption.FORMAT.getClusterId();
if (clusterId == null || clusterId.equals("")) {
//Generate a new cluster id
clusterId = StorageInfo.newClusterID();
}
try {
HdfsStorageFactory.setConfiguration(conf);
// HdfsStorageFactory.formatAllStorageNonTransactional();
HdfsStorageFactory.formatStorage();
StorageInfo.storeStorageInfoToDB(clusterId); //this adds new row to the db
} catch (StorageException e) {
throw new RuntimeException(e.getMessage());
}
return false;
}
public static void checkAllowFormat(Configuration conf) throws IOException {
if (!conf.getBoolean(DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY,
DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_DEFAULT)) {
throw new IOException(
"The option " + DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY +
" is set to false for this filesystem, so it " +
"cannot be formatted. You will need to set " +
DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY + " parameter " +
"to true in order to format this filesystem");
}
}
private static void printUsage(PrintStream out) {
out.println(USAGE + "\n");
}
private static StartupOption parseArguments(String args[]) {
int argsLen = (args == null) ? 0 : args.length;
StartupOption startOpt = StartupOption.REGULAR;
for (int i = 0; i < argsLen; i++) {
String cmd = args[i];
if (StartupOption.SET_BLOCK_REPORT_PROCESS_SIZE.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.SET_BLOCK_REPORT_PROCESS_SIZE;
String msg = "Specify a maximum number of blocks that the NameNodes can process for block reporting.";
if ((i + 1) >= argsLen) {
// if no of blks not specified then return null
LOG.fatal(msg);
return null;
}
// Make sure an id is specified and not another flag
long noOfBlks = 0;
try{
noOfBlks = Long.parseLong(args[i+1]);
if(noOfBlks < 100000){
LOG.fatal("The number should be >= 100K. ");
return null;
}
}catch(NumberFormatException e){
return null;
}
startOpt.setMaxBlkRptProcessSize(noOfBlks);
return startOpt;
}
if (StartupOption.FORMAT.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.FORMAT;
for (i = i + 1; i < argsLen; i++) {
if (args[i].equalsIgnoreCase(StartupOption.CLUSTERID.getName())) {
i++;
if (i >= argsLen) {
// if no cluster id specified, return null
LOG.fatal("Must specify a valid cluster ID after the " +
StartupOption.CLUSTERID.getName() + " flag");
return null;
}
String clusterId = args[i];
// Make sure an id is specified and not another flag
if (clusterId.isEmpty() ||
clusterId.equalsIgnoreCase(StartupOption.FORCE.getName()) ||
clusterId
.equalsIgnoreCase(StartupOption.NONINTERACTIVE.getName())) {
LOG.fatal("Must specify a valid cluster ID after the " +
StartupOption.CLUSTERID.getName() + " flag");
return null;
}
startOpt.setClusterId(clusterId);
}
if (args[i].equalsIgnoreCase(StartupOption.FORCE.getName())) {
startOpt.setForceFormat(true);
}
if (args[i]
.equalsIgnoreCase(StartupOption.NONINTERACTIVE.getName())) {
startOpt.setInteractiveFormat(false);
}
}
} else if (StartupOption.DROP_AND_CREATE_DB.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.DROP_AND_CREATE_DB;
} else if (StartupOption.FORMAT_ALL.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.FORMAT_ALL;
} else if (StartupOption.GENCLUSTERID.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.GENCLUSTERID;
} else if (StartupOption.REGULAR.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.REGULAR;
} else if (StartupOption.BACKUP.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.BACKUP;
} else if (StartupOption.CHECKPOINT.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.CHECKPOINT;
} else if (StartupOption.UPGRADE.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.UPGRADE;
// might be followed by two args
if (i + 2 < argsLen &&
args[i + 1].equalsIgnoreCase(StartupOption.CLUSTERID.getName())) {
i += 2;
startOpt.setClusterId(args[i]);
}
} else if (StartupOption.ROLLBACK.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.ROLLBACK;
} else if (StartupOption.FINALIZE.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.FINALIZE;
} else if (StartupOption.IMPORT.getName().equalsIgnoreCase(cmd)) {
startOpt = StartupOption.IMPORT;
} else if (StartupOption.BOOTSTRAPSTANDBY.getName()
.equalsIgnoreCase(cmd)) {
startOpt = StartupOption.BOOTSTRAPSTANDBY;
return startOpt;
} else if (StartupOption.INITIALIZESHAREDEDITS.getName()
.equalsIgnoreCase(cmd)) {
startOpt = StartupOption.INITIALIZESHAREDEDITS;
for (i = i + 1; i < argsLen; i++) {
if (StartupOption.NONINTERACTIVE.getName().equals(args[i])) {
startOpt.setInteractiveFormat(false);
} else if (StartupOption.FORCE.getName().equals(args[i])) {
startOpt.setForceFormat(true);
} else {
LOG.fatal("Invalid argument: " + args[i]);
return null;
}
}
return startOpt;
} else if (StartupOption.RECOVER.getName().equalsIgnoreCase(cmd)) {
if (startOpt != StartupOption.REGULAR) {
throw new RuntimeException(
"Can't combine -recover with " + "other startup options.");
}
startOpt = StartupOption.RECOVER;
while (++i < argsLen) {
if (args[i].equalsIgnoreCase(StartupOption.FORCE.getName())) {
startOpt.setForce(MetaRecoveryContext.FORCE_FIRST_CHOICE);
} else {
throw new RuntimeException("Error parsing recovery options: " +
"can't understand option \"" + args[i] + "\"");
}
}
} else {
return null;
}
}
return startOpt;
}
private static void setStartupOption(Configuration conf, StartupOption opt) {
conf.set(DFS_NAMENODE_STARTUP_KEY, opt.toString());
}
static StartupOption getStartupOption(Configuration conf) {
return StartupOption.valueOf(
conf.get(DFS_NAMENODE_STARTUP_KEY, StartupOption.REGULAR.toString()));
}
public static NameNode createNameNode(String argv[], Configuration conf)
throws IOException {
if (conf == null) {
conf = new HdfsConfiguration();
}
StartupOption startOpt = parseArguments(argv);
if (startOpt == null) {
printUsage(System.err);
return null;
}
setStartupOption(conf, startOpt);
switch (startOpt) {
//HOP
case DROP_AND_CREATE_DB: { //delete everything other than inode and blocks table. this is tmp fix for safe mode
dropAndCreateDB(conf);
return null;
}
case SET_BLOCK_REPORT_PROCESS_SIZE:
HdfsVariables.setBrLbMasBlkPerMin(startOpt.getMaxBlkRptProcessSize());
LOG.fatal("Set block processing size to "+startOpt.getMaxBlkRptProcessSize());
return null;
case FORMAT: {
boolean aborted = formatHdfs(conf, startOpt.getForceFormat(),
startOpt.getInteractiveFormat());
terminate(aborted ? 1 : 0);
return null; // avoid javac warning
}
case FORMAT_ALL: {
boolean aborted = formatAll(conf);
terminate(aborted ? 1 : 0);
return null; // avoid javac warning
}
case GENCLUSTERID: {
System.err.println("Generating new cluster id:");
System.out.println(StorageInfo.newClusterID());
terminate(0);
return null;
}
case FINALIZE: {
throw new UnsupportedOperationException(
"HOP: FINALIZE is not supported anymore");
}
case BOOTSTRAPSTANDBY: {
throw new UnsupportedOperationException(
"HOP: BOOTSTRAPSTANDBY is not supported anymore");
}
case INITIALIZESHAREDEDITS: {
throw new UnsupportedOperationException(
"HOP: INITIALIZESHAREDEDITS is not supported anymore");
}
case BACKUP:
case CHECKPOINT: {
throw new UnsupportedOperationException(
"HOP: BACKUP/CHECKPOINT is not supported anymore");
}
case RECOVER: {
new UnsupportedOperationException(
"Hops. Metadata recovery is not supported");
return null;
}
default: {
DefaultMetricsSystem.initialize("NameNode");
return new NameNode(conf);
}
}
}
public static void initializeGenericKeys(Configuration conf) {
// If the RPC address is set use it to (re-)configure the default FS
if (conf.get(DFS_NAMENODE_RPC_ADDRESS_KEY) != null) {
URI defaultUri = URI.create(HdfsConstants.HDFS_URI_SCHEME + "://" +
conf.get(DFS_NAMENODE_RPC_ADDRESS_KEY));
conf.set(FS_DEFAULT_NAME_KEY, defaultUri.toString());
LOG.debug(
"Setting " + FS_DEFAULT_NAME_KEY + " to " + defaultUri.toString());
}
}
/**
*/
public static void main(String argv[]) throws Exception {
if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
System.exit(0);
}
try {
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
NameNode namenode = createNameNode(argv, null);
if (namenode != null) {
namenode.join();
}
} catch (Throwable e) {
LOG.fatal("Exception in namenode join", e);
terminate(1, e);
}
}
private void enterActiveState() throws ServiceFailedException {
try {
startActiveServicesInternal();
} catch (IOException e) {
throw new ServiceFailedException("Failed to start active services", e);
}
}
private void startActiveServicesInternal() throws IOException {
try {
namesystem.startActiveServices();
startTrashEmptier(conf);
} catch (Throwable t) {
doImmediateShutdown(t);
}
}
private void exitActiveServices() throws ServiceFailedException {
try {
stopActiveServicesInternal();
} catch (IOException e) {
throw new ServiceFailedException("Failed to stop active services", e);
}
}
private void stopActiveServicesInternal() throws IOException {
try {
if (namesystem != null) {
namesystem.stopActiveServices();
}
stopTrashEmptier();
} catch (Throwable t) {
doImmediateShutdown(t);
}
}
/**
* Shutdown the NN immediately in an ungraceful way. Used when it would be
* unsafe for the NN to continue operating, e.g. during a failed HA state
* transition.
*
* @param t
* exception which warrants the shutdown. Printed to the NN log
* before exit.
* @throws ExitException
* thrown only for testing.
*/
protected synchronized void doImmediateShutdown(Throwable t)
throws ExitException {
String message = "Error encountered requiring NN shutdown. " +
"Shutting down immediately.";
try {
LOG.fatal(message, t);
} catch (Throwable ignored) {
// This is unlikely to happen, but there's nothing we can do if it does.
}
terminate(1, t);
}
/**
* Returns the id of this namenode
*/
public long getId() {
return leaderElection.getCurrentId();
}
/**
* Return the {@link LeaderElection} object.
*
* @return {@link LeaderElection} object.
*/
public LeaderElection getLeaderElectionInstance() {
return leaderElection;
}
public boolean isLeader() {
if (leaderElection != null) {
return leaderElection.isLeader();
} else {
return false;
}
}
public ActiveNode getNextNamenodeToSendBlockReport(final long noOfBlks) throws IOException {
if(leaderElection.isLeader()) {
LOG.debug("NN Id: "+leaderElection.getCurrentId()+") Received request to assign work ("+noOfBlks+" blks) ");
ActiveNode an = brTrackingService.assignWork(leaderElection.getActiveNamenodes(), noOfBlks);
return an;
}else{
String msg = "NN Id: "+leaderElection.getCurrentId()+") Received request to assign work ("+noOfBlks+" blks). Returning null as I am not the leader NN";
LOG.debug(msg);
throw new BRLoadBalancingException(msg);
}
}
private static void dropAndCreateDB(Configuration conf) throws IOException {
HdfsStorageFactory.setConfiguration(conf);
HdfsStorageFactory.getConnector().dropAndRecreateDB();
}
public boolean isNameNodeAlive(long namenodeId) {
List<ActiveNode> activeNamenodes = getActiveNameNodes().getActiveNodes();
return isNameNodeAlive(activeNamenodes, namenodeId);
}
public static boolean isNameNodeAlive(Collection<ActiveNode> activeNamenodes,
long namenodeId) {
if (activeNamenodes == null) {
// We do not know yet, be conservative
return true;
}
for (ActiveNode namenode : activeNamenodes) {
if (namenode.getId() == namenodeId) {
return true;
}
}
return false;
}
public long getLeCurrentId() {
return leaderElection.getCurrentId();
}
public SortedActiveNodeList getActiveNameNodes() {
return leaderElection.getActiveNamenodes();
}
private void startLeaderElectionService() throws IOException {
// Initialize the leader election algorithm (only once rpc server is
// created and httpserver is started)
long leadercheckInterval =
conf.getInt(DFSConfigKeys.DFS_LEADER_CHECK_INTERVAL_IN_MS_KEY,
DFSConfigKeys.DFS_LEADER_CHECK_INTERVAL_IN_MS_DEFAULT);
int missedHeartBeatThreshold =
conf.getInt(DFSConfigKeys.DFS_LEADER_MISSED_HB_THRESHOLD_KEY,
DFSConfigKeys.DFS_LEADER_MISSED_HB_THRESHOLD_DEFAULT);
int leIncrement = conf.getInt(DFSConfigKeys.DFS_LEADER_TP_INCREMENT_KEY,
DFSConfigKeys.DFS_LEADER_TP_INCREMENT_DEFAULT);
leaderElection =
new LeaderElection(new HdfsLeDescriptorFactory(), leadercheckInterval,
missedHeartBeatThreshold, leIncrement,
httpServer.getHttpAddress().getAddress().getHostAddress() + ":" +
httpServer.getHttpAddress().getPort(),
rpcServer.getRpcAddress().getAddress().getHostAddress() + ":" +
rpcServer.getRpcAddress().getPort());
leaderElection.start();
try {
leaderElection.waitActive();
} catch (InterruptedException e) {
LOG.warn("NN was interrupted");
}
}
}