hadoop-hdfs-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hair...@apache.org
Subject svn commit: r1032470 - in /hadoop/hdfs/trunk: ./ src/java/org/apache/hadoop/hdfs/protocol/ src/java/org/apache/hadoop/hdfs/server/namenode/ src/java/org/apache/hadoop/hdfs/server/protocol/ src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/
Date Mon, 08 Nov 2010 06:49:32 GMT
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();
+    }
+  }
 }



Mime
View raw message