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.hdfs.server.namenode;
019
020import com.google.common.annotations.VisibleForTesting;
021import com.google.common.base.Joiner;
022import com.google.common.base.Preconditions;
023import com.google.common.collect.Lists;
024import org.apache.hadoop.HadoopIllegalArgumentException;
025import org.apache.hadoop.classification.InterfaceAudience;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.fs.FileSystem;
028import org.apache.hadoop.fs.Trash;
029import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
030import org.apache.hadoop.ha.HAServiceProtocol.StateChangeRequestInfo;
031import org.apache.hadoop.ha.HAServiceStatus;
032import org.apache.hadoop.ha.HealthCheckFailedException;
033import org.apache.hadoop.ha.ServiceFailedException;
034import org.apache.hadoop.hdfs.DFSConfigKeys;
035import org.apache.hadoop.hdfs.DFSUtil;
036import org.apache.hadoop.hdfs.HAUtil;
037import org.apache.hadoop.hdfs.HdfsConfiguration;
038import org.apache.hadoop.hdfs.protocol.ClientProtocol;
039import org.apache.hadoop.hdfs.protocol.HdfsConstants;
040import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
041import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.RollingUpgradeStartupOption;
042import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
043import org.apache.hadoop.hdfs.server.namenode.ha.ActiveState;
044import org.apache.hadoop.hdfs.server.namenode.ha.BootstrapStandby;
045import org.apache.hadoop.hdfs.server.namenode.ha.HAContext;
046import org.apache.hadoop.hdfs.server.namenode.ha.HAState;
047import org.apache.hadoop.hdfs.server.namenode.ha.StandbyState;
048import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
049import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgress;
050import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgressMetrics;
051import org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol;
052import org.apache.hadoop.hdfs.server.protocol.JournalProtocol;
053import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol;
054import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols;
055import org.apache.hadoop.hdfs.server.protocol.NamenodeRegistration;
056import org.apache.hadoop.hdfs.server.protocol.NamespaceInfo;
057import org.apache.hadoop.ipc.RefreshCallQueueProtocol;
058import org.apache.hadoop.ipc.Server;
059import org.apache.hadoop.ipc.StandbyException;
060import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
061import org.apache.hadoop.metrics2.util.MBeans;
062import org.apache.hadoop.net.NetUtils;
063import org.apache.hadoop.security.AccessControlException;
064import org.apache.hadoop.security.RefreshUserMappingsProtocol;
065import org.apache.hadoop.security.SecurityUtil;
066import org.apache.hadoop.security.UserGroupInformation;
067import org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol;
068import org.apache.hadoop.tools.GetUserMappingsProtocol;
069import org.apache.hadoop.tracing.SpanReceiverHost;
070import org.apache.hadoop.tracing.TraceAdminProtocol;
071import org.apache.hadoop.util.ExitUtil.ExitException;
072import org.apache.hadoop.util.GenericOptionsParser;
073import org.apache.hadoop.util.JvmPauseMonitor;
074import org.apache.hadoop.util.ServicePlugin;
075import org.apache.hadoop.util.StringUtils;
076import org.apache.log4j.LogManager;
077import org.slf4j.Logger;
078import org.slf4j.LoggerFactory;
079
080import javax.management.ObjectName;
081
082import java.io.IOException;
083import java.io.PrintStream;
084import java.net.InetSocketAddress;
085import java.net.URI;
086import java.security.PrivilegedExceptionAction;
087import java.util.ArrayList;
088import java.util.Arrays;
089import java.util.Collection;
090import java.util.List;
091import java.util.concurrent.atomic.AtomicBoolean;
092
093import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY;
094import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_DEFAULT;
095import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY;
096import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HA_AUTO_FAILOVER_ENABLED_DEFAULT;
097import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HA_AUTO_FAILOVER_ENABLED_KEY;
098import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HA_FENCE_METHODS_KEY;
099import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HA_NAMENODE_ID_KEY;
100import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_HA_ZKFC_PORT_KEY;
101import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_METRICS_PERCENTILES_INTERVALS_KEY;
102import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_BACKUP_ADDRESS_KEY;
103import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_BACKUP_HTTP_ADDRESS_KEY;
104import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_BACKUP_SERVICE_RPC_ADDRESS_KEY;
105import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_DIR_KEY;
106import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_EDITS_DIR_KEY;
107import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY;
108import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY;
109import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTPS_BIND_HOST_KEY;
110import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_DEFAULT;
111import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY;
112import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_HTTP_BIND_HOST_KEY;
113import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KERBEROS_INTERNAL_SPNEGO_PRINCIPAL_KEY;
114import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY;
115import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY;
116import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY;
117import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_PLUGINS_KEY;
118import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_RPC_ADDRESS_KEY;
119import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_RPC_BIND_HOST_KEY;
120import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SECONDARY_HTTPS_ADDRESS_KEY;
121import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SECONDARY_HTTP_ADDRESS_KEY;
122import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY;
123import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SERVICE_RPC_BIND_HOST_KEY;
124import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SHARED_EDITS_DIR_KEY;
125import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_STARTUP_KEY;
126import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_DEFAULT;
127import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY;
128import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMESERVICE_ID;
129import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_SECONDARY_NAMENODE_KEYTAB_FILE_KEY;
130import static org.apache.hadoop.hdfs.DFSConfigKeys.HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS;
131import static org.apache.hadoop.util.ExitUtil.terminate;
132import static org.apache.hadoop.util.ToolRunner.confirmPrompt;
133
134/**********************************************************
135 * NameNode serves as both directory namespace manager and
136 * "inode table" for the Hadoop DFS.  There is a single NameNode
137 * running in any DFS deployment.  (Well, except when there
138 * is a second backup/failover NameNode, or when using federated NameNodes.)
139 *
140 * The NameNode controls two critical tables:
141 *   1)  filename->blocksequence (namespace)
142 *   2)  block->machinelist ("inodes")
143 *
144 * The first table is stored on disk and is very precious.
145 * The second table is rebuilt every time the NameNode comes up.
146 *
147 * 'NameNode' refers to both this class as well as the 'NameNode server'.
148 * The 'FSNamesystem' class actually performs most of the filesystem
149 * management.  The majority of the 'NameNode' class itself is concerned
150 * with exposing the IPC interface and the HTTP server to the outside world,
151 * plus some configuration management.
152 *
153 * NameNode implements the
154 * {@link org.apache.hadoop.hdfs.protocol.ClientProtocol} interface, which
155 * allows clients to ask for DFS services.
156 * {@link org.apache.hadoop.hdfs.protocol.ClientProtocol} is not designed for
157 * direct use by authors of DFS client code.  End-users should instead use the
158 * {@link org.apache.hadoop.fs.FileSystem} class.
159 *
160 * NameNode also implements the
161 * {@link org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol} interface,
162 * used by DataNodes that actually store DFS data blocks.  These
163 * methods are invoked repeatedly and automatically by all the
164 * DataNodes in a DFS deployment.
165 *
166 * NameNode also implements the
167 * {@link org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol} interface,
168 * used by secondary namenodes or rebalancing processes to get partial
169 * NameNode state, for example partial blocksMap etc.
170 **********************************************************/
171@InterfaceAudience.Private
172public class NameNode implements NameNodeStatusMXBean {
173  static{
174    HdfsConfiguration.init();
175  }
176
177  /**
178   * Categories of operations supported by the namenode.
179   */
180  public static enum OperationCategory {
181    /** Operations that are state agnostic */
182    UNCHECKED,
183    /** Read operation that does not change the namespace state */
184    READ,
185    /** Write operation that changes the namespace state */
186    WRITE,
187    /** Operations related to checkpointing */
188    CHECKPOINT,
189    /** Operations related to {@link JournalProtocol} */
190    JOURNAL
191  }
192  
193  /**
194   * HDFS configuration can have three types of parameters:
195   * <ol>
196   * <li>Parameters that are common for all the name services in the cluster.</li>
197   * <li>Parameters that are specific to a name service. These keys are suffixed
198   * with nameserviceId in the configuration. For example,
199   * "dfs.namenode.rpc-address.nameservice1".</li>
200   * <li>Parameters that are specific to a single name node. These keys are suffixed
201   * with nameserviceId and namenodeId in the configuration. for example,
202   * "dfs.namenode.rpc-address.nameservice1.namenode1"</li>
203   * </ol>
204   * 
205   * In the latter cases, operators may specify the configuration without
206   * any suffix, with a nameservice suffix, or with a nameservice and namenode
207   * suffix. The more specific suffix will take precedence.
208   * 
209   * These keys are specific to a given namenode, and thus may be configured
210   * globally, for a nameservice, or for a specific namenode within a nameservice.
211   */
212  public static final String[] NAMENODE_SPECIFIC_KEYS = {
213    DFS_NAMENODE_RPC_ADDRESS_KEY,
214    DFS_NAMENODE_RPC_BIND_HOST_KEY,
215    DFS_NAMENODE_NAME_DIR_KEY,
216    DFS_NAMENODE_EDITS_DIR_KEY,
217    DFS_NAMENODE_SHARED_EDITS_DIR_KEY,
218    DFS_NAMENODE_CHECKPOINT_DIR_KEY,
219    DFS_NAMENODE_CHECKPOINT_EDITS_DIR_KEY,
220    DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY,
221    DFS_NAMENODE_SERVICE_RPC_BIND_HOST_KEY,
222    DFS_NAMENODE_HTTP_ADDRESS_KEY,
223    DFS_NAMENODE_HTTPS_ADDRESS_KEY,
224    DFS_NAMENODE_HTTP_BIND_HOST_KEY,
225    DFS_NAMENODE_HTTPS_BIND_HOST_KEY,
226    DFS_NAMENODE_KEYTAB_FILE_KEY,
227    DFS_NAMENODE_SECONDARY_HTTP_ADDRESS_KEY,
228    DFS_NAMENODE_SECONDARY_HTTPS_ADDRESS_KEY,
229    DFS_SECONDARY_NAMENODE_KEYTAB_FILE_KEY,
230    DFS_NAMENODE_BACKUP_ADDRESS_KEY,
231    DFS_NAMENODE_BACKUP_HTTP_ADDRESS_KEY,
232    DFS_NAMENODE_BACKUP_SERVICE_RPC_ADDRESS_KEY,
233    DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY,
234    DFS_NAMENODE_KERBEROS_INTERNAL_SPNEGO_PRINCIPAL_KEY,
235    DFS_HA_FENCE_METHODS_KEY,
236    DFS_HA_ZKFC_PORT_KEY,
237    DFS_HA_FENCE_METHODS_KEY
238  };
239  
240  /**
241   * @see #NAMENODE_SPECIFIC_KEYS
242   * These keys are specific to a nameservice, but may not be overridden
243   * for a specific namenode.
244   */
245  public static final String[] NAMESERVICE_SPECIFIC_KEYS = {
246    DFS_HA_AUTO_FAILOVER_ENABLED_KEY
247  };
248  
249  private static final String USAGE = "Usage: java NameNode ["
250      + StartupOption.BACKUP.getName() + "] | \n\t["
251      + StartupOption.CHECKPOINT.getName() + "] | \n\t["
252      + StartupOption.FORMAT.getName() + " ["
253      + StartupOption.CLUSTERID.getName() + " cid ] ["
254      + StartupOption.FORCE.getName() + "] ["
255      + StartupOption.NONINTERACTIVE.getName() + "] ] | \n\t["
256      + StartupOption.UPGRADE.getName() + 
257        " [" + StartupOption.CLUSTERID.getName() + " cid]" +
258        " [" + StartupOption.RENAMERESERVED.getName() + "<k-v pairs>] ] | \n\t["
259      + StartupOption.UPGRADEONLY.getName() + 
260        " [" + StartupOption.CLUSTERID.getName() + " cid]" +
261        " [" + StartupOption.RENAMERESERVED.getName() + "<k-v pairs>] ] | \n\t["
262      + StartupOption.ROLLBACK.getName() + "] | \n\t["
263      + StartupOption.ROLLINGUPGRADE.getName() + " "
264      + RollingUpgradeStartupOption.getAllOptionString() + " ] | \n\t["
265      + StartupOption.FINALIZE.getName() + "] | \n\t["
266      + StartupOption.IMPORT.getName() + "] | \n\t["
267      + StartupOption.INITIALIZESHAREDEDITS.getName() + "] | \n\t["
268      + StartupOption.BOOTSTRAPSTANDBY.getName() + "] | \n\t["
269      + StartupOption.RECOVER.getName() + " [ "
270      + StartupOption.FORCE.getName() + "] ] | \n\t["
271      + StartupOption.METADATAVERSION.getName() + " ] "
272      + " ]";
273
274  
275  public long getProtocolVersion(String protocol, 
276                                 long clientVersion) throws IOException {
277    if (protocol.equals(ClientProtocol.class.getName())) {
278      return ClientProtocol.versionID; 
279    } else if (protocol.equals(DatanodeProtocol.class.getName())){
280      return DatanodeProtocol.versionID;
281    } else if (protocol.equals(NamenodeProtocol.class.getName())){
282      return NamenodeProtocol.versionID;
283    } else if (protocol.equals(RefreshAuthorizationPolicyProtocol.class.getName())){
284      return RefreshAuthorizationPolicyProtocol.versionID;
285    } else if (protocol.equals(RefreshUserMappingsProtocol.class.getName())){
286      return RefreshUserMappingsProtocol.versionID;
287    } else if (protocol.equals(RefreshCallQueueProtocol.class.getName())) {
288      return RefreshCallQueueProtocol.versionID;
289    } else if (protocol.equals(GetUserMappingsProtocol.class.getName())){
290      return GetUserMappingsProtocol.versionID;
291    } else if (protocol.equals(TraceAdminProtocol.class.getName())){
292      return TraceAdminProtocol.versionID;
293    } else {
294      throw new IOException("Unknown protocol to name node: " + protocol);
295    }
296  }
297    
298  public static final int DEFAULT_PORT = 8020;
299  public static final Logger LOG =
300      LoggerFactory.getLogger(NameNode.class.getName());
301  public static final Logger stateChangeLog =
302      LoggerFactory.getLogger("org.apache.hadoop.hdfs.StateChange");
303  public static final Logger blockStateChangeLog =
304      LoggerFactory.getLogger("BlockStateChange");
305  public static final HAState ACTIVE_STATE = new ActiveState();
306  public static final HAState STANDBY_STATE = new StandbyState();
307  
308  protected FSNamesystem namesystem; 
309  protected final Configuration conf;
310  protected final NamenodeRole role;
311  private volatile HAState state;
312  private final boolean haEnabled;
313  private final HAContext haContext;
314  protected final boolean allowStaleStandbyReads;
315  private AtomicBoolean started = new AtomicBoolean(false); 
316
317  
318  /** httpServer */
319  protected NameNodeHttpServer httpServer;
320  private Thread emptier;
321  /** only used for testing purposes  */
322  protected boolean stopRequested = false;
323  /** Registration information of this name-node  */
324  protected NamenodeRegistration nodeRegistration;
325  /** Activated plug-ins. */
326  private List<ServicePlugin> plugins;
327  
328  private NameNodeRpcServer rpcServer;
329
330  private JvmPauseMonitor pauseMonitor;
331  private ObjectName nameNodeStatusBeanName;
332  SpanReceiverHost spanReceiverHost;
333  /**
334   * The namenode address that clients will use to access this namenode
335   * or the name service. For HA configurations using logical URI, it
336   * will be the logical address.
337   */
338  private String clientNamenodeAddress;
339  
340  /** Format a new filesystem.  Destroys any filesystem that may already
341   * exist at this location.  **/
342  public static void format(Configuration conf) throws IOException {
343    format(conf, true, true);
344  }
345
346  static NameNodeMetrics metrics;
347  private static final StartupProgress startupProgress = new StartupProgress();
348  /** Return the {@link FSNamesystem} object.
349   * @return {@link FSNamesystem} object.
350   */
351  public FSNamesystem getNamesystem() {
352    return namesystem;
353  }
354
355  public NamenodeProtocols getRpcServer() {
356    return rpcServer;
357  }
358  
359  static void initMetrics(Configuration conf, NamenodeRole role) {
360    metrics = NameNodeMetrics.create(conf, role);
361  }
362
363  public static NameNodeMetrics getNameNodeMetrics() {
364    return metrics;
365  }
366
367  /**
368   * Returns object used for reporting namenode startup progress.
369   * 
370   * @return StartupProgress for reporting namenode startup progress
371   */
372  public static StartupProgress getStartupProgress() {
373    return startupProgress;
374  }
375
376  /**
377   * Return the service name of the issued delegation token.
378   *
379   * @return The name service id in HA-mode, or the rpc address in non-HA mode
380   */
381  public String getTokenServiceName() {
382    return getClientNamenodeAddress();
383  }
384
385  /**
386   * Set the namenode address that will be used by clients to access this
387   * namenode or name service. This needs to be called before the config
388   * is overriden.
389   */
390  public void setClientNamenodeAddress(Configuration conf) {
391    String nnAddr = conf.get(FS_DEFAULT_NAME_KEY);
392    if (nnAddr == null) {
393      // default fs is not set.
394      clientNamenodeAddress = null;
395      return;
396    }
397
398    LOG.info("{} is {}", FS_DEFAULT_NAME_KEY, nnAddr);
399    URI nnUri = URI.create(nnAddr);
400
401    String nnHost = nnUri.getHost();
402    if (nnHost == null) {
403      clientNamenodeAddress = null;
404      return;
405    }
406
407    if (DFSUtil.getNameServiceIds(conf).contains(nnHost)) {
408      // host name is logical
409      clientNamenodeAddress = nnHost;
410    } else if (nnUri.getPort() > 0) {
411      // physical address with a valid port
412      clientNamenodeAddress = nnUri.getAuthority();
413    } else {
414      // the port is missing or 0. Figure out real bind address later.
415      clientNamenodeAddress = null;
416      return;
417    }
418    LOG.info("Clients are to use {} to access"
419        + " this namenode/service.", clientNamenodeAddress );
420  }
421
422  /**
423   * Get the namenode address to be used by clients.
424   * @return nn address
425   */
426  public String getClientNamenodeAddress() {
427    return clientNamenodeAddress;
428  }
429
430  public static InetSocketAddress getAddress(String address) {
431    return NetUtils.createSocketAddr(address, DEFAULT_PORT);
432  }
433  
434  /**
435   * Set the configuration property for the service rpc address
436   * to address
437   */
438  public static void setServiceAddress(Configuration conf,
439                                           String address) {
440    LOG.info("Setting ADDRESS {}", address);
441    conf.set(DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY, address);
442  }
443  
444  /**
445   * Fetches the address for services to use when connecting to namenode
446   * based on the value of fallback returns null if the special
447   * address is not specified or returns the default namenode address
448   * to be used by both clients and services.
449   * Services here are datanodes, backup node, any non client connection
450   */
451  public static InetSocketAddress getServiceAddress(Configuration conf,
452                                                        boolean fallback) {
453    String addr = conf.getTrimmed(DFS_NAMENODE_SERVICE_RPC_ADDRESS_KEY);
454    if (addr == null || addr.isEmpty()) {
455      return fallback ? getAddress(conf) : null;
456    }
457    return getAddress(addr);
458  }
459
460  public static InetSocketAddress getAddress(Configuration conf) {
461    URI filesystemURI = FileSystem.getDefaultUri(conf);
462    return getAddress(filesystemURI);
463  }
464
465
466  /**
467   * @return address of file system
468   */
469  public static InetSocketAddress getAddress(URI filesystemURI) {
470    String authority = filesystemURI.getAuthority();
471    if (authority == null) {
472      throw new IllegalArgumentException(String.format(
473          "Invalid URI for NameNode address (check %s): %s has no authority.",
474          FileSystem.FS_DEFAULT_NAME_KEY, filesystemURI.toString()));
475    }
476    if (!HdfsConstants.HDFS_URI_SCHEME.equalsIgnoreCase(
477        filesystemURI.getScheme())) {
478      throw new IllegalArgumentException(String.format(
479          "Invalid URI for NameNode address (check %s): %s is not of scheme '%s'.",
480          FileSystem.FS_DEFAULT_NAME_KEY, filesystemURI.toString(),
481          HdfsConstants.HDFS_URI_SCHEME));
482    }
483    return getAddress(authority);
484  }
485
486  public static URI getUri(InetSocketAddress namenode) {
487    int port = namenode.getPort();
488    String portString = port == DEFAULT_PORT ? "" : (":"+port);
489    return URI.create(HdfsConstants.HDFS_URI_SCHEME + "://" 
490        + namenode.getHostName()+portString);
491  }
492
493  //
494  // Common NameNode methods implementation for the active name-node role.
495  //
496  public NamenodeRole getRole() {
497    return role;
498  }
499
500  boolean isRole(NamenodeRole that) {
501    return role.equals(that);
502  }
503
504  /**
505   * Given a configuration get the address of the service rpc server
506   * If the service rpc is not configured returns null
507   */
508  protected InetSocketAddress getServiceRpcServerAddress(Configuration conf) {
509    return NameNode.getServiceAddress(conf, false);
510  }
511
512  protected InetSocketAddress getRpcServerAddress(Configuration conf) {
513    return getAddress(conf);
514  }
515  
516  /** Given a configuration get the bind host of the service rpc server
517   *  If the bind host is not configured returns null.
518   */
519  protected String getServiceRpcServerBindHost(Configuration conf) {
520    String addr = conf.getTrimmed(DFS_NAMENODE_SERVICE_RPC_BIND_HOST_KEY);
521    if (addr == null || addr.isEmpty()) {
522      return null;
523    }
524    return addr;
525  }
526
527  /** Given a configuration get the bind host of the client rpc server
528   *  If the bind host is not configured returns null.
529   */
530  protected String getRpcServerBindHost(Configuration conf) {
531    String addr = conf.getTrimmed(DFS_NAMENODE_RPC_BIND_HOST_KEY);
532    if (addr == null || addr.isEmpty()) {
533      return null;
534    }
535    return addr;
536  }
537   
538  /**
539   * Modifies the configuration passed to contain the service rpc address setting
540   */
541  protected void setRpcServiceServerAddress(Configuration conf,
542      InetSocketAddress serviceRPCAddress) {
543    setServiceAddress(conf, NetUtils.getHostPortString(serviceRPCAddress));
544  }
545
546  protected void setRpcServerAddress(Configuration conf,
547      InetSocketAddress rpcAddress) {
548    FileSystem.setDefaultUri(conf, getUri(rpcAddress));
549  }
550
551  protected InetSocketAddress getHttpServerAddress(Configuration conf) {
552    return getHttpAddress(conf);
553  }
554
555  /**
556   * HTTP server address for binding the endpoint. This method is
557   * for use by the NameNode and its derivatives. It may return
558   * a different address than the one that should be used by clients to
559   * connect to the NameNode. See
560   * {@link DFSConfigKeys#DFS_NAMENODE_HTTP_BIND_HOST_KEY}
561   *
562   * @param conf
563   * @return
564   */
565  protected InetSocketAddress getHttpServerBindAddress(Configuration conf) {
566    InetSocketAddress bindAddress = getHttpServerAddress(conf);
567
568    // If DFS_NAMENODE_HTTP_BIND_HOST_KEY exists then it overrides the
569    // host name portion of DFS_NAMENODE_HTTP_ADDRESS_KEY.
570    final String bindHost = conf.getTrimmed(DFS_NAMENODE_HTTP_BIND_HOST_KEY);
571    if (bindHost != null && !bindHost.isEmpty()) {
572      bindAddress = new InetSocketAddress(bindHost, bindAddress.getPort());
573    }
574
575    return bindAddress;
576  }
577
578  /** @return the NameNode HTTP address. */
579  public static InetSocketAddress getHttpAddress(Configuration conf) {
580    return  NetUtils.createSocketAddr(
581        conf.getTrimmed(DFS_NAMENODE_HTTP_ADDRESS_KEY, DFS_NAMENODE_HTTP_ADDRESS_DEFAULT));
582  }
583
584  protected void loadNamesystem(Configuration conf) throws IOException {
585    this.namesystem = FSNamesystem.loadFromDisk(conf);
586  }
587
588  NamenodeRegistration getRegistration() {
589    return nodeRegistration;
590  }
591
592  NamenodeRegistration setRegistration() {
593    nodeRegistration = new NamenodeRegistration(
594        NetUtils.getHostPortString(rpcServer.getRpcAddress()),
595        NetUtils.getHostPortString(getHttpAddress()),
596        getFSImage().getStorage(), getRole());
597    return nodeRegistration;
598  }
599
600  /* optimize ugi lookup for RPC operations to avoid a trip through
601   * UGI.getCurrentUser which is synch'ed
602   */
603  public static UserGroupInformation getRemoteUser() throws IOException {
604    UserGroupInformation ugi = Server.getRemoteUser();
605    return (ugi != null) ? ugi : UserGroupInformation.getCurrentUser();
606  }
607
608
609  /**
610   * Login as the configured user for the NameNode.
611   */
612  void loginAsNameNodeUser(Configuration conf) throws IOException {
613    InetSocketAddress socAddr = getRpcServerAddress(conf);
614    SecurityUtil.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY,
615        DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, socAddr.getHostName());
616  }
617  
618  /**
619   * Initialize name-node.
620   * 
621   * @param conf the configuration
622   */
623  protected void initialize(Configuration conf) throws IOException {
624    if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) {
625      String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY);
626      if (intervals != null) {
627        conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS,
628          intervals);
629      }
630    }
631
632    UserGroupInformation.setConfiguration(conf);
633    loginAsNameNodeUser(conf);
634
635    NameNode.initMetrics(conf, this.getRole());
636    StartupProgressMetrics.register(startupProgress);
637
638    if (NamenodeRole.NAMENODE == role) {
639      startHttpServer(conf);
640    }
641
642    this.spanReceiverHost =
643      SpanReceiverHost.get(conf, DFSConfigKeys.DFS_SERVER_HTRACE_PREFIX);
644
645    loadNamesystem(conf);
646
647    rpcServer = createRpcServer(conf);
648    if (clientNamenodeAddress == null) {
649      // This is expected for MiniDFSCluster. Set it now using 
650      // the RPC server's bind address.
651      clientNamenodeAddress = 
652          NetUtils.getHostPortString(rpcServer.getRpcAddress());
653      LOG.info("Clients are to use " + clientNamenodeAddress + " to access"
654          + " this namenode/service.");
655    }
656    if (NamenodeRole.NAMENODE == role) {
657      httpServer.setNameNodeAddress(getNameNodeAddress());
658      httpServer.setFSImage(getFSImage());
659    }
660    
661    pauseMonitor = new JvmPauseMonitor(conf);
662    pauseMonitor.start();
663    metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
664    
665    startCommonServices(conf);
666  }
667  
668  /**
669   * Create the RPC server implementation. Used as an extension point for the
670   * BackupNode.
671   */
672  protected NameNodeRpcServer createRpcServer(Configuration conf)
673      throws IOException {
674    return new NameNodeRpcServer(conf, this);
675  }
676
677  /** Start the services common to active and standby states */
678  private void startCommonServices(Configuration conf) throws IOException {
679    namesystem.startCommonServices(conf, haContext);
680    registerNNSMXBean();
681    if (NamenodeRole.NAMENODE != role) {
682      startHttpServer(conf);
683      httpServer.setNameNodeAddress(getNameNodeAddress());
684      httpServer.setFSImage(getFSImage());
685    }
686    rpcServer.start();
687    try {
688      plugins = conf.getInstances(DFS_NAMENODE_PLUGINS_KEY,
689          ServicePlugin.class);
690    } catch (RuntimeException e) {
691      String pluginsValue = conf.get(DFS_NAMENODE_PLUGINS_KEY);
692      LOG.error("Unable to load NameNode plugins. Specified list of plugins: " +
693          pluginsValue, e);
694      throw e;
695    }
696    for (ServicePlugin p: plugins) {
697      try {
698        p.start(this);
699      } catch (Throwable t) {
700        LOG.warn("ServicePlugin " + p + " could not be started", t);
701      }
702    }
703    LOG.info(getRole() + " RPC up at: " + rpcServer.getRpcAddress());
704    if (rpcServer.getServiceRpcAddress() != null) {
705      LOG.info(getRole() + " service RPC up at: "
706          + rpcServer.getServiceRpcAddress());
707    }
708  }
709  
710  private void stopCommonServices() {
711    if(rpcServer != null) rpcServer.stop();
712    if(namesystem != null) namesystem.close();
713    if (pauseMonitor != null) pauseMonitor.stop();
714    if (plugins != null) {
715      for (ServicePlugin p : plugins) {
716        try {
717          p.stop();
718        } catch (Throwable t) {
719          LOG.warn("ServicePlugin " + p + " could not be stopped", t);
720        }
721      }
722    }   
723    stopHttpServer();
724  }
725  
726  private void startTrashEmptier(final Configuration conf) throws IOException {
727    long trashInterval =
728        conf.getLong(FS_TRASH_INTERVAL_KEY, FS_TRASH_INTERVAL_DEFAULT);
729    if (trashInterval == 0) {
730      return;
731    } else if (trashInterval < 0) {
732      throw new IOException("Cannot start trash emptier with negative interval."
733          + " Set " + FS_TRASH_INTERVAL_KEY + " to a positive value.");
734    }
735    
736    // This may be called from the transitionToActive code path, in which
737    // case the current user is the administrator, not the NN. The trash
738    // emptier needs to run as the NN. See HDFS-3972.
739    FileSystem fs = SecurityUtil.doAsLoginUser(
740        new PrivilegedExceptionAction<FileSystem>() {
741          @Override
742          public FileSystem run() throws IOException {
743            return FileSystem.get(conf);
744          }
745        });
746    this.emptier = new Thread(new Trash(fs, conf).getEmptier(), "Trash Emptier");
747    this.emptier.setDaemon(true);
748    this.emptier.start();
749  }
750  
751  private void stopTrashEmptier() {
752    if (this.emptier != null) {
753      emptier.interrupt();
754      emptier = null;
755    }
756  }
757  
758  private void startHttpServer(final Configuration conf) throws IOException {
759    httpServer = new NameNodeHttpServer(conf, this, getHttpServerBindAddress(conf));
760    httpServer.start();
761    httpServer.setStartupProgress(startupProgress);
762  }
763  
764  private void stopHttpServer() {
765    try {
766      if (httpServer != null) httpServer.stop();
767    } catch (Exception e) {
768      LOG.error("Exception while stopping httpserver", e);
769    }
770  }
771
772  /**
773   * Start NameNode.
774   * <p>
775   * The name-node can be started with one of the following startup options:
776   * <ul> 
777   * <li>{@link StartupOption#REGULAR REGULAR} - normal name node startup</li>
778   * <li>{@link StartupOption#FORMAT FORMAT} - format name node</li>
779   * <li>{@link StartupOption#BACKUP BACKUP} - start backup node</li>
780   * <li>{@link StartupOption#CHECKPOINT CHECKPOINT} - start checkpoint node</li>
781   * <li>{@link StartupOption#UPGRADE UPGRADE} - start the cluster  
782   * <li>{@link StartupOption#UPGRADEONLY UPGRADEONLY} - upgrade the cluster  
783   * upgrade and create a snapshot of the current file system state</li> 
784   * <li>{@link StartupOption#RECOVER RECOVERY} - recover name node
785   * metadata</li>
786   * <li>{@link StartupOption#ROLLBACK ROLLBACK} - roll the  
787   *            cluster back to the previous state</li>
788   * <li>{@link StartupOption#FINALIZE FINALIZE} - finalize 
789   *            previous upgrade</li>
790   * <li>{@link StartupOption#IMPORT IMPORT} - import checkpoint</li>
791   * </ul>
792   * The option is passed via configuration field: 
793   * <tt>dfs.namenode.startup</tt>
794   * 
795   * The conf will be modified to reflect the actual ports on which 
796   * the NameNode is up and running if the user passes the port as
797   * <code>zero</code> in the conf.
798   * 
799   * @param conf  confirguration
800   * @throws IOException
801   */
802  public NameNode(Configuration conf) throws IOException {
803    this(conf, NamenodeRole.NAMENODE);
804  }
805
806  protected NameNode(Configuration conf, NamenodeRole role) 
807      throws IOException { 
808    this.conf = conf;
809    this.role = role;
810    setClientNamenodeAddress(conf);
811    String nsId = getNameServiceId(conf);
812    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
813    this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
814    state = createHAState(getStartupOption(conf));
815    this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
816    this.haContext = createHAContext();
817    try {
818      initializeGenericKeys(conf, nsId, namenodeId);
819      initialize(conf);
820      try {
821        haContext.writeLock();
822        state.prepareToEnterState(haContext);
823        state.enterState(haContext);
824      } finally {
825        haContext.writeUnlock();
826      }
827    } catch (IOException e) {
828      this.stop();
829      throw e;
830    } catch (HadoopIllegalArgumentException e) {
831      this.stop();
832      throw e;
833    }
834    this.started.set(true);
835  }
836
837  protected HAState createHAState(StartupOption startOpt) {
838    if (!haEnabled || startOpt == StartupOption.UPGRADE 
839        || startOpt == StartupOption.UPGRADEONLY) {
840      return ACTIVE_STATE;
841    } else {
842      return STANDBY_STATE;
843    }
844  }
845
846  protected HAContext createHAContext() {
847    return new NameNodeHAContext();
848  }
849
850  /**
851   * Wait for service to finish.
852   * (Normally, it runs forever.)
853   */
854  public void join() {
855    try {
856      rpcServer.join();
857    } catch (InterruptedException ie) {
858      LOG.info("Caught interrupted exception ", ie);
859    }
860  }
861
862  /**
863   * Stop all NameNode threads and wait for all to finish.
864   */
865  public void stop() {
866    synchronized(this) {
867      if (stopRequested)
868        return;
869      stopRequested = true;
870    }
871    try {
872      if (state != null) {
873        state.exitState(haContext);
874      }
875    } catch (ServiceFailedException e) {
876      LOG.warn("Encountered exception while exiting state ", e);
877    } finally {
878      stopCommonServices();
879      if (metrics != null) {
880        metrics.shutdown();
881      }
882      if (namesystem != null) {
883        namesystem.shutdown();
884      }
885      if (nameNodeStatusBeanName != null) {
886        MBeans.unregister(nameNodeStatusBeanName);
887        nameNodeStatusBeanName = null;
888      }
889      if (this.spanReceiverHost != null) {
890        this.spanReceiverHost.closeReceivers();
891      }
892    }
893  }
894
895  synchronized boolean isStopRequested() {
896    return stopRequested;
897  }
898
899  /**
900   * Is the cluster currently in safe mode?
901   */
902  public boolean isInSafeMode() {
903    return namesystem.isInSafeMode();
904  }
905    
906  /** get FSImage */
907  @VisibleForTesting
908  public FSImage getFSImage() {
909    return namesystem.getFSImage();
910  }
911
912  /**
913   * @return NameNode RPC address
914   */
915  public InetSocketAddress getNameNodeAddress() {
916    return rpcServer.getRpcAddress();
917  }
918
919  /**
920   * @return NameNode RPC address in "host:port" string form
921   */
922  public String getNameNodeAddressHostPortString() {
923    return NetUtils.getHostPortString(rpcServer.getRpcAddress());
924  }
925
926  /**
927   * @return NameNode service RPC address if configured, the
928   *    NameNode RPC address otherwise
929   */
930  public InetSocketAddress getServiceRpcAddress() {
931    final InetSocketAddress serviceAddr = rpcServer.getServiceRpcAddress();
932    return serviceAddr == null ? rpcServer.getRpcAddress() : serviceAddr;
933  }
934
935  /**
936   * @return NameNode HTTP address, used by the Web UI, image transfer,
937   *    and HTTP-based file system clients like Hftp and WebHDFS
938   */
939  public InetSocketAddress getHttpAddress() {
940    return httpServer.getHttpAddress();
941  }
942
943  /**
944   * @return NameNode HTTPS address, used by the Web UI, image transfer,
945   *    and HTTP-based file system clients like Hftp and WebHDFS
946   */
947  public InetSocketAddress getHttpsAddress() {
948    return httpServer.getHttpsAddress();
949  }
950
951  /**
952   * Verify that configured directories exist, then
953   * Interactively confirm that formatting is desired 
954   * for each existing directory and format them.
955   * 
956   * @param conf configuration to use
957   * @param force if true, format regardless of whether dirs exist
958   * @return true if formatting was aborted, false otherwise
959   * @throws IOException
960   */
961  private static boolean format(Configuration conf, boolean force,
962      boolean isInteractive) throws IOException {
963    String nsId = DFSUtil.getNamenodeNameServiceId(conf);
964    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
965    initializeGenericKeys(conf, nsId, namenodeId);
966    checkAllowFormat(conf);
967
968    if (UserGroupInformation.isSecurityEnabled()) {
969      InetSocketAddress socAddr = getAddress(conf);
970      SecurityUtil.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY,
971          DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, socAddr.getHostName());
972    }
973    
974    Collection<URI> nameDirsToFormat = FSNamesystem.getNamespaceDirs(conf);
975    List<URI> sharedDirs = FSNamesystem.getSharedEditsDirs(conf);
976    List<URI> dirsToPrompt = new ArrayList<URI>();
977    dirsToPrompt.addAll(nameDirsToFormat);
978    dirsToPrompt.addAll(sharedDirs);
979    List<URI> editDirsToFormat = 
980                 FSNamesystem.getNamespaceEditsDirs(conf);
981
982    // if clusterID is not provided - see if you can find the current one
983    String clusterId = StartupOption.FORMAT.getClusterId();
984    if(clusterId == null || clusterId.equals("")) {
985      //Generate a new cluster id
986      clusterId = NNStorage.newClusterID();
987    }
988    System.out.println("Formatting using clusterid: " + clusterId);
989    
990    FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
991    try {
992      FSNamesystem fsn = new FSNamesystem(conf, fsImage);
993      fsImage.getEditLog().initJournalsForWrite();
994
995      if (!fsImage.confirmFormat(force, isInteractive)) {
996        return true; // aborted
997      }
998
999      fsImage.format(fsn, clusterId);
1000    } catch (IOException ioe) {
1001      LOG.warn("Encountered exception during format: ", ioe);
1002      fsImage.close();
1003      throw ioe;
1004    }
1005    return false;
1006  }
1007
1008  public static void checkAllowFormat(Configuration conf) throws IOException {
1009    if (!conf.getBoolean(DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY, 
1010        DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_DEFAULT)) {
1011      throw new IOException("The option " + DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY
1012                + " is set to false for this filesystem, so it "
1013                + "cannot be formatted. You will need to set "
1014                + DFS_NAMENODE_SUPPORT_ALLOW_FORMAT_KEY +" parameter "
1015                + "to true in order to format this filesystem");
1016    }
1017  }
1018  
1019  @VisibleForTesting
1020  public static boolean initializeSharedEdits(Configuration conf) throws IOException {
1021    return initializeSharedEdits(conf, true);
1022  }
1023  
1024  @VisibleForTesting
1025  public static boolean initializeSharedEdits(Configuration conf,
1026      boolean force) throws IOException {
1027    return initializeSharedEdits(conf, force, false);
1028  }
1029
1030  /**
1031   * Clone the supplied configuration but remove the shared edits dirs.
1032   *
1033   * @param conf Supplies the original configuration.
1034   * @return Cloned configuration without the shared edit dirs.
1035   * @throws IOException on failure to generate the configuration.
1036   */
1037  private static Configuration getConfigurationWithoutSharedEdits(
1038      Configuration conf)
1039      throws IOException {
1040    List<URI> editsDirs = FSNamesystem.getNamespaceEditsDirs(conf, false);
1041    String editsDirsString = Joiner.on(",").join(editsDirs);
1042
1043    Configuration confWithoutShared = new Configuration(conf);
1044    confWithoutShared.unset(DFSConfigKeys.DFS_NAMENODE_SHARED_EDITS_DIR_KEY);
1045    confWithoutShared.setStrings(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY,
1046        editsDirsString);
1047    return confWithoutShared;
1048  }
1049
1050  /**
1051   * Format a new shared edits dir and copy in enough edit log segments so that
1052   * the standby NN can start up.
1053   * 
1054   * @param conf configuration
1055   * @param force format regardless of whether or not the shared edits dir exists
1056   * @param interactive prompt the user when a dir exists
1057   * @return true if the command aborts, false otherwise
1058   */
1059  private static boolean initializeSharedEdits(Configuration conf,
1060      boolean force, boolean interactive) throws IOException {
1061    String nsId = DFSUtil.getNamenodeNameServiceId(conf);
1062    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
1063    initializeGenericKeys(conf, nsId, namenodeId);
1064    
1065    if (conf.get(DFSConfigKeys.DFS_NAMENODE_SHARED_EDITS_DIR_KEY) == null) {
1066      LOG.error("No shared edits directory configured for namespace " +
1067          nsId + " namenode " + namenodeId);
1068      return false;
1069    }
1070
1071    if (UserGroupInformation.isSecurityEnabled()) {
1072      InetSocketAddress socAddr = getAddress(conf);
1073      SecurityUtil.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY,
1074          DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, socAddr.getHostName());
1075    }
1076
1077    NNStorage existingStorage = null;
1078    FSImage sharedEditsImage = null;
1079    try {
1080      FSNamesystem fsns =
1081          FSNamesystem.loadFromDisk(getConfigurationWithoutSharedEdits(conf));
1082      
1083      existingStorage = fsns.getFSImage().getStorage();
1084      NamespaceInfo nsInfo = existingStorage.getNamespaceInfo();
1085      
1086      List<URI> sharedEditsDirs = FSNamesystem.getSharedEditsDirs(conf);
1087      
1088      sharedEditsImage = new FSImage(conf,
1089          Lists.<URI>newArrayList(),
1090          sharedEditsDirs);
1091      sharedEditsImage.getEditLog().initJournalsForWrite();
1092      
1093      if (!sharedEditsImage.confirmFormat(force, interactive)) {
1094        return true; // abort
1095      }
1096      
1097      NNStorage newSharedStorage = sharedEditsImage.getStorage();
1098      // Call Storage.format instead of FSImage.format here, since we don't
1099      // actually want to save a checkpoint - just prime the dirs with
1100      // the existing namespace info
1101      newSharedStorage.format(nsInfo);
1102      sharedEditsImage.getEditLog().formatNonFileJournals(nsInfo);
1103
1104      // Need to make sure the edit log segments are in good shape to initialize
1105      // the shared edits dir.
1106      fsns.getFSImage().getEditLog().close();
1107      fsns.getFSImage().getEditLog().initJournalsForWrite();
1108      fsns.getFSImage().getEditLog().recoverUnclosedStreams();
1109
1110      copyEditLogSegmentsToSharedDir(fsns, sharedEditsDirs, newSharedStorage,
1111          conf);
1112    } catch (IOException ioe) {
1113      LOG.error("Could not initialize shared edits dir", ioe);
1114      return true; // aborted
1115    } finally {
1116      if (sharedEditsImage != null) {
1117        try {
1118          sharedEditsImage.close();
1119        }  catch (IOException ioe) {
1120          LOG.warn("Could not close sharedEditsImage", ioe);
1121        }
1122      }
1123      // Have to unlock storage explicitly for the case when we're running in a
1124      // unit test, which runs in the same JVM as NNs.
1125      if (existingStorage != null) {
1126        try {
1127          existingStorage.unlockAll();
1128        } catch (IOException ioe) {
1129          LOG.warn("Could not unlock storage directories", ioe);
1130          return true; // aborted
1131        }
1132      }
1133    }
1134    return false; // did not abort
1135  }
1136
1137  private static void copyEditLogSegmentsToSharedDir(FSNamesystem fsns,
1138      Collection<URI> sharedEditsDirs, NNStorage newSharedStorage,
1139      Configuration conf) throws IOException {
1140    Preconditions.checkArgument(!sharedEditsDirs.isEmpty(),
1141        "No shared edits specified");
1142    // Copy edit log segments into the new shared edits dir.
1143    List<URI> sharedEditsUris = new ArrayList<URI>(sharedEditsDirs);
1144    FSEditLog newSharedEditLog = new FSEditLog(conf, newSharedStorage,
1145        sharedEditsUris);
1146    newSharedEditLog.initJournalsForWrite();
1147    newSharedEditLog.recoverUnclosedStreams();
1148    
1149    FSEditLog sourceEditLog = fsns.getFSImage().editLog;
1150    
1151    long fromTxId = fsns.getFSImage().getMostRecentCheckpointTxId();
1152    
1153    Collection<EditLogInputStream> streams = null;
1154    try {
1155      streams = sourceEditLog.selectInputStreams(fromTxId + 1, 0);
1156
1157      // Set the nextTxid to the CheckpointTxId+1
1158      newSharedEditLog.setNextTxId(fromTxId + 1);
1159
1160      // Copy all edits after last CheckpointTxId to shared edits dir
1161      for (EditLogInputStream stream : streams) {
1162        LOG.debug("Beginning to copy stream " + stream + " to shared edits");
1163        FSEditLogOp op;
1164        boolean segmentOpen = false;
1165        while ((op = stream.readOp()) != null) {
1166          if (LOG.isTraceEnabled()) {
1167            LOG.trace("copying op: " + op);
1168          }
1169          if (!segmentOpen) {
1170            newSharedEditLog.startLogSegment(op.txid, false);
1171            segmentOpen = true;
1172          }
1173
1174          newSharedEditLog.logEdit(op);
1175
1176          if (op.opCode == FSEditLogOpCodes.OP_END_LOG_SEGMENT) {
1177            newSharedEditLog.logSync();
1178            newSharedEditLog.endCurrentLogSegment(false);
1179            LOG.debug("ending log segment because of END_LOG_SEGMENT op in "
1180                + stream);
1181            segmentOpen = false;
1182          }
1183        }
1184
1185        if (segmentOpen) {
1186          LOG.debug("ending log segment because of end of stream in " + stream);
1187          newSharedEditLog.logSync();
1188          newSharedEditLog.endCurrentLogSegment(false);
1189          segmentOpen = false;
1190        }
1191      }
1192    } finally {
1193      if (streams != null) {
1194        FSEditLog.closeAllStreams(streams);
1195      }
1196    }
1197  }
1198  
1199  @VisibleForTesting
1200  public static boolean doRollback(Configuration conf,
1201      boolean isConfirmationNeeded) throws IOException {
1202    String nsId = DFSUtil.getNamenodeNameServiceId(conf);
1203    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
1204    initializeGenericKeys(conf, nsId, namenodeId);
1205
1206    FSNamesystem nsys = new FSNamesystem(conf, new FSImage(conf));
1207    System.err.print(
1208        "\"rollBack\" will remove the current state of the file system,\n"
1209        + "returning you to the state prior to initiating your recent.\n"
1210        + "upgrade. This action is permanent and cannot be undone. If you\n"
1211        + "are performing a rollback in an HA environment, you should be\n"
1212        + "certain that no NameNode process is running on any host.");
1213    if (isConfirmationNeeded) {
1214      if (!confirmPrompt("Roll back file system state?")) {
1215        System.err.println("Rollback aborted.");
1216        return true;
1217      }
1218    }
1219    nsys.getFSImage().doRollback(nsys);
1220    return false;
1221  }
1222
1223  private static void printUsage(PrintStream out) {
1224    out.println(USAGE + "\n");
1225  }
1226
1227  @VisibleForTesting
1228  static StartupOption parseArguments(String args[]) {
1229    int argsLen = (args == null) ? 0 : args.length;
1230    StartupOption startOpt = StartupOption.REGULAR;
1231    for(int i=0; i < argsLen; i++) {
1232      String cmd = args[i];
1233      if (StartupOption.FORMAT.getName().equalsIgnoreCase(cmd)) {
1234        startOpt = StartupOption.FORMAT;
1235        for (i = i + 1; i < argsLen; i++) {
1236          if (args[i].equalsIgnoreCase(StartupOption.CLUSTERID.getName())) {
1237            i++;
1238            if (i >= argsLen) {
1239              // if no cluster id specified, return null
1240              LOG.error("Must specify a valid cluster ID after the "
1241                  + StartupOption.CLUSTERID.getName() + " flag");
1242              return null;
1243            }
1244            String clusterId = args[i];
1245            // Make sure an id is specified and not another flag
1246            if (clusterId.isEmpty() ||
1247                clusterId.equalsIgnoreCase(StartupOption.FORCE.getName()) ||
1248                clusterId.equalsIgnoreCase(
1249                    StartupOption.NONINTERACTIVE.getName())) {
1250              LOG.error("Must specify a valid cluster ID after the "
1251                  + StartupOption.CLUSTERID.getName() + " flag");
1252              return null;
1253            }
1254            startOpt.setClusterId(clusterId);
1255          }
1256
1257          if (args[i].equalsIgnoreCase(StartupOption.FORCE.getName())) {
1258            startOpt.setForceFormat(true);
1259          }
1260
1261          if (args[i].equalsIgnoreCase(StartupOption.NONINTERACTIVE.getName())) {
1262            startOpt.setInteractiveFormat(false);
1263          }
1264        }
1265      } else if (StartupOption.GENCLUSTERID.getName().equalsIgnoreCase(cmd)) {
1266        startOpt = StartupOption.GENCLUSTERID;
1267      } else if (StartupOption.REGULAR.getName().equalsIgnoreCase(cmd)) {
1268        startOpt = StartupOption.REGULAR;
1269      } else if (StartupOption.BACKUP.getName().equalsIgnoreCase(cmd)) {
1270        startOpt = StartupOption.BACKUP;
1271      } else if (StartupOption.CHECKPOINT.getName().equalsIgnoreCase(cmd)) {
1272        startOpt = StartupOption.CHECKPOINT;
1273      } else if (StartupOption.UPGRADE.getName().equalsIgnoreCase(cmd)
1274          || StartupOption.UPGRADEONLY.getName().equalsIgnoreCase(cmd)) {
1275        startOpt = StartupOption.UPGRADE.getName().equalsIgnoreCase(cmd) ? 
1276            StartupOption.UPGRADE : StartupOption.UPGRADEONLY;
1277        /* Can be followed by CLUSTERID with a required parameter or
1278         * RENAMERESERVED with an optional parameter
1279         */
1280        while (i + 1 < argsLen) {
1281          String flag = args[i + 1];
1282          if (flag.equalsIgnoreCase(StartupOption.CLUSTERID.getName())) {
1283            if (i + 2 < argsLen) {
1284              i += 2;
1285              startOpt.setClusterId(args[i]);
1286            } else {
1287              LOG.error("Must specify a valid cluster ID after the "
1288                  + StartupOption.CLUSTERID.getName() + " flag");
1289              return null;
1290            }
1291          } else if (flag.equalsIgnoreCase(StartupOption.RENAMERESERVED
1292              .getName())) {
1293            if (i + 2 < argsLen) {
1294              FSImageFormat.setRenameReservedPairs(args[i + 2]);
1295              i += 2;
1296            } else {
1297              FSImageFormat.useDefaultRenameReservedPairs();
1298              i += 1;
1299            }
1300          } else {
1301            LOG.error("Unknown upgrade flag " + flag);
1302            return null;
1303          }
1304        }
1305      } else if (StartupOption.ROLLINGUPGRADE.getName().equalsIgnoreCase(cmd)) {
1306        startOpt = StartupOption.ROLLINGUPGRADE;
1307        ++i;
1308        if (i >= argsLen) {
1309          LOG.error("Must specify a rolling upgrade startup option "
1310              + RollingUpgradeStartupOption.getAllOptionString());
1311          return null;
1312        }
1313        startOpt.setRollingUpgradeStartupOption(args[i]);
1314      } else if (StartupOption.ROLLBACK.getName().equalsIgnoreCase(cmd)) {
1315        startOpt = StartupOption.ROLLBACK;
1316      } else if (StartupOption.FINALIZE.getName().equalsIgnoreCase(cmd)) {
1317        startOpt = StartupOption.FINALIZE;
1318      } else if (StartupOption.IMPORT.getName().equalsIgnoreCase(cmd)) {
1319        startOpt = StartupOption.IMPORT;
1320      } else if (StartupOption.BOOTSTRAPSTANDBY.getName().equalsIgnoreCase(cmd)) {
1321        startOpt = StartupOption.BOOTSTRAPSTANDBY;
1322        return startOpt;
1323      } else if (StartupOption.INITIALIZESHAREDEDITS.getName().equalsIgnoreCase(cmd)) {
1324        startOpt = StartupOption.INITIALIZESHAREDEDITS;
1325        for (i = i + 1 ; i < argsLen; i++) {
1326          if (StartupOption.NONINTERACTIVE.getName().equals(args[i])) {
1327            startOpt.setInteractiveFormat(false);
1328          } else if (StartupOption.FORCE.getName().equals(args[i])) {
1329            startOpt.setForceFormat(true);
1330          } else {
1331            LOG.error("Invalid argument: " + args[i]);
1332            return null;
1333          }
1334        }
1335        return startOpt;
1336      } else if (StartupOption.RECOVER.getName().equalsIgnoreCase(cmd)) {
1337        if (startOpt != StartupOption.REGULAR) {
1338          throw new RuntimeException("Can't combine -recover with " +
1339              "other startup options.");
1340        }
1341        startOpt = StartupOption.RECOVER;
1342        while (++i < argsLen) {
1343          if (args[i].equalsIgnoreCase(
1344                StartupOption.FORCE.getName())) {
1345            startOpt.setForce(MetaRecoveryContext.FORCE_FIRST_CHOICE);
1346          } else {
1347            throw new RuntimeException("Error parsing recovery options: " + 
1348              "can't understand option \"" + args[i] + "\"");
1349          }
1350        }
1351      } else if (StartupOption.METADATAVERSION.getName().equalsIgnoreCase(cmd)) {
1352        startOpt = StartupOption.METADATAVERSION;
1353      } else {
1354        return null;
1355      }
1356    }
1357    return startOpt;
1358  }
1359
1360  private static void setStartupOption(Configuration conf, StartupOption opt) {
1361    conf.set(DFS_NAMENODE_STARTUP_KEY, opt.name());
1362  }
1363
1364  static StartupOption getStartupOption(Configuration conf) {
1365    return StartupOption.valueOf(conf.get(DFS_NAMENODE_STARTUP_KEY,
1366                                          StartupOption.REGULAR.toString()));
1367  }
1368
1369  private static void doRecovery(StartupOption startOpt, Configuration conf)
1370      throws IOException {
1371    String nsId = DFSUtil.getNamenodeNameServiceId(conf);
1372    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
1373    initializeGenericKeys(conf, nsId, namenodeId);
1374    if (startOpt.getForce() < MetaRecoveryContext.FORCE_ALL) {
1375      if (!confirmPrompt("You have selected Metadata Recovery mode.  " +
1376          "This mode is intended to recover lost metadata on a corrupt " +
1377          "filesystem.  Metadata recovery mode often permanently deletes " +
1378          "data from your HDFS filesystem.  Please back up your edit log " +
1379          "and fsimage before trying this!\n\n" +
1380          "Are you ready to proceed? (Y/N)\n")) {
1381        System.err.println("Recovery aborted at user request.\n");
1382        return;
1383      }
1384    }
1385    MetaRecoveryContext.LOG.info("starting recovery...");
1386    UserGroupInformation.setConfiguration(conf);
1387    NameNode.initMetrics(conf, startOpt.toNodeRole());
1388    FSNamesystem fsn = null;
1389    try {
1390      fsn = FSNamesystem.loadFromDisk(conf);
1391      fsn.getFSImage().saveNamespace(fsn);
1392      MetaRecoveryContext.LOG.info("RECOVERY COMPLETE");
1393    } catch (IOException e) {
1394      MetaRecoveryContext.LOG.info("RECOVERY FAILED: caught exception", e);
1395      throw e;
1396    } catch (RuntimeException e) {
1397      MetaRecoveryContext.LOG.info("RECOVERY FAILED: caught exception", e);
1398      throw e;
1399    } finally {
1400      if (fsn != null)
1401        fsn.close();
1402    }
1403  }
1404
1405  /**
1406   * Verify that configured directories exist, then print the metadata versions
1407   * of the software and the image.
1408   *
1409   * @param conf configuration to use
1410   * @throws IOException
1411   */
1412  private static boolean printMetadataVersion(Configuration conf)
1413    throws IOException {
1414    final String nsId = DFSUtil.getNamenodeNameServiceId(conf);
1415    final String namenodeId = HAUtil.getNameNodeId(conf, nsId);
1416    NameNode.initializeGenericKeys(conf, nsId, namenodeId);
1417    final FSImage fsImage = new FSImage(conf);
1418    final FSNamesystem fs = new FSNamesystem(conf, fsImage, false);
1419    return fsImage.recoverTransitionRead(
1420      StartupOption.METADATAVERSION, fs, null);
1421  }
1422
1423  public static NameNode createNameNode(String argv[], Configuration conf)
1424      throws IOException {
1425    LOG.info("createNameNode " + Arrays.asList(argv));
1426    if (conf == null)
1427      conf = new HdfsConfiguration();
1428    // Parse out some generic args into Configuration.
1429    GenericOptionsParser hParser = new GenericOptionsParser(conf, argv);
1430    argv = hParser.getRemainingArgs();
1431    // Parse the rest, NN specific args.
1432    StartupOption startOpt = parseArguments(argv);
1433    if (startOpt == null) {
1434      printUsage(System.err);
1435      return null;
1436    }
1437    setStartupOption(conf, startOpt);
1438
1439    switch (startOpt) {
1440      case FORMAT: {
1441        boolean aborted = format(conf, startOpt.getForceFormat(),
1442            startOpt.getInteractiveFormat());
1443        terminate(aborted ? 1 : 0);
1444        return null; // avoid javac warning
1445      }
1446      case GENCLUSTERID: {
1447        System.err.println("Generating new cluster id:");
1448        System.out.println(NNStorage.newClusterID());
1449        terminate(0);
1450        return null;
1451      }
1452      case FINALIZE: {
1453        System.err.println("Use of the argument '" + StartupOption.FINALIZE +
1454            "' is no longer supported. To finalize an upgrade, start the NN " +
1455            " and then run `hdfs dfsadmin -finalizeUpgrade'");
1456        terminate(1);
1457        return null; // avoid javac warning
1458      }
1459      case ROLLBACK: {
1460        boolean aborted = doRollback(conf, true);
1461        terminate(aborted ? 1 : 0);
1462        return null; // avoid warning
1463      }
1464      case BOOTSTRAPSTANDBY: {
1465        String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);
1466        int rc = BootstrapStandby.run(toolArgs, conf);
1467        terminate(rc);
1468        return null; // avoid warning
1469      }
1470      case INITIALIZESHAREDEDITS: {
1471        boolean aborted = initializeSharedEdits(conf,
1472            startOpt.getForceFormat(),
1473            startOpt.getInteractiveFormat());
1474        terminate(aborted ? 1 : 0);
1475        return null; // avoid warning
1476      }
1477      case BACKUP:
1478      case CHECKPOINT: {
1479        NamenodeRole role = startOpt.toNodeRole();
1480        DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
1481        return new BackupNode(conf, role);
1482      }
1483      case RECOVER: {
1484        NameNode.doRecovery(startOpt, conf);
1485        return null;
1486      }
1487      case METADATAVERSION: {
1488        printMetadataVersion(conf);
1489        terminate(0);
1490        return null; // avoid javac warning
1491      }
1492      case UPGRADEONLY: {
1493        DefaultMetricsSystem.initialize("NameNode");
1494        new NameNode(conf);
1495        terminate(0);
1496        return null;
1497      }
1498      default: {
1499        DefaultMetricsSystem.initialize("NameNode");
1500        return new NameNode(conf);
1501      }
1502    }
1503  }
1504
1505  /**
1506   * In federation configuration is set for a set of
1507   * namenode and secondary namenode/backup/checkpointer, which are
1508   * grouped under a logical nameservice ID. The configuration keys specific 
1509   * to them have suffix set to configured nameserviceId.
1510   * 
1511   * This method copies the value from specific key of format key.nameserviceId
1512   * to key, to set up the generic configuration. Once this is done, only
1513   * generic version of the configuration is read in rest of the code, for
1514   * backward compatibility and simpler code changes.
1515   * 
1516   * @param conf
1517   *          Configuration object to lookup specific key and to set the value
1518   *          to the key passed. Note the conf object is modified
1519   * @param nameserviceId name service Id (to distinguish federated NNs)
1520   * @param namenodeId the namenode ID (to distinguish HA NNs)
1521   * @see DFSUtil#setGenericConf(Configuration, String, String, String...)
1522   */
1523  public static void initializeGenericKeys(Configuration conf,
1524      String nameserviceId, String namenodeId) {
1525    if ((nameserviceId != null && !nameserviceId.isEmpty()) || 
1526        (namenodeId != null && !namenodeId.isEmpty())) {
1527      if (nameserviceId != null) {
1528        conf.set(DFS_NAMESERVICE_ID, nameserviceId);
1529      }
1530      if (namenodeId != null) {
1531        conf.set(DFS_HA_NAMENODE_ID_KEY, namenodeId);
1532      }
1533      
1534      DFSUtil.setGenericConf(conf, nameserviceId, namenodeId,
1535          NAMENODE_SPECIFIC_KEYS);
1536      DFSUtil.setGenericConf(conf, nameserviceId, null,
1537          NAMESERVICE_SPECIFIC_KEYS);
1538    }
1539    
1540    // If the RPC address is set use it to (re-)configure the default FS
1541    if (conf.get(DFS_NAMENODE_RPC_ADDRESS_KEY) != null) {
1542      URI defaultUri = URI.create(HdfsConstants.HDFS_URI_SCHEME + "://"
1543          + conf.get(DFS_NAMENODE_RPC_ADDRESS_KEY));
1544      conf.set(FS_DEFAULT_NAME_KEY, defaultUri.toString());
1545      LOG.debug("Setting " + FS_DEFAULT_NAME_KEY + " to " + defaultUri.toString());
1546    }
1547  }
1548    
1549  /** 
1550   * Get the name service Id for the node
1551   * @return name service Id or null if federation is not configured
1552   */
1553  protected String getNameServiceId(Configuration conf) {
1554    return DFSUtil.getNamenodeNameServiceId(conf);
1555  }
1556  
1557  /**
1558   */
1559  public static void main(String argv[]) throws Exception {
1560    if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
1561      System.exit(0);
1562    }
1563
1564    try {
1565      StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
1566      NameNode namenode = createNameNode(argv, null);
1567      if (namenode != null) {
1568        namenode.join();
1569      }
1570    } catch (Throwable e) {
1571      LOG.error("Failed to start namenode.", e);
1572      terminate(1, e);
1573    }
1574  }
1575
1576  synchronized void monitorHealth() 
1577      throws HealthCheckFailedException, AccessControlException {
1578    namesystem.checkSuperuserPrivilege();
1579    if (!haEnabled) {
1580      return; // no-op, if HA is not enabled
1581    }
1582    getNamesystem().checkAvailableResources();
1583    if (!getNamesystem().nameNodeHasResourcesAvailable()) {
1584      throw new HealthCheckFailedException(
1585          "The NameNode has no resources available");
1586    }
1587  }
1588  
1589  synchronized void transitionToActive() 
1590      throws ServiceFailedException, AccessControlException {
1591    namesystem.checkSuperuserPrivilege();
1592    if (!haEnabled) {
1593      throw new ServiceFailedException("HA for namenode is not enabled");
1594    }
1595    state.setState(haContext, ACTIVE_STATE);
1596  }
1597  
1598  synchronized void transitionToStandby() 
1599      throws ServiceFailedException, AccessControlException {
1600    namesystem.checkSuperuserPrivilege();
1601    if (!haEnabled) {
1602      throw new ServiceFailedException("HA for namenode is not enabled");
1603    }
1604    state.setState(haContext, STANDBY_STATE);
1605  }
1606
1607  synchronized HAServiceStatus getServiceStatus()
1608      throws ServiceFailedException, AccessControlException {
1609    namesystem.checkSuperuserPrivilege();
1610    if (!haEnabled) {
1611      throw new ServiceFailedException("HA for namenode is not enabled");
1612    }
1613    if (state == null) {
1614      return new HAServiceStatus(HAServiceState.INITIALIZING);
1615    }
1616    HAServiceState retState = state.getServiceState();
1617    HAServiceStatus ret = new HAServiceStatus(retState);
1618    if (retState == HAServiceState.STANDBY) {
1619      String safemodeTip = namesystem.getSafeModeTip();
1620      if (!safemodeTip.isEmpty()) {
1621        ret.setNotReadyToBecomeActive(
1622            "The NameNode is in safemode. " +
1623            safemodeTip);
1624      } else {
1625        ret.setReadyToBecomeActive();
1626      }
1627    } else if (retState == HAServiceState.ACTIVE) {
1628      ret.setReadyToBecomeActive();
1629    } else {
1630      ret.setNotReadyToBecomeActive("State is " + state);
1631    }
1632    return ret;
1633  }
1634
1635  synchronized HAServiceState getServiceState() {
1636    if (state == null) {
1637      return HAServiceState.INITIALIZING;
1638    }
1639    return state.getServiceState();
1640  }
1641
1642  /**
1643   * Register NameNodeStatusMXBean
1644   */
1645  private void registerNNSMXBean() {
1646    nameNodeStatusBeanName = MBeans.register("NameNode", "NameNodeStatus", this);
1647  }
1648
1649  @Override // NameNodeStatusMXBean
1650  public String getNNRole() {
1651    String roleStr = "";
1652    NamenodeRole role = getRole();
1653    if (null != role) {
1654      roleStr = role.toString();
1655    }
1656    return roleStr;
1657  }
1658
1659  @Override // NameNodeStatusMXBean
1660  public String getState() {
1661    String servStateStr = "";
1662    HAServiceState servState = getServiceState();
1663    if (null != servState) {
1664      servStateStr = servState.toString();
1665    }
1666    return servStateStr;
1667  }
1668
1669  @Override // NameNodeStatusMXBean
1670  public String getHostAndPort() {
1671    return getNameNodeAddressHostPortString();
1672  }
1673
1674  @Override // NameNodeStatusMXBean
1675  public boolean isSecurityEnabled() {
1676    return UserGroupInformation.isSecurityEnabled();
1677  }
1678
1679  @Override // NameNodeStatusMXBean
1680  public long getLastHATransitionTime() {
1681    return state.getLastHATransitionTime();
1682  }
1683
1684  /**
1685   * Shutdown the NN immediately in an ungraceful way. Used when it would be
1686   * unsafe for the NN to continue operating, e.g. during a failed HA state
1687   * transition.
1688   * 
1689   * @param t exception which warrants the shutdown. Printed to the NN log
1690   *          before exit.
1691   * @throws ExitException thrown only for testing.
1692   */
1693  protected synchronized void doImmediateShutdown(Throwable t)
1694      throws ExitException {
1695    String message = "Error encountered requiring NN shutdown. " +
1696        "Shutting down immediately.";
1697    try {
1698      LOG.error(message, t);
1699    } catch (Throwable ignored) {
1700      // This is unlikely to happen, but there's nothing we can do if it does.
1701    }
1702    terminate(1, t);
1703  }
1704  
1705  /**
1706   * Class used to expose {@link NameNode} as context to {@link HAState}
1707   */
1708  protected class NameNodeHAContext implements HAContext {
1709    @Override
1710    public void setState(HAState s) {
1711      state = s;
1712    }
1713
1714    @Override
1715    public HAState getState() {
1716      return state;
1717    }
1718
1719    @Override
1720    public void startActiveServices() throws IOException {
1721      try {
1722        namesystem.startActiveServices();
1723        startTrashEmptier(conf);
1724      } catch (Throwable t) {
1725        doImmediateShutdown(t);
1726      }
1727    }
1728
1729    @Override
1730    public void stopActiveServices() throws IOException {
1731      try {
1732        if (namesystem != null) {
1733          namesystem.stopActiveServices();
1734        }
1735        stopTrashEmptier();
1736      } catch (Throwable t) {
1737        doImmediateShutdown(t);
1738      }
1739    }
1740
1741    @Override
1742    public void startStandbyServices() throws IOException {
1743      try {
1744        namesystem.startStandbyServices(conf);
1745      } catch (Throwable t) {
1746        doImmediateShutdown(t);
1747      }
1748    }
1749
1750    @Override
1751    public void prepareToStopStandbyServices() throws ServiceFailedException {
1752      try {
1753        namesystem.prepareToStopStandbyServices();
1754      } catch (Throwable t) {
1755        doImmediateShutdown(t);
1756      }
1757    }
1758    
1759    @Override
1760    public void stopStandbyServices() throws IOException {
1761      try {
1762        if (namesystem != null) {
1763          namesystem.stopStandbyServices();
1764        }
1765      } catch (Throwable t) {
1766        doImmediateShutdown(t);
1767      }
1768    }
1769    
1770    @Override
1771    public void writeLock() {
1772      namesystem.writeLock();
1773      namesystem.lockRetryCache();
1774    }
1775    
1776    @Override
1777    public void writeUnlock() {
1778      namesystem.unlockRetryCache();
1779      namesystem.writeUnlock();
1780    }
1781    
1782    /** Check if an operation of given category is allowed */
1783    @Override
1784    public void checkOperation(final OperationCategory op)
1785        throws StandbyException {
1786      state.checkOperation(haContext, op);
1787    }
1788    
1789    @Override
1790    public boolean allowStaleReads() {
1791      return allowStaleStandbyReads;
1792    }
1793
1794  }
1795  
1796  public boolean isStandbyState() {
1797    return (state.equals(STANDBY_STATE));
1798  }
1799  
1800  public boolean isActiveState() {
1801    return (state.equals(ACTIVE_STATE));
1802  }
1803
1804  /**
1805   * Returns whether the NameNode is completely started
1806   */
1807  boolean isStarted() {
1808    return this.started.get();
1809  }
1810
1811  /**
1812   * Check that a request to change this node's HA state is valid.
1813   * In particular, verifies that, if auto failover is enabled, non-forced
1814   * requests from the HAAdmin CLI are rejected, and vice versa.
1815   *
1816   * @param req the request to check
1817   * @throws AccessControlException if the request is disallowed
1818   */
1819  void checkHaStateChange(StateChangeRequestInfo req)
1820      throws AccessControlException {
1821    boolean autoHaEnabled = conf.getBoolean(DFS_HA_AUTO_FAILOVER_ENABLED_KEY,
1822        DFS_HA_AUTO_FAILOVER_ENABLED_DEFAULT);
1823    switch (req.getSource()) {
1824    case REQUEST_BY_USER:
1825      if (autoHaEnabled) {
1826        throw new AccessControlException(
1827            "Manual HA control for this NameNode is disallowed, because " +
1828            "automatic HA is enabled.");
1829      }
1830      break;
1831    case REQUEST_BY_USER_FORCED:
1832      if (autoHaEnabled) {
1833        LOG.warn("Allowing manual HA control from " +
1834            Server.getRemoteAddress() +
1835            " even though automatic HA is enabled, because the user " +
1836            "specified the force flag");
1837      }
1838      break;
1839    case REQUEST_BY_ZKFC:
1840      if (!autoHaEnabled) {
1841        throw new AccessControlException(
1842            "Request from ZK failover controller at " +
1843            Server.getRemoteAddress() + " denied since automatic HA " +
1844            "is not enabled"); 
1845      }
1846      break;
1847    }
1848  }
1849}