HDFS-2030. Improve usability of namenode -upgrade command. Contributed by Bharath Mundlapudi.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/hdfs/trunk@1134138 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES.txt b/CHANGES.txt
index b4ed3ea..afbe7ff 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -510,6 +510,9 @@
HDFS-941. The DFS client should cache and reuse open sockets to datanodes
while performing reads. (bc Wong and Todd Lipcon via todd)
+ HDFS-2030. Improve usability of namenode -upgrade command.
+ (Bharath Mundlapudi via suresh)
+
BUG FIXES
HDFS-1449. Fix test failures - ExtendedBlock must return
diff --git a/src/java/org/apache/hadoop/hdfs/protocol/LayoutVersion.java b/src/java/org/apache/hadoop/hdfs/protocol/LayoutVersion.java
index 9efa360..0becfd8 100644
--- a/src/java/org/apache/hadoop/hdfs/protocol/LayoutVersion.java
+++ b/src/java/org/apache/hadoop/hdfs/protocol/LayoutVersion.java
@@ -106,6 +106,30 @@
this.ancestorLV = ancestorLV;
this.description = description;
}
+
+ /**
+ * Accessor method for feature layout version
+ * @return int lv value
+ */
+ public int getLayoutVersion() {
+ return lv;
+ }
+
+ /**
+ * Accessor method for feature ancestor layout version
+ * @return int ancestor LV value
+ */
+ public int getAncestorLayoutVersion() {
+ return ancestorLV;
+ }
+
+ /**
+ * Accessor method for feature description
+ * @return String feature description
+ */
+ public String getDescription() {
+ return description;
+ }
}
// Build layout version and corresponding feature matrix
diff --git a/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java b/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
index d239761..5874c27 100644
--- a/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
+++ b/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
@@ -267,24 +267,9 @@
+ "Please restart NameNode with -upgrade option.");
}
- // Upgrade to federation requires -upgrade -clusterid <clusterID> option
- if (startOpt == StartupOption.UPGRADE &&
- !LayoutVersion.supports(Feature.FEDERATION, layoutVersion)) {
- if (startOpt.getClusterId() == null) {
- throw new IOException(
- "\nFile system image contains an old layout version "
- + layoutVersion + ".\nAn upgrade to version "
- + FSConstants.LAYOUT_VERSION
- + " is required.\nPlease restart NameNode with "
- + "-upgrade -clusterid <clusterID> option.");
- }
- storage.setClusterID(startOpt.getClusterId());
-
- // Create new block pool Id
- storage.setBlockPoolID(storage.newBlockPoolID());
- }
-
- // check whether distributed upgrade is reguired and/or should be continued
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+
+ // check whether distributed upgrade is required and/or should be continued
storage.verifyDistributedUpgradeProgress(startOpt);
// 2. Format unformatted dirs.
diff --git a/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java b/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java
index 3303c03..cef7f01 100644
--- a/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java
+++ b/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java
@@ -932,6 +932,40 @@
LOG.debug("at the end current list of storage dirs:" + lsd);
}
+ /**
+ * Processes the startup options for the clusterid and blockpoolid
+ * for the upgrade.
+ * @param startOpt Startup options
+ * @param layoutVersion Layout version for the upgrade
+ * @throws IOException
+ */
+ void processStartupOptionsForUpgrade(StartupOption startOpt, int layoutVersion)
+ throws IOException {
+ if (startOpt == StartupOption.UPGRADE) {
+ // If upgrade from a release that does not support federation,
+ // if clusterId is provided in the startupOptions use it.
+ // Else generate a new cluster ID
+ if (!LayoutVersion.supports(Feature.FEDERATION, layoutVersion)) {
+ if (startOpt.getClusterId() == null) {
+ startOpt.setClusterId(newClusterID());
+ }
+ setClusterID(startOpt.getClusterId());
+ setBlockPoolID(newBlockPoolID());
+ } else {
+ // Upgrade from one version of federation to another supported
+ // version of federation doesn't require clusterID.
+ // Warn the user if the current clusterid didn't match with the input
+ // clusterid.
+ if (startOpt.getClusterId() != null
+ && !startOpt.getClusterId().equals(getClusterID())) {
+ LOG.warn("Clusterid mismatch - current clusterid: " + getClusterID()
+ + ", Ignoring given clusterid: " + startOpt.getClusterId());
+ }
+ }
+ LOG.info("Using clusterid: " + getClusterID());
+ }
+ }
+
/**
* Generate new clusterID.
*
diff --git a/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java b/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java
new file mode 100644
index 0000000..f501c6a
--- /dev/null
+++ b/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java
@@ -0,0 +1,139 @@
+/**
+ * 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 junit.framework.Assert;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdfs.HdfsConfiguration;
+import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
+import org.apache.hadoop.hdfs.server.common.HdfsConstants.StartupOption;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This class tests various upgrade cases from earlier versions to current
+ * version with and without clusterid.
+ */
+public class TestStartupOptionUpgrade {
+
+ private Configuration conf;
+ private StartupOption startOpt;
+ private int layoutVersion;
+ NNStorage storage;
+
+ @Before
+ public void setUp() throws Exception {
+ conf = new HdfsConfiguration();
+ startOpt = StartupOption.UPGRADE;
+ startOpt.setClusterId(null);
+ storage = new NNStorage(conf);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ conf = null;
+ startOpt = null;
+ }
+
+ /**
+ * Tests the upgrade from version 0.20.204 to Federation version Test without
+ * clusterid the case: -upgrade
+ * Expected to generate clusterid
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testStartupOptUpgradeFrom204() throws Exception {
+ layoutVersion = Feature.RESERVED_REL20_204.getLayoutVersion();
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+ Assert.assertTrue("Clusterid should start with CID", storage.getClusterID()
+ .startsWith("CID"));
+ }
+
+ /**
+ * Tests the upgrade from version 0.22 to Federation version Test with
+ * clusterid case: -upgrade -clusterid <cid>
+ * Expected to reuse user given clusterid
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testStartupOptUpgradeFrom22WithCID() throws Exception {
+ startOpt.setClusterId("cid");
+ layoutVersion = Feature.RESERVED_REL22.getLayoutVersion();
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+ Assert.assertEquals("Clusterid should match with the given clusterid",
+ "cid", storage.getClusterID());
+ }
+
+ /**
+ * Tests the upgrade from one version of Federation to another Federation
+ * version Test without clusterid case: -upgrade
+ * Expected to reuse existing clusterid
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testStartupOptUpgradeFromFederation()
+ throws Exception {
+ // Test assumes clusterid already exists, set the clusterid
+ storage.setClusterID("currentcid");
+ layoutVersion = Feature.FEDERATION.getLayoutVersion();
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+ Assert.assertEquals("Clusterid should match with the existing one",
+ "currentcid", storage.getClusterID());
+ }
+
+ /**
+ * Tests the upgrade from one version of Federation to another Federation
+ * version Test with wrong clusterid case: -upgrade -clusterid <cid>
+ * Expected to reuse existing clusterid and ignore user given clusterid
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testStartupOptUpgradeFromFederationWithWrongCID()
+ throws Exception {
+ startOpt.setClusterId("wrong-cid");
+ storage.setClusterID("currentcid");
+ layoutVersion = Feature.FEDERATION.getLayoutVersion();
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+ Assert.assertEquals("Clusterid should match with the existing one",
+ "currentcid", storage.getClusterID());
+ }
+
+ /**
+ * Tests the upgrade from one version of Federation to another Federation
+ * version Test with correct clusterid case: -upgrade -clusterid <cid>
+ * Expected to reuse existing clusterid and ignore user given clusterid
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testStartupOptUpgradeFromFederationWithCID()
+ throws Exception {
+ startOpt.setClusterId("currentcid");
+ storage.setClusterID("currentcid");
+ layoutVersion = Feature.FEDERATION.getLayoutVersion();
+ storage.processStartupOptionsForUpgrade(startOpt, layoutVersion);
+ Assert.assertEquals("Clusterid should match with the existing one",
+ "currentcid", storage.getClusterID());
+ }
+}
\ No newline at end of file