Author: hairong
Date: Mon Nov 8 06:49:32 2010
New Revision: 1032470
URL: http://svn.apache.org/viewvc?rev=1032470&view=rev
Log:
HDFS-903. Support fsimage validation using MD5 checksum. Contributed by
Hairong Kuang.
Modified:
hadoop/hdfs/trunk/CHANGES.txt
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/protocol/FSConstants.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/BackupStorage.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/CheckpointSignature.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/Checkpointer.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/GetImageServlet.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/TransferFsImage.java
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/protocol/NamenodeProtocol.java
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java
Modified: hadoop/hdfs/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/CHANGES.txt?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
--- hadoop/hdfs/trunk/CHANGES.txt (original)
+++ hadoop/hdfs/trunk/CHANGES.txt Mon Nov 8 06:49:32 2010
@@ -37,6 +37,8 @@ Trunk (unreleased changes)
HDFS-1435. Provide an option to store fsimage compressed. (hairong)
+ HDFS-903. Support fsimage validation through MD5 checksum. (hairong)
+
IMPROVEMENTS
HDFS-1304. Add a new unit test for HftpFileSystem.open(..). (szetszwo)
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/protocol/FSConstants.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/protocol/FSConstants.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
--- hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/protocol/FSConstants.java
(original)
+++ hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/protocol/FSConstants.java
Mon Nov 8 06:49:32 2010
@@ -91,7 +91,7 @@ public interface FSConstants {
// Version is reflected in the data storage file.
// Versions are negative.
// Decrement LAYOUT_VERSION to define a new version.
- public static final int LAYOUT_VERSION = -25;
+ public static final int LAYOUT_VERSION = -26;
// Current version:
- // -25: support iamge compression.
+ // -26: support image checksum.
}
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/BackupStorage.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/BackupStorage.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/BackupStorage.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/BackupStorage.java
Mon Nov 8 06:49:32 2010
@@ -165,6 +165,7 @@ public class BackupStorage extends FSIma
// set storage fields
setStorageInfo(sig);
+ imageDigest = sig.imageDigest;
checkpointTime = sig.checkpointTime;
}
@@ -355,7 +356,7 @@ public class BackupStorage extends FSIma
editLog.revertFileStreams(STORAGE_JSPOOL_DIR + "/" + STORAGE_JSPOOL_FILE);
// write version file
- resetVersion(false);
+ resetVersion(false, imageDigest);
// wake up journal writer
synchronized(this) {
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/CheckpointSignature.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/CheckpointSignature.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/CheckpointSignature.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/CheckpointSignature.java
Mon Nov 8 06:49:32 2010
@@ -24,6 +24,7 @@ import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.server.common.StorageInfo;
import org.apache.hadoop.hdfs.server.namenode.FSImage;
+import org.apache.hadoop.io.MD5Hash;
import org.apache.hadoop.io.WritableComparable;
/**
@@ -35,6 +36,7 @@ public class CheckpointSignature extends
private static final String FIELD_SEPARATOR = ":";
long editsTime = -1L;
long checkpointTime = -1L;
+ MD5Hash imageDigest = null;
public CheckpointSignature() {}
@@ -42,16 +44,26 @@ public class CheckpointSignature extends
super(fsImage);
editsTime = fsImage.getEditLog().getFsEditTime();
checkpointTime = fsImage.getCheckpointTime();
+ imageDigest = fsImage.imageDigest;
}
CheckpointSignature(String str) {
String[] fields = str.split(FIELD_SEPARATOR);
- assert fields.length == 5 : "Must be 5 fields in CheckpointSignature";
+ assert fields.length == 6 : "Must be 6 fields in CheckpointSignature";
layoutVersion = Integer.valueOf(fields[0]);
namespaceID = Integer.valueOf(fields[1]);
cTime = Long.valueOf(fields[2]);
editsTime = Long.valueOf(fields[3]);
checkpointTime = Long.valueOf(fields[4]);
+ imageDigest = new MD5Hash(fields[5]);
+ }
+
+ /**
+ * Get the MD5 image digest
+ * @return the MD5 image digest
+ */
+ MD5Hash getImageDigest() {
+ return imageDigest;
}
public String toString() {
@@ -59,20 +71,23 @@ public class CheckpointSignature extends
+ String.valueOf(namespaceID) + FIELD_SEPARATOR
+ String.valueOf(cTime) + FIELD_SEPARATOR
+ String.valueOf(editsTime) + FIELD_SEPARATOR
- + String.valueOf(checkpointTime);
+ + String.valueOf(checkpointTime) + FIELD_SEPARATOR
+ + imageDigest.toString();
}
void validateStorageInfo(FSImage si) throws IOException {
if(layoutVersion != si.layoutVersion
|| namespaceID != si.namespaceID || cTime != si.cTime
- || checkpointTime != si.checkpointTime) {
+ || checkpointTime != si.checkpointTime ||
+ !imageDigest.equals(si.imageDigest)) {
// checkpointTime can change when the image is saved - do not compare
throw new IOException("Inconsistent checkpoint fields.\n"
+ "LV = " + layoutVersion + " namespaceID = " + namespaceID
- + " cTime = " + cTime + "; checkpointTime = " + checkpointTime
+ + " cTime = " + cTime + "; checkpointTime = " + checkpointTime
+ + " ; imageDigest = " + imageDigest
+ ".\nExpecting respectively: "
+ si.layoutVersion + "; " + si.namespaceID + "; " + si.cTime
- + "; " + si.checkpointTime);
+ + "; " + si.checkpointTime + "; " + si.imageDigest);
}
}
@@ -87,7 +102,8 @@ public class CheckpointSignature extends
(cTime < o.cTime) ? -1 : (cTime > o.cTime) ? 1 :
(editsTime < o.editsTime) ? -1 : (editsTime > o.editsTime) ? 1 :
(checkpointTime < o.checkpointTime) ? -1 :
- (checkpointTime > o.checkpointTime) ? 1 : 0;
+ (checkpointTime > o.checkpointTime) ? 1 :
+ imageDigest.compareTo(o.imageDigest);
}
public boolean equals(Object o) {
@@ -99,7 +115,8 @@ public class CheckpointSignature extends
public int hashCode() {
return layoutVersion ^ namespaceID ^
- (int)(cTime ^ editsTime ^ checkpointTime);
+ (int)(cTime ^ editsTime ^ checkpointTime) ^
+ imageDigest.hashCode();
}
/////////////////////////////////////////////////
@@ -109,11 +126,14 @@ public class CheckpointSignature extends
super.write(out);
out.writeLong(editsTime);
out.writeLong(checkpointTime);
+ imageDigest.write(out);
}
public void readFields(DataInput in) throws IOException {
super.readFields(in);
editsTime = in.readLong();
checkpointTime = in.readLong();
+ imageDigest = new MD5Hash();
+ imageDigest.readFields(in);
}
}
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/Checkpointer.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/Checkpointer.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/Checkpointer.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/Checkpointer.java
Mon Nov 8 06:49:32 2010
@@ -211,7 +211,8 @@ class Checkpointer extends Daemon {
int httpPort = httpSocAddr.getPort();
String fileid = "putimage=1&port=" + httpPort +
"&machine=" + infoBindAddress +
- "&token=" + sig.toString();
+ "&token=" + sig.toString() +
+ "&newChecksum=" + getFSImage().imageDigest.toString();
LOG.info("Posted URL " + backupNode.nnHttpAddress + fileid);
TransferFsImage.getFileClient(backupNode.nnHttpAddress, fileid,
(File[])null);
}
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSImage.java
Mon Nov 8 06:49:32 2010
@@ -30,6 +30,9 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URI;
import java.nio.ByteBuffer;
+import java.security.DigestInputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -71,6 +74,7 @@ import org.apache.hadoop.hdfs.server.pro
import org.apache.hadoop.hdfs.server.protocol.NamenodeCommand;
import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol;
import org.apache.hadoop.hdfs.server.protocol.NamenodeRegistration;
+import org.apache.hadoop.io.MD5Hash;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.compress.CompressionCodec;
@@ -88,6 +92,7 @@ public class FSImage extends Storage {
private static final SimpleDateFormat DATE_FORM =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ static final String MESSAGE_DIGEST_PROPERTY = "imageMD5Digest";
//
// The filenames used for storing the images
//
@@ -132,6 +137,8 @@ public class FSImage extends Storage {
protected long checkpointTime = -1L; // The age of the image
protected FSEditLog editLog = null;
private boolean isUpgradeFinalized = false;
+ protected MD5Hash imageDigest = null;
+ protected MD5Hash newImageDigest = null;
/**
* flag that controls if we try to restore failed storages
@@ -711,6 +718,20 @@ public class FSImage extends Storage {
setDistributedUpgradeState(
sDUS == null? false : Boolean.parseBoolean(sDUS),
sDUV == null? getLayoutVersion() : Integer.parseInt(sDUV));
+
+ String sMd5 = props.getProperty(MESSAGE_DIGEST_PROPERTY);
+ if (layoutVersion <= -26) {
+ if (sMd5 == null) {
+ throw new InconsistentFSStateException(sd.getRoot(),
+ "file " + STORAGE_FILE_VERSION + " does not have MD5 image
digest.");
+ }
+ this.imageDigest = new MD5Hash(sMd5);
+ } else if (sMd5 != null) {
+ throw new InconsistentFSStateException(sd.getRoot(),
+ "file " + STORAGE_FILE_VERSION +
+ " has image MD5 digest when version is " + layoutVersion);
+ }
+
this.checkpointTime = readCheckpointTime(sd);
}
@@ -755,6 +776,12 @@ public class FSImage extends Storage {
props.setProperty("distributedUpgradeState", Boolean.toString(uState));
props.setProperty("distributedUpgradeVersion",
Integer.toString(uVersion));
}
+ if (imageDigest == null) {
+ imageDigest = MD5Hash.digest(
+ new FileInputStream(getImageFile(sd, NameNodeFile.IMAGE)));
+ }
+ props.setProperty(MESSAGE_DIGEST_PROPERTY, imageDigest.toString());
+
writeCheckpointTime(sd);
}
@@ -1075,7 +1102,10 @@ public class FSImage extends Storage {
// Load in bits
//
boolean needToSave = true;
- FileInputStream fin = new FileInputStream(curFile);
+ MessageDigest digester = MD5Hash.getDigester();
+ DigestInputStream fin = new DigestInputStream(
+ new FileInputStream(curFile), digester);
+
DataInputStream in = new DataInputStream(fin);
try {
/*
@@ -1237,7 +1267,17 @@ public class FSImage extends Storage {
} finally {
in.close();
}
-
+
+ // verify checksum
+ MD5Hash readImageMd5 = new MD5Hash(digester.digest());
+ if (imageDigest == null) {
+ imageDigest = readImageMd5; // set this fsimage's checksum
+ } else if (!imageDigest.equals(readImageMd5)) {
+ throw new IOException("Image file " + curFile +
+ "is corrupt with MD5 checksum of " + readImageMd5 +
+ " but expecting " + imageDigest);
+ }
+
LOG.info("Image file of size " + curFile.length() + " loaded in "
+ (now() - startTime)/1000 + " seconds.");
@@ -1318,7 +1358,10 @@ public class FSImage extends Storage {
//
// Write out data
//
- FileOutputStream fos = new FileOutputStream(newFile);
+ FileOutputStream fout = new FileOutputStream(newFile);
+ MessageDigest digester = MD5Hash.getDigester();
+ DigestOutputStream fos = new DigestOutputStream(fout, digester);
+
DataOutputStream out = new DataOutputStream(fos);
try {
out.writeInt(FSConstants.LAYOUT_VERSION);
@@ -1350,15 +1393,21 @@ public class FSImage extends Storage {
strbuf = null;
out.flush();
- fos.getChannel().force(true);
+ fout.getChannel().force(true);
} finally {
out.close();
}
+ // set md5 of the saved image
+ setImageDigest( new MD5Hash(digester.digest()));
+
LOG.info("Image file of size " + newFile.length() + " saved in "
+ (now() - startTime)/1000 + " seconds.");
}
+ public void setImageDigest(MD5Hash digest) {
+ this.imageDigest = digest;
+ }
/**
* Save the contents of the FS image and create empty edits.
*
@@ -1749,11 +1798,14 @@ public class FSImage extends Storage {
* Moves fsimage.ckpt to fsImage and edits.new to edits
* Reopens the new edits file.
*/
- void rollFSImage() throws IOException {
+ void rollFSImage(CheckpointSignature sig,
+ boolean renewCheckpointTime) throws IOException {
+ sig.validateStorageInfo(this);
rollFSImage(true);
}
- void rollFSImage(boolean renewCheckpointTime) throws IOException {
+ private void rollFSImage(boolean renewCheckpointTime)
+ throws IOException {
if (ckptState != CheckpointStates.UPLOAD_DONE
&& !(ckptState == CheckpointStates.ROLLED_EDITS
&& getNumStorageDirs(NameNodeDirType.IMAGE) == 0)) {
@@ -1777,7 +1829,7 @@ public class FSImage extends Storage {
// Renames new image
//
renameCheckpoint();
- resetVersion(renewCheckpointTime);
+ resetVersion(renewCheckpointTime, newImageDigest);
}
/**
@@ -1811,10 +1863,11 @@ public class FSImage extends Storage {
/**
* Updates version and fstime files in all directories (fsimage and edits).
*/
- void resetVersion(boolean renewCheckpointTime) throws IOException {
+ void resetVersion(boolean renewCheckpointTime, MD5Hash newImageDigest)
throws IOException {
this.layoutVersion = FSConstants.LAYOUT_VERSION;
if(renewCheckpointTime)
this.checkpointTime = now();
+ this.imageDigest = newImageDigest;
ArrayList<StorageDirectory> al = null;
for (Iterator<StorageDirectory> it =
@@ -1951,7 +2004,7 @@ public class FSImage extends Storage {
* @param remoteNNRole
* @throws IOException
*/
- void endCheckpoint(CheckpointSignature sig,
+ void endCheckpoint(CheckpointSignature sig,
NamenodeRole remoteNNRole) throws IOException {
sig.validateStorageInfo(this);
// Renew checkpoint time for the active if the other is a checkpoint-node.
@@ -1960,7 +2013,7 @@ public class FSImage extends Storage {
// The backup-node always has up-to-date image and will have the same
// checkpoint time as the active node.
boolean renewCheckpointTime = remoteNNRole.equals(NamenodeRole.CHECKPOINT);
- rollFSImage(renewCheckpointTime);
+ rollFSImage(sig, renewCheckpointTime);
}
CheckpointStates getCheckpointState() {
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java
Mon Nov 8 06:49:32 2010
@@ -4195,7 +4195,13 @@ public class FSNamesystem implements FSC
}
}
- void rollFSImage() throws IOException {
+ /**
+ * Moves fsimage.ckpt to fsImage and edits.new to edits
+ * Reopens the new edits file.
+ *
+ * @param sig the signature of this checkpoint (old image)
+ */
+ void rollFSImage(CheckpointSignature sig) throws IOException {
writeLock();
try {
if (isInSafeMode()) {
@@ -4203,7 +4209,7 @@ public class FSNamesystem implements FSC
safeMode);
}
LOG.info("Roll FSImage from " + Server.getRemoteAddress());
- getFSImage().rollFSImage();
+ getFSImage().rollFSImage(sig, true);
} finally {
writeUnlock();
}
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/GetImageServlet.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/GetImageServlet.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/GetImageServlet.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/GetImageServlet.java
Mon Nov 8 06:49:32 2010
@@ -87,6 +87,7 @@ public class GetImageServlet extends Htt
} else if (ff.putImage()) {
// issue a HTTP get request to download the new fsimage
nnImage.validateCheckpointUpload(ff.getToken());
+ nnImage.newImageDigest = ff.getNewChecksum();
reloginIfNecessary().doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/NameNode.java
Mon Nov 8 06:49:32 2010
@@ -1100,9 +1100,9 @@ public class NameNode implements Namenod
/**
* Roll the image
*/
- @Deprecated
- public void rollFsImage() throws IOException {
- namesystem.rollFSImage();
+ @Deprecated @Override
+ public void rollFsImage(CheckpointSignature sig) throws IOException {
+ namesystem.rollFSImage(sig);
}
public void finalizeUpgrade() throws IOException {
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
Mon Nov 8 06:49:32 2010
@@ -370,7 +370,8 @@ public class SecondaryNameNode implement
private void putFSImage(CheckpointSignature sig) throws IOException {
String fileid = "putimage=1&port=" + imagePort +
"&machine=" + infoBindAddress +
- "&token=" + sig.toString();
+ "&token=" + sig.toString() +
+ "&newChecksum=" + checkpointImage.imageDigest;
LOG.info("Posted URL " + fsName + fileid);
TransferFsImage.getFileClient(fsName, fileid, (File[])null);
}
@@ -433,7 +434,7 @@ public class SecondaryNameNode implement
"after uploading new image to NameNode");
}
- namenode.rollFsImage();
+ namenode.rollFsImage(sig);
checkpointImage.endCheckpoint();
LOG.warn("Checkpoint done. New Image Size: "
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/TransferFsImage.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/TransferFsImage.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/TransferFsImage.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/namenode/TransferFsImage.java
Mon Nov 8 06:49:32 2010
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletReq
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.hdfs.protocol.FSConstants;
import org.apache.hadoop.hdfs.DFSUtil.ErrorSimulator;
+import org.apache.hadoop.io.MD5Hash;
import org.apache.hadoop.security.UserGroupInformation;
@@ -44,6 +45,7 @@ class TransferFsImage implements FSConst
private int remoteport;
private String machineName;
private CheckpointSignature token;
+ private MD5Hash newChecksum = null;
/**
* File downloader.
@@ -76,6 +78,8 @@ class TransferFsImage implements FSConst
machineName = pmap.get("machine")[0];
} else if (key.equals("token")) {
token = new CheckpointSignature(pmap.get("token")[0]);
+ } else if (key.equals("newChecksum")) {
+ newChecksum = new MD5Hash(pmap.get("newChecksum")[0]);
}
}
@@ -101,6 +105,14 @@ class TransferFsImage implements FSConst
return token;
}
+ /**
+ * Get the MD5 digest of the new image
+ * @return the MD5 digest of the new image
+ */
+ MD5Hash getNewChecksum() {
+ return newChecksum;
+ }
+
String getInfoServer() throws IOException{
if (machineName == null || remoteport == 0) {
throw new IOException ("MachineName and port undefined");
Modified:
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/protocol/NamenodeProtocol.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/protocol/NamenodeProtocol.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/protocol/NamenodeProtocol.java
(original)
+++
hadoop/hdfs/trunk/src/java/org/apache/hadoop/hdfs/server/protocol/NamenodeProtocol.java
Mon Nov 8 06:49:32 2010
@@ -42,10 +42,10 @@ public interface NamenodeProtocol extend
* (Only the latest change is reflected.
* The log of historical changes can be retrieved from the svn).
*
- * 4: new method added: getAccessKeys()
- *
+ * 5: Added one parameter to rollFSImage() and
+ * changed the definition of CheckpointSignature
*/
- public static final long versionID = 4L;
+ public static final long versionID = 5L;
// Error codes passed by errorReport().
final static int NOTIFY = 0;
@@ -108,12 +108,15 @@ public interface NamenodeProtocol extend
* Rolls the fsImage log. It removes the old fsImage, copies the
* new image to fsImage, removes the old edits and renames edits.new
* to edits. The call fails if any of the four files are missing.
+ *
+ * @param sig the signature of this checkpoint (old fsimage)
* @throws IOException
* @deprecated
* See {...@link org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode}
*/
@Deprecated
- public void rollFsImage() throws IOException;
+ public void rollFsImage(CheckpointSignature sig)
+ throws IOException;
/**
* Request name-node version and storage information.
Modified:
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java
(original)
+++
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java
Mon Nov 8 06:49:32 2010
@@ -94,13 +94,16 @@ public class TestSaveNamespace {
// Replace the FSImage with a spy
FSImage originalImage = fsn.dir.fsImage;
FSImage spyImage = spy(originalImage);
+ spyImage.setStorageDirectories(
+ FSNamesystem.getNamespaceDirs(conf),
+ FSNamesystem.getNamespaceEditsDirs(conf));
fsn.dir.fsImage = spyImage;
// inject fault
switch(fault) {
case SAVE_FSIMAGE:
// The spy throws a RuntimeException when writing to the second directory
- doAnswer(new FaultySaveImage(originalImage)).
+ doAnswer(new FaultySaveImage(spyImage)).
when(spyImage).saveFSImage((File)anyObject());
break;
case MOVE_CURRENT:
@@ -127,7 +130,8 @@ public class TestSaveNamespace {
}
// Now shut down and restart the namesystem
- fsn.close();
+ originalImage.close();
+ fsn.close();
fsn = null;
// Start a new namesystem, which should be able to recover
@@ -168,6 +172,9 @@ public class TestSaveNamespace {
// Replace the FSImage with a spy
final FSImage originalImage = fsn.dir.fsImage;
FSImage spyImage = spy(originalImage);
+ spyImage.setStorageDirectories(
+ FSNamesystem.getNamespaceDirs(conf),
+ FSNamesystem.getNamespaceEditsDirs(conf));
fsn.dir.fsImage = spyImage;
try {
@@ -182,6 +189,7 @@ public class TestSaveNamespace {
fsn.saveNamespace();
// Now shut down and restart the NN
+ originalImage.close();
fsn.close();
fsn = null;
Modified:
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java
URL:
http://svn.apache.org/viewvc/hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java?rev=1032470&r1=1032469&r2=1032470&view=diff
==============================================================================
---
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java
(original)
+++
hadoop/hdfs/trunk/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java
Mon Nov 8 06:49:32 2010
@@ -21,10 +21,14 @@ import static org.apache.hadoop.hdfs.ser
import static org.apache.hadoop.hdfs.server.common.Util.fileAsURI;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
+import java.util.Properties;
import java.util.Random;
import junit.framework.TestCase;
@@ -46,6 +50,8 @@ import org.apache.hadoop.hdfs.protocol.F
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
import org.apache.hadoop.hdfs.server.namenode.FSImage.NameNodeDirType;
import org.apache.hadoop.hdfs.server.namenode.FSImage.NameNodeFile;
+import org.apache.hadoop.io.IOUtils;
+import org.apache.hadoop.io.MD5Hash;
import org.apache.hadoop.util.StringUtils;
/**
@@ -405,4 +411,78 @@ public class TestStartup extends TestCas
namenode.stop();
namenode.join();
}
+
+ public void testImageChecksum() throws Exception {
+ LOG.info("Test uncompressed image checksum");
+ testImageChecksum(false);
+ LOG.info("Test compressed image checksum");
+ testImageChecksum(true);
+ }
+
+ private void testImageChecksum(boolean compress) throws Exception {
+ Configuration conf = new Configuration();
+ FileSystem.setDefaultUri(conf, "hdfs://localhost:0");
+ conf.set("dfs.http.address", "127.0.0.1:0");
+ File base_dir = new File(
+ System.getProperty("test.build.data", "build/test/data"), "dfs/");
+ conf.set("dfs.name.dir", new File(base_dir, "name").getPath());
+ conf.setBoolean("dfs.permissions", false);
+ if (compress) {
+ conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESSION_CODEC_KEY, true);
+ }
+
+ NameNode.format(conf);
+
+ // create an image
+ LOG.info("Create an fsimage");
+ NameNode namenode = new NameNode(conf);
+ namenode.getNamesystem().mkdirs("/test",
+ new PermissionStatus("hairong", null, FsPermission.getDefault()),
true);
+ assertTrue(namenode.getFileInfo("/test").isDir());
+ namenode.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
+ namenode.saveNamespace();
+
+ FSImage image = namenode.getFSImage();
+ image.loadFSImage();
+
+ File versionFile = image.getStorageDir(0).getVersionFile();
+
+ RandomAccessFile file = new RandomAccessFile(versionFile, "rws");
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ try {
+ // read the property from version file
+ in = new FileInputStream(file.getFD());
+ file.seek(0);
+ Properties props = new Properties();
+ props.load(in);
+
+ // get the MD5 property and change it
+ String sMd5 = props.getProperty(FSImage.MESSAGE_DIGEST_PROPERTY);
+ MD5Hash md5 = new MD5Hash(sMd5);
+ byte[] bytes = md5.getDigest();
+ bytes[0] += 1;
+ md5 = new MD5Hash(bytes);
+ props.setProperty(FSImage.MESSAGE_DIGEST_PROPERTY, md5.toString());
+
+ // write the properties back to version file
+ file.seek(0);
+ out = new FileOutputStream(file.getFD());
+ props.store(out, null);
+ out.flush();
+ file.setLength(out.getChannel().position());
+
+ // now load the image again
+ image.loadFSImage();
+
+ fail("Expect to get a checksumerror");
+ } catch(IOException e) {
+ assertTrue(e.getMessage().contains("is corrupt"));
+ } finally {
+ IOUtils.closeStream(in);
+ IOUtils.closeStream(out);
+ namenode.stop();
+ namenode.join();
+ }
+ }
}