You are viewing a plain text version of this content. The canonical link for it is here.
Posted to hdfs-commits@hadoop.apache.org by to...@apache.org on 2011/06/10 00:56:43 UTC
svn commit: r1134125 - in /hadoop/hdfs/branches/HDFS-1073: ./
src/java/org/apache/hadoop/hdfs/server/namenode/
src/test/hdfs/org/apache/hadoop/hdfs/
src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/
Author: todd
Date: Thu Jun 9 22:56:43 2011
New Revision: 1134125
URL: http://svn.apache.org/viewvc?rev=1134125&view=rev
Log:
HDFS-2048. Add upgrade tests and fix upgrade from 0.22 with corrupt image. Contributed by Todd Lipcon.
Modified:
hadoop/hdfs/branches/HDFS-1073/CHANGES.HDFS-1073.txt
hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java
hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/TestDFSUpgradeFromImage.java
hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImageTestUtil.java
Modified: hadoop/hdfs/branches/HDFS-1073/CHANGES.HDFS-1073.txt
URL: http://svn.apache.org/viewvc/hadoop/hdfs/branches/HDFS-1073/CHANGES.HDFS-1073.txt?rev=1134125&r1=1134124&r2=1134125&view=diff
==============================================================================
--- hadoop/hdfs/branches/HDFS-1073/CHANGES.HDFS-1073.txt (original)
+++ hadoop/hdfs/branches/HDFS-1073/CHANGES.HDFS-1073.txt Thu Jun 9 22:56:43 2011
@@ -46,3 +46,5 @@ HDFS-2015. Remove checkpointTxId from VE
HDFS-2016. Add infrastructure to remove or archive old and unneeded storage
files within the name directories. (todd)
HDFS-2047. Improve TestNamespace and TestEditLog in HDFS-1073 branch. (todd)
+HDFS-2048. Add upgrade tests and fix upgrade from 0.22 with corrupt image.
+ (todd)
Modified: hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java?rev=1134125&r1=1134124&r2=1134125&view=diff
==============================================================================
--- hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java (original)
+++ hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java Thu Jun 9 22:56:43 2011
@@ -609,7 +609,27 @@ public class FSImage implements Closeabl
File imageFile = loadPlan.getImageFile();
try {
- loadFSImage(imageFile);
+ if (LayoutVersion.supports(Feature.TXID_BASED_LAYOUT,
+ getLayoutVersion())) {
+ // For txid-based layout, we should have a .md5 file
+ // next to the image file
+ loadFSImage(imageFile);
+ } else if (LayoutVersion.supports(Feature.FSIMAGE_CHECKSUM,
+ getLayoutVersion())) {
+ // In 0.22, we have the checksum stored in the VERSION file.
+ String md5 = storage.getDeprecatedProperty(
+ NNStorage.DEPRECATED_MESSAGE_DIGEST_PROPERTY);
+ if (md5 == null) {
+ throw new InconsistentFSStateException(sdForProperties.getRoot(),
+ "Message digest property " +
+ NNStorage.DEPRECATED_MESSAGE_DIGEST_PROPERTY +
+ " not set for storage directory " + sdForProperties.getRoot());
+ }
+ loadFSImage(imageFile, new MD5Hash(md5));
+ } else {
+ // We don't have any record of the md5sum
+ loadFSImage(imageFile, null);
+ }
} catch (IOException ioe) {
throw new IOException("Failed to load image from " + loadPlan.getImageFile(), ioe);
}
@@ -662,6 +682,10 @@ public class FSImage implements Closeabl
*/
void loadFSImage(File imageFile) throws IOException {
MD5Hash expectedMD5 = MD5FileUtils.readStoredMd5ForFile(imageFile);
+ if (expectedMD5 == null) {
+ throw new IOException("No MD5 file found corresponding to image file "
+ + imageFile);
+ }
loadFSImage(imageFile, expectedMD5);
}
Modified: hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java?rev=1134125&r1=1134124&r2=1134125&view=diff
==============================================================================
--- hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java (original)
+++ hadoop/hdfs/branches/HDFS-1073/src/java/org/apache/hadoop/hdfs/server/namenode/NNStorage.java Thu Jun 9 22:56:43 2011
@@ -34,6 +34,7 @@ import java.security.NoSuchAlgorithmExce
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
@@ -77,7 +78,7 @@ import com.google.common.annotations.Vis
public class NNStorage extends Storage implements Closeable {
private static final Log LOG = LogFactory.getLog(NNStorage.class.getName());
- static final String MESSAGE_DIGEST_PROPERTY = "imageMD5Digest";
+ static final String DEPRECATED_MESSAGE_DIGEST_PROPERTY = "imageMD5Digest";
//
// The filenames used for storing the images
@@ -146,6 +147,12 @@ public class NNStorage extends Storage i
= new CopyOnWriteArrayList<StorageDirectory>();
/**
+ * Properties from old layout versions that may be needed
+ * during upgrade only.
+ */
+ private HashMap<String, String> deprecatedProperties;
+
+ /**
* Construct the NNStorage.
* @param conf Namenode configuration.
* @param imageDirs Directories the image can be stored in.
@@ -589,7 +596,32 @@ public class NNStorage extends Storage i
setDistributedUpgradeState(
sDUS == null? false : Boolean.parseBoolean(sDUS),
sDUV == null? getLayoutVersion() : Integer.parseInt(sDUV));
+ setDeprecatedPropertiesForUpgrade(props);
+ }
+
+ /**
+ * Pull any properties out of the VERSION file that are from older
+ * versions of HDFS and only necessary during upgrade.
+ */
+ private void setDeprecatedPropertiesForUpgrade(Properties props) {
+ deprecatedProperties = new HashMap<String, String>();
+ String md5 = props.getProperty(DEPRECATED_MESSAGE_DIGEST_PROPERTY);
+ if (md5 != null) {
+ deprecatedProperties.put(DEPRECATED_MESSAGE_DIGEST_PROPERTY, md5);
}
+ }
+
+ /**
+ * Return a property that was stored in an earlier version of HDFS.
+ *
+ * This should only be used during upgrades.
+ */
+ String getDeprecatedProperty(String prop) {
+ assert getLayoutVersion() > FSConstants.LAYOUT_VERSION :
+ "getDeprecatedProperty should only be done when loading " +
+ "storage from past versions during upgrade.";
+ return deprecatedProperties.get(prop);
+ }
/**
* Write version file into the storage directory.
@@ -617,18 +649,6 @@ public class NNStorage extends Storage i
props.setProperty("distributedUpgradeVersion",
Integer.toString(uVersion));
}
- /* TODO: resolve merge here.
- if (LayoutVersion.supports(Feature.FSIMAGE_CHECKSUM, layoutVersion)) {
- // TODO && ! transactional storage
- // Though the current NN supports this feature, this function
- // is called with old layoutVersions from the upgrade tests.
-
- // May be null on the first save after an upgrade.
- imageDigest = MD5Hash.digest(
- new FileInputStream(getStorageFile(sd, NameNodeFile.IMAGE)));
- }
- props.setProperty(MESSAGE_DIGEST_PROPERTY, imageDigest.toString());
- } */
}
static File getStorageFile(StorageDirectory sd, NameNodeFile type, long imageTxId) {
Modified: hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/TestDFSUpgradeFromImage.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/TestDFSUpgradeFromImage.java?rev=1134125&r1=1134124&r2=1134125&view=diff
==============================================================================
--- hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/TestDFSUpgradeFromImage.java (original)
+++ hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/TestDFSUpgradeFromImage.java Thu Jun 9 22:56:43 2011
@@ -32,6 +32,7 @@ import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.protocol.FSConstants;
import org.apache.hadoop.hdfs.server.common.HdfsConstants.StartupOption;
+import org.apache.hadoop.hdfs.server.namenode.FSImageTestUtil;
import org.apache.hadoop.util.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -182,38 +183,6 @@ public class TestDFSUpgradeFromImage ext
}
}
- public void testUpgradeFromRel14Image() throws IOException {
- unpackStorage();
- MiniDFSCluster cluster = null;
- try {
- Configuration conf = new HdfsConfiguration();
- if (System.getProperty("test.build.data") == null) { // to allow test to be run outside of Ant
- System.setProperty("test.build.data", "build/test/data");
- }
- conf.setInt(DFSConfigKeys.DFS_DATANODE_SCAN_PERIOD_HOURS_KEY, -1); // block scanning off
- cluster = new MiniDFSCluster.Builder(conf)
- .numDataNodes(numDataNodes)
- .format(false)
- .startupOption(StartupOption.UPGRADE)
- .clusterId("testClusterId")
- .build();
- cluster.waitActive();
- DistributedFileSystem dfs = (DistributedFileSystem)cluster.getFileSystem();
- DFSClient dfsClient = dfs.dfs;
- //Safemode will be off only after upgrade is complete. Wait for it.
- while ( dfsClient.setSafeMode(FSConstants.SafeModeAction.SAFEMODE_GET) ) {
- LOG.info("Waiting for SafeMode to be OFF.");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ignored) {}
- }
-
- verifyFileSystem(dfs);
- } finally {
- if (cluster != null) { cluster.shutdown(); }
- }
- }
-
/**
* Test that sets up a fake image from Hadoop 0.3.0 and tries to start a
* NN, verifying that the correct error message is thrown.
@@ -257,10 +226,50 @@ public class TestDFSUpgradeFromImage ext
}
/**
+ * Test upgrade from an 0.14 image
+ */
+ public void testUpgradeFromRel14Image() throws IOException {
+ unpackStorage();
+ upgradeAndVerify();
+ }
+
+ /**
* Test upgrade from 0.22 image
*/
public void testUpgradeFromRel22Image() throws IOException {
unpackStorage(HADOOP22_IMAGE);
+ upgradeAndVerify();
+ }
+
+ /**
+ * Test upgrade from 0.22 image with corrupt md5, make sure it
+ * fails to upgrade
+ */
+ public void testUpgradeFromCorruptRel22Image() throws IOException {
+ unpackStorage(HADOOP22_IMAGE);
+
+ // Overwrite the md5 stored in the VERSION files
+ File baseDir = new File(MiniDFSCluster.getBaseDirectory());
+ FSImageTestUtil.corruptVersionFile(
+ new File(baseDir, "name1/current/VERSION"),
+ "imageMD5Digest", "22222222222222222222222222222222");
+ FSImageTestUtil.corruptVersionFile(
+ new File(baseDir, "name2/current/VERSION"),
+ "imageMD5Digest", "22222222222222222222222222222222");
+
+ // Upgrade should now fail
+ try {
+ upgradeAndVerify();
+ fail("Upgrade did not fail with bad MD5");
+ } catch (IOException ioe) {
+ String msg = StringUtils.stringifyException(ioe);
+ if (!msg.contains("is corrupt with MD5 checksum")) {
+ throw ioe;
+ }
+ }
+ }
+
+ private void upgradeAndVerify() throws IOException {
MiniDFSCluster cluster = null;
try {
Configuration conf = new HdfsConfiguration();
@@ -284,8 +293,12 @@ public class TestDFSUpgradeFromImage ext
Thread.sleep(1000);
} catch (InterruptedException ignored) {}
}
+
+ verifyFileSystem(dfs);
} finally {
if (cluster != null) { cluster.shutdown(); }
- }
+ }
}
+
+
}
Modified: hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImageTestUtil.java
URL: http://svn.apache.org/viewvc/hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImageTestUtil.java?rev=1134125&r1=1134124&r2=1134125&view=diff
==============================================================================
--- hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImageTestUtil.java (original)
+++ hadoop/hdfs/branches/HDFS-1073/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImageTestUtil.java Thu Jun 9 22:56:43 2011
@@ -22,6 +22,7 @@ import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
@@ -30,12 +31,14 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import java.util.Set;
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
import org.apache.hadoop.hdfs.server.namenode.FSImageTransactionalStorageInspector.FoundFSImage;
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
import org.apache.hadoop.hdfs.util.MD5FileUtils;
+import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.MD5Hash;
import org.mockito.Mockito;
@@ -232,5 +235,32 @@ public abstract class FSImageTestUtil {
return (latestImage == null) ? null : latestImage.getFile();
}
+ /**
+ * Corrupt the given VERSION file by replacing a given
+ * key with a new value and re-writing the file.
+ *
+ * @param versionFile the VERSION file to corrupt
+ * @param key the key to replace
+ * @param value the new value for this key
+ */
+ public static void corruptVersionFile(File versionFile, String key, String value)
+ throws IOException {
+ Properties props = new Properties();
+ FileInputStream fis = new FileInputStream(versionFile);
+ FileOutputStream out = null;
+ try {
+ props.load(fis);
+ IOUtils.closeStream(fis);
+
+ props.setProperty(key, value);
+
+ out = new FileOutputStream(versionFile);
+ props.store(out, null);
+
+ } finally {
+ IOUtils.cleanup(null, fis, out);
+ }
+ }
+
}