hadoop-common-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From szets...@apache.org
Subject svn commit: r1349086 - in /hadoop/common/branches/branch-1: ./ src/hdfs/org/apache/hadoop/hdfs/ src/hdfs/org/apache/hadoop/hdfs/server/namenode/ src/test/org/apache/hadoop/hdfs/server/namenode/
Date Tue, 12 Jun 2012 01:29:24 GMT
Author: szetszwo
Date: Tue Jun 12 01:29:24 2012
New Revision: 1349086

URL: http://svn.apache.org/viewvc?rev=1349086&view=rev
Log:
HDFS-3521. Check every byte at the end of edit log and allow namenode to tolerate corruption.

Added:
    hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLogToleration.java
Modified:
    hadoop/common/branches/branch-1/CHANGES.txt
    hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/DFSConfigKeys.java
    hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
    hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java
    hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImage.java
    hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
    hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestCheckpoint.java
    hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java
    hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java

Modified: hadoop/common/branches/branch-1/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/CHANGES.txt?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/CHANGES.txt (original)
+++ hadoop/common/branches/branch-1/CHANGES.txt Tue Jun 12 01:29:24 2012
@@ -12,6 +12,9 @@ Release 1.2.0 - unreleased
 
     HDFS-3479. Port HDFS-3335 to branch-1. (Colin Patrick McCabe via eli)
 
+    HDFS-3521. Check every byte at the end of edit log and allow namenode to
+    tolerate corruption.  (szetszwo)
+
   BUG FIXES
 
     HADOOP-8445. Token should not print the password in toString

Modified: hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/DFSConfigKeys.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/DFSConfigKeys.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/DFSConfigKeys.java (original)
+++ hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/DFSConfigKeys.java Tue
Jun 12 01:29:24 2012
@@ -65,6 +65,8 @@ public class DFSConfigKeys extends Commo
   public static final long    DFS_NAMENODE_CHECKPOINT_PERIOD_DEFAULT = 3600;
   public static final String  DFS_NAMENODE_CHECKPOINT_SIZE_KEY = "dfs.namenode.checkpoint.size";
   public static final long    DFS_NAMENODE_CHECKPOINT_SIZE_DEFAULT = 4194304;
+  public static final String  DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY = "dfs.namenode.edits.toleration.length";
+  public static final int     DFS_NAMENODE_EDITS_TOLERATION_LENGTH_DEFAULT = -1; //i.e. disable
it
   public static final String  DFS_NAMENODE_UPGRADE_PERMISSION_KEY = "dfs.namenode.upgrade.permission";
   public static final int     DFS_NAMENODE_UPGRADE_PERMISSION_DEFAULT = 00777;
   public static final String  DFS_NAMENODE_HEARTBEAT_RECHECK_INTERVAL_KEY = "dfs.namenode.heartbeat.recheck-interval";

Modified: hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
(original)
+++ hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java
Tue Jun 12 01:29:24 2012
@@ -72,6 +72,10 @@ class FSDirectory implements FSConstants
     fsImage.setRestoreRemovedDirs(conf.getBoolean(
         DFSConfigKeys.DFS_NAMENODE_NAME_DIR_RESTORE_KEY,
         DFSConfigKeys.DFS_NAMENODE_NAME_DIR_RESTORE_DEFAULT));
+    fsImage.setEditsTolerationLength(conf.getInt(
+        DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY,
+        DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_DEFAULT));
+
     namesystem = ns;
     int configuredLimit = conf.getInt(
         DFSConfigKeys.DFS_LIST_LIMIT, DFSConfigKeys.DFS_LIST_LIMIT_DEFAULT);

Modified: hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java
(original)
+++ hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java
Tue Jun 12 01:29:24 2012
@@ -26,28 +26,37 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FilterInputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.LinkedList;
-import java.lang.Math;
-import java.nio.channels.FileChannel;
-import java.nio.ByteBuffer;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.fs.permission.PermissionStatus;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.protocol.Block;
 import org.apache.hadoop.hdfs.protocol.DatanodeID;
 import org.apache.hadoop.hdfs.protocol.FSConstants;
-import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
 import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
+import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
 import org.apache.hadoop.hdfs.server.common.Storage;
 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.metrics.NameNodeInstrumentation;
-import org.apache.hadoop.io.*;
-import org.apache.hadoop.fs.permission.*;
+import org.apache.hadoop.io.ArrayWritable;
+import org.apache.hadoop.io.DataOutputBuffer;
+import org.apache.hadoop.io.LongWritable;
+import org.apache.hadoop.io.UTF8;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.io.WritableFactories;
+import org.apache.hadoop.io.WritableFactory;
 import org.apache.hadoop.security.token.delegation.DelegationKey;
 
 /**
@@ -55,7 +64,9 @@ import org.apache.hadoop.security.token.
  * 
  */
 public class FSEditLog {
-  private static final byte OP_INVALID = -1;
+  public static final Log LOG = LogFactory.getLog(FSEditLog.class);
+
+  static final byte OP_INVALID = -1;
   private static final byte OP_ADD = 0;
   private static final byte OP_RENAME = 1;  // rename
   private static final byte OP_DELETE = 2;  // delete
@@ -80,7 +91,10 @@ public class FSEditLog {
   private static final byte OP_UPDATE_MASTER_KEY = 21; //update master key
 
   private static int sizeFlushBuffer = 512*1024;
+  /** Preallocation length in bytes for writing edit log. */
   private static final int PREALLOCATION_LENGTH = 1024 * 1024;
+  /** The limit of the length in bytes for each edit log transaction. */
+  private static int TRANSACTION_LENGTH_LIMIT = Integer.MAX_VALUE;
 
   private ArrayList<EditLogOutputStream> editStreams = null;
   private FSImage fsimage = null;
@@ -123,20 +137,21 @@ public class FSEditLog {
    * which stores edits in a local file.
    */
   static private class EditLogFileOutputStream extends EditLogOutputStream {
+    /** Preallocation buffer, padded with OP_INVALID */
+    private static final ByteBuffer PREALLOCATION_BUFFER
+        = ByteBuffer.allocateDirect(PREALLOCATION_LENGTH);
+    static {
+      PREALLOCATION_BUFFER.position(0).limit(PREALLOCATION_LENGTH);
+      for(int i = 0; i < PREALLOCATION_BUFFER.capacity(); i++) {
+        PREALLOCATION_BUFFER.put(OP_INVALID);
+      }
+    }
+
     private File file;
     private FileOutputStream fp;    // file stream for storing edit logs 
     private FileChannel fc;         // channel of the file stream for sync
     private DataOutputBuffer bufCurrent;  // current buffer for writing
     private DataOutputBuffer bufReady;    // buffer ready for flushing
-    static final ByteBuffer fill =
-        ByteBuffer.allocateDirect(PREALLOCATION_LENGTH);
-
-    static {
-      fill.position(0);
-      for (int i = 0; i < fill.capacity(); i++) {
-        fill.put(OP_INVALID);
-      }
-    }
 
     EditLogFileOutputStream(File name) throws IOException {
       super();
@@ -183,6 +198,8 @@ public class FSEditLog {
 
     @Override
     public void close() throws IOException {
+      LOG.info("closing edit log: position=" + fc.position() + ", editlog=" + getName());
+
       // close should have been called after all pending transactions 
       // have been flushed & synced.
       int bufSize = bufCurrent.size();
@@ -199,6 +216,8 @@ public class FSEditLog {
       fp.close();
       
       bufCurrent = bufReady = null;
+
+      LOG.info("close success: truncate to " + file.length() + ", editlog=" + getName());
     }
 
     /**
@@ -239,15 +258,18 @@ public class FSEditLog {
 
     // allocate a big chunk of data
     private void preallocate() throws IOException {
-      long position = fc.position();
-      if (position + 4096 >= fc.size()) {
-        FSNamesystem.LOG.debug("Preallocating Edit log, current size " +
-                                fc.size());
-        fill.position(0);
-        int written = fc.write(fill, position);
-        FSNamesystem.LOG.debug("Edit log size is now " + fc.size() +
-                              " written " + written + " bytes " +
-                              " at offset " +  position);
+      final long oldsize = fc.size();
+      if (fc.position() + 4096 >= oldsize) {
+        final ByteBuffer buffer = PREALLOCATION_BUFFER;
+        buffer.position(0).limit(PREALLOCATION_LENGTH);
+
+        int w = 0;
+        for(; (w += fc.write(buffer, oldsize + w)) < PREALLOCATION_LENGTH; );
+
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("PREALLOCATE: size is now " + fc.size() + " written " + w
+              + " bytes at offset " + oldsize + "; editlog=" + getName());
+        }
       }
     }
     
@@ -396,7 +418,7 @@ public class FSEditLog {
   }
 
   void fatalExit(String msg) {
-    FSNamesystem.LOG.fatal(msg, new Exception(msg));
+    LOG.fatal(msg, new Exception(msg));
     Runtime.getRuntime().exit(-1);
   }
 
@@ -494,42 +516,93 @@ public class FSEditLog {
     return false;
   }
 
-  static void verifyEndOfLog(PositionTrackingInputStream tracker,
-      DataInputStream in, MetaRecoveryContext recovery, long editsLength)
-          throws IOException {
-    /** The end of the edit log should contain only 0x00 or 0xff bytes.
-     * If it contains other bytes, the log itself may be corrupt.
-     * It is important to check this; if we don't, a stray OP_INVALID byte 
-     * could make us stop reading the edit log halfway through, and we'd never
-     * know that we had lost data.
-     *
-     * We don't check the very last part of the edit log, in case the
-     * NameNode crashed while writing to the edit log.
-     */
-    byte[] buf = new byte[4096];
-    while (true) {
-      long amt = (editsLength - PREALLOCATION_LENGTH) - tracker.getPos();
-      if (amt <= 0) {
-        return;
-      } else if (amt > buf.length) {
-        amt = buf.length;
-      }
-      int numRead = in.read(buf, 0, (int)amt);
-      if (numRead <= 0) {
-          MetaRecoveryContext.editLogLoaderPrompt("Unexpected short read " +
-              "at the end of the edit log!  Current position is " + 
-              tracker.getPos(), recovery);
-          break;
-      }
-      for (int i = 0; i < numRead; i++) {
-        if ((buf[i] != (byte)0) && (buf[i] != (byte)-1)) {
-          MetaRecoveryContext.editLogLoaderPrompt("Found garbage at the end " +
-              "of the edit log!  Current position is " + tracker.getPos(),
-              recovery);
-          break;
+  /**
+   * The end of a edit log should contain padding of either 0x00 or OP_INVALID.
+   * If it contains other bytes, the edit log may be corrupted.
+   * It is important to perform the check; otherwise, a stray OP_INVALID byte 
+   * could be misinterpreted as an end-of-log, and lead to silent data loss.
+   */
+  private static void checkEndOfLog(final EditLogInputStream edits,
+      final DataInputStream in,
+      final PositionTrackingInputStream pin,
+      final int tolerationLength) throws IOException {
+    if (tolerationLength < 0) {
+      //the checking is disabled.
+      return;
+    }
+    LOG.info("Start checking end of edit log (" + edits.getName() + ") ...");
+
+    in.mark(0); //clear the mark
+    final long readLength = pin.getPos();
+
+    long firstPadPos = -1; //first padded byte position 
+    byte pad = 0;          //padded value; must be either 0 or OP_INVALID
+    
+    final byte[] bytes = new byte[4096];
+    for(int n; (n = in.read(bytes)) != -1; ) {
+      for(int i = 0; i < n; i++) {
+        final byte b = bytes[i];
+
+        if (firstPadPos != -1 && b != pad) {
+          //the byte is different from the first padded byte, reset firstPos
+          firstPadPos = -1;
+
+          if (LOG.isDebugEnabled()) {
+            LOG.debug(String.format("reset: bytes[%d]=0x%X, pad=0x%02X", i, b, pad));
+          }
         }
+
+        if (firstPadPos == -1) {
+          if (b == 0 || b == OP_INVALID) {
+            //found the first padded byte
+            firstPadPos = pin.getPos() - n + i;
+            pad = b;
+            
+            if (LOG.isDebugEnabled()) {
+              LOG.debug(String.format("found: bytes[%d]=0x%02X=pad, firstPadPos=%d",
+                  i, b, firstPadPos));
+            }
+          }
+        } 
+      }
+    }
+    
+    final long corruptionLength;
+    final long padLength;
+    if (firstPadPos == -1) { //padding not found
+      corruptionLength = edits.length() - readLength;
+      padLength = 0;
+    } else {
+      corruptionLength = firstPadPos - readLength;
+      padLength = edits.length() - firstPadPos;
+    }
+
+    LOG.info("Checked the bytes after the end of edit log (" + edits.getName() + "):");
+    LOG.info("  Padding position  = " + firstPadPos + " (-1 means padding not found)");
+    LOG.info("  Edit log length   = " + edits.length());
+    LOG.info("  Read length       = " + readLength);
+    LOG.info("  Corruption length = " + corruptionLength);
+    LOG.info("  Toleration length = " + tolerationLength
+        + " (= " + DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY + ")");
+    LOG.info(String.format(
+        "Summary: |---------- Read=%d ----------|-- Corrupt=%d --|-- Pad=%d --|",
+        readLength, corruptionLength, padLength));
+
+    if (pin.getPos() != edits.length()) {
+      throw new IOException("Edit log length mismatched: edits.length() = "
+          + edits.length() + " != input steam position = " + pin.getPos());
+    }
+    if (corruptionLength > 0) {
+      final String err = "Edit log corruption detected: corruption length = " + corruptionLength;
+      if (corruptionLength <= tolerationLength) {
+        LOG.warn(err + " <= toleration length = " + tolerationLength
+            + "; the corruption is tolerable.");
+      } else {
+        throw new IOException(err + " > toleration length = " + tolerationLength
+            + "; the corruption is intolerable.");
       }
     }
+    return;
   }
   
   /**
@@ -537,7 +610,7 @@ public class FSEditLog {
    * This is where we apply edits that we've been writing to disk all
    * along.
    */
-  static int loadFSEdits(EditLogInputStream edits,
+  static int loadFSEdits(EditLogInputStream edits, int tolerationLength,
       MetaRecoveryContext recovery) throws IOException {
     FSNamesystem fsNamesys = FSNamesystem.getFSNamesystem();
     FSDirectory fsDir = fsNamesys.dir;
@@ -562,7 +635,9 @@ public class FSEditLog {
     long recentOpcodeOffsets[] = new long[4];
     Arrays.fill(recentOpcodeOffsets, -1);
 
+    final boolean isToterationEnabled = tolerationLength >= 0;
     DataInputStream in = new DataInputStream(tracker);
+    Byte opcode = null;
     try {
       // Read log file version. Could be missing. 
       in.mark(4);
@@ -587,21 +662,26 @@ public class FSEditLog {
                             "Unsupported version " + logVersion;
 
       while (true) {
+        if (isToterationEnabled) {
+          //mark position could be reset in case of exceptions
+          in.mark(TRANSACTION_LENGTH_LIMIT); 
+        }
+
         long timestamp = 0;
         long mtime = 0;
         long atime = 0;
         long blockSize = 0;
-        byte opcode = -1;
+        opcode = null;
         try {
           opcode = in.readByte();
           if (opcode == OP_INVALID) {
-            verifyEndOfLog(tracker, in, recovery, edits.length());
-            FSNamesystem.LOG.info("Invalid opcode, reached end of edit log " +
+            LOG.info("Invalid opcode, reached end of edit log " +
                        "Number of transactions found: " + numEdits + ".  " +
                        "Bytes read: " + tracker.getPos());
             break; // no more transactions
           }
         } catch (EOFException e) {
+          LOG.info("Reading " + edits.getName() + ": " + e);
           break; // no more transactions
         }
         recentOpcodeOffsets[numEdits % recentOpcodeOffsets.length] =
@@ -677,8 +757,8 @@ public class FSEditLog {
 
           // The open lease transaction re-creates a file if necessary.
           // Delete the file if it already exists.
-          if (FSNamesystem.LOG.isDebugEnabled()) {
-            FSNamesystem.LOG.debug(opcode + ": " + path + 
+          if (LOG.isDebugEnabled()) {
+            LOG.debug(opcode + ": " + path + 
                                    " numblocks : " + blocks.length +
                                    " clientHolder " +  clientName +
                                    " clientMachine " + clientMachine);
@@ -915,6 +995,12 @@ public class FSEditLog {
         }
       }
     } catch (Throwable t) {
+      String msg = "Failed to parse edit log (" + edits.getName()
+          + ") at position " + tracker.getPos()
+          + ", edit log length is " + edits.length()
+          + ", opcode=" + opcode
+          + ", isToterationEnabled=" + isToterationEnabled;
+
       // Catch Throwable because in the case of a truly corrupt edits log, any
       // sort of error might be thrown (NumberFormat, NullPointer, EOF, etc.)
       if (Storage.is203LayoutVersion(logVersion) &&
@@ -922,35 +1008,44 @@ public class FSEditLog {
         // Failed to load 0.20.203 version edits during upgrade. This version has
         // conflicting opcodes with the later releases. The editlog must be 
         // emptied by restarting the namenode, before proceeding with the upgrade.
-        String msg = "During upgrade, failed to load the editlog version " + 
+        msg += ": During upgrade, failed to load the editlog version " + 
           logVersion + " from release 0.20.203. Please go back to the old " + 
           " release and restart the namenode. This empties the editlog " +
           " and saves the namespace. Resume the upgrade after this step.";
         throw new IOException(msg, t);
       }
-      StringBuilder sb = new StringBuilder();
-      sb.append("Error replaying edit log at offset " + tracker.getPos());
       if (recentOpcodeOffsets[0] != -1) {
         Arrays.sort(recentOpcodeOffsets);
-        sb.append("\nRecent opcode offsets:");
-        for (long offset : recentOpcodeOffsets) {
-          if (offset != -1) {
-            sb.append(' ').append(offset);
-          }
-        }
+        StringBuilder sb = new StringBuilder(", Recent opcode offsets=[")
+            .append(recentOpcodeOffsets[0]);
+        for (int i = 1; i < recentOpcodeOffsets.length; i++) {
+          if (recentOpcodeOffsets[i] != -1) {
+            sb.append(' ').append(recentOpcodeOffsets[i]);
+          }
+        }
+        msg += sb.append("]");
+      }
+
+      LOG.warn(msg, t);
+      if (isToterationEnabled) {
+        in.reset(); //reset to the beginning position of this transaction
+      } else {
+        //edit log toleration feature is disabled
+        MetaRecoveryContext.editLogLoaderPrompt(msg, recovery);
       }
-      String errorMessage = sb.toString();
-      FSImage.LOG.error(errorMessage, t);
-      MetaRecoveryContext.editLogLoaderPrompt(errorMessage, recovery);
     } finally {
-      in.close();
+      try {
+        checkEndOfLog(edits, in, tracker, tolerationLength);
+      } finally {
+        in.close();
+      }
     }
-    FSImage.LOG.info("Edits file " + edits.getName() 
+    LOG.info("Edits file " + edits.getName() 
         + " of size " + edits.length() + " edits # " + numEdits 
         + " loaded in " + (FSNamesystem.now()-startTime)/1000 + " seconds.");
 
-    if (FSImage.LOG.isDebugEnabled()) {
-      FSImage.LOG.debug("numOpAdd = " + numOpAdd + " numOpClose = " + numOpClose 
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("numOpAdd = " + numOpAdd + " numOpClose = " + numOpClose 
           + " numOpDelete = " + numOpDelete + " numOpRename = " + numOpRename 
           + " numOpSetRepl = " + numOpSetRepl + " numOpMkDir = " + numOpMkDir
           + " numOpSetPerm = " + numOpSetPerm 
@@ -1075,7 +1170,7 @@ public class FSEditLog {
             eStream.setReadyToFlush();
             streams.add(eStream);
           } catch (IOException ie) {
-            FSNamesystem.LOG.error("Unable to get ready to flush.", ie);
+            LOG.error("Unable to get ready to flush.", ie);
             //
             // remember the streams that encountered an error.
             //
@@ -1093,7 +1188,7 @@ public class FSEditLog {
         try {
           eStream.flush();
         } catch (IOException ie) {
-          FSNamesystem.LOG.error("Unable to sync edit log.", ie);
+          LOG.error("Unable to sync edit log.", ie);
           //
           // remember the streams that encountered an error.
           //
@@ -1150,7 +1245,7 @@ public class FSEditLog {
       buf.append(eStream.getTotalSyncTime());
       buf.append(" ");
     }
-    FSNamesystem.LOG.info(buf);
+    LOG.info(buf);
   }
 
   /** 
@@ -1341,7 +1436,7 @@ public class FSEditLog {
               "Inconsistent existence of edits.new " + editsNew);
         }
       }
-      FSNamesystem.LOG.warn("Cannot roll edit log," +
+      LOG.warn("Cannot roll edit log," +
           " edits.new files already exists in all healthy directories:" + b);
       return;
     }
@@ -1364,7 +1459,7 @@ public class FSEditLog {
         eStream.create();
         editStreams.add(eStream);
       } catch (IOException ioe) {
-        FSImage.LOG.error("error retrying to reopen storage directory '" +
+        LOG.error("error retrying to reopen storage directory '" +
             sd.getRoot().getAbsolutePath() + "'", ioe);
         toRemove.add(sd);
         it.remove();

Modified: hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImage.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImage.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImage.java
(original)
+++ hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/FSImage.java
Tue Jun 12 01:29:24 2012
@@ -60,7 +60,6 @@ import org.apache.hadoop.hdfs.server.nam
 import org.apache.hadoop.hdfs.server.namenode.FSEditLog.EditLogFileInputStream;
 import org.apache.hadoop.hdfs.util.AtomicFileOutputStream;
 import org.apache.hadoop.io.IOUtils;
-import org.apache.hadoop.io.MultipleIOException;
 import org.apache.hadoop.io.UTF8;
 import org.apache.hadoop.io.Writable;
 
@@ -143,6 +142,8 @@ public class FSImage extends Storage {
   /** Flag to restore removed storage directories at checkpointing */
   private boolean restoreRemovedDirs = DFSConfigKeys.DFS_NAMENODE_NAME_DIR_RESTORE_DEFAULT;
 
+  private int editsTolerationLength = DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_DEFAULT;
+
   /**
    */
   FSImage() {
@@ -1020,12 +1021,12 @@ public class FSImage extends Storage {
     int numEdits = 0;
     EditLogFileInputStream edits = 
       new EditLogFileInputStream(getImageFile(sd, NameNodeFile.EDITS));
-    numEdits = FSEditLog.loadFSEdits(edits, recovery);
+    numEdits = FSEditLog.loadFSEdits(edits, editsTolerationLength, recovery);
     edits.close();
     File editsNew = getImageFile(sd, NameNodeFile.EDITS_NEW);
     if (editsNew.exists() && editsNew.length() > 0) {
       edits = new EditLogFileInputStream(editsNew);
-      numEdits += FSEditLog.loadFSEdits(edits, recovery);
+      numEdits += FSEditLog.loadFSEdits(edits, editsTolerationLength, recovery);
       edits.close();
     }
     // update the counts.
@@ -1233,6 +1234,12 @@ public class FSImage extends Storage {
     this.restoreRemovedDirs = allow;
   }  
   
+  void setEditsTolerationLength(int editsTolerationLength) {
+    this.editsTolerationLength = editsTolerationLength;
+    FSEditLog.LOG.info(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY
+        + " = " + editsTolerationLength);
+  }  
+  
   /** restore a metadata file */
   private static void restoreFile(File src, File dstdir, String dstfile)
       throws IOException {

Modified: hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
(original)
+++ hadoop/common/branches/branch-1/src/hdfs/org/apache/hadoop/hdfs/server/namenode/SecondaryNameNode.java
Tue Jun 12 01:29:24 2012
@@ -148,6 +148,18 @@ public class SecondaryNameNode implement
    * Initialize SecondaryNameNode.
    */
   private void initialize(final Configuration conf) throws IOException {
+    //SecondaryNameNode should not tolerate any corruption
+    //since edit logs are transferred from a healthy NameNode.
+    final int editsTolerationLength = conf.getInt(
+        DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY, 
+        DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_DEFAULT);
+    if (editsTolerationLength >= 0) {
+      LOG.info(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY
+          + " is set to " + editsTolerationLength 
+          + ".  Override it with -1, i.e. disable it.");
+      conf.setInt(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY, -1);
+    }
+
     final InetSocketAddress infoSocAddr = getHttpAddress(conf);
     infoBindAddress = infoSocAddr.getHostName();
     if (UserGroupInformation.isSecurityEnabled()) {

Modified: hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestCheckpoint.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestCheckpoint.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestCheckpoint.java
(original)
+++ hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestCheckpoint.java
Tue Jun 12 01:29:24 2012
@@ -17,29 +17,32 @@
  */
 package org.apache.hadoop.hdfs.server.namenode;
 
-import junit.framework.TestCase;
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
 import java.util.Collection;
-import java.util.List;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Random;
 
+import junit.framework.TestCase;
+
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.DistributedFileSystem;
 import org.apache.hadoop.hdfs.MiniDFSCluster;
 import org.apache.hadoop.hdfs.protocol.FSConstants.SafeModeAction;
-import org.apache.hadoop.hdfs.server.common.Storage;
-import org.apache.hadoop.hdfs.server.namenode.FSImage.NameNodeFile;
-import org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.ErrorSimulator;
 import org.apache.hadoop.hdfs.server.common.HdfsConstants.StartupOption;
+import org.apache.hadoop.hdfs.server.common.Storage;
 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.hdfs.server.namenode.SecondaryNameNode.ErrorSimulator;
 import org.apache.hadoop.hdfs.tools.DFSAdmin;
 import org.apache.hadoop.io.MD5Hash;
-import org.apache.hadoop.fs.FSDataOutputStream;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.FileUtil;
-import org.apache.hadoop.fs.Path;
 
 /**
  * This class tests the creation and validation of a checkpoint.
@@ -589,10 +592,15 @@ public class TestCheckpoint extends Test
       writeFile(fileSys, file1, replication);
       checkFile(fileSys, file1, replication);
 
+      //test edit toleration auto disable
+      conf.setInt(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY, 1024);
+      assertEquals(1024, conf.getInt(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY,
0));
+      SecondaryNameNode secondary = startSecondaryNameNode(conf);
+      assertEquals(-1, conf.getInt(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY,
0));
+
       //
       // Take a checkpoint
       //
-      SecondaryNameNode secondary = startSecondaryNameNode(conf);
       ErrorSimulator.initializeErrorSimulationEvent(3);
       secondary.doCheckpoint();
       secondary.shutdown();

Modified: hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java
(original)
+++ hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java
Tue Jun 12 01:29:24 2012
@@ -143,7 +143,7 @@ public class TestEditLog extends TestCas
       File editFile = FSImage.getImageFile(it.next(), NameNodeFile.EDITS);
       System.out.println("Verifying file: " + editFile);
       int numEdits = FSEditLog.loadFSEdits(
-          new EditLogFileInputStream(editFile), null);
+          new EditLogFileInputStream(editFile), -1, null);
       int numLeases = FSNamesystem.getFSNamesystem().leaseManager.countLease();
       System.out.println("Number of outstanding leases " + numLeases);
       assertEquals(0, numLeases);

Added: hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLogToleration.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLogToleration.java?rev=1349086&view=auto
==============================================================================
--- hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLogToleration.java
(added)
+++ hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestEditLogToleration.java
Tue Jun 12 01:29:24 2012
@@ -0,0 +1,381 @@
+/**
+ * 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 static org.junit.Assert.assertTrue;
+
+import java.io.DataOutput;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.Log4JLogger;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.MiniDFSCluster;
+import org.apache.hadoop.hdfs.server.namenode.FSImage.NameNodeFile;
+import org.apache.hadoop.metrics2.util.MBeans;
+import org.apache.log4j.Level;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test the edit log toleration feature
+ * which allows namenode to tolerate edit log corruption.
+ * The corruption could possibly be edit file truncation, extra padding,
+ * truncate-and-then-pad, etc.
+ */
+public class TestEditLogToleration {
+  {
+    ((Log4JLogger)FSEditLog.LOG).getLogger().setLevel(Level.ALL);
+    ((Log4JLogger)LogFactory.getLog(MBeans.class)).getLogger().setLevel(Level.OFF);
+  }
+
+  private static final Log LOG = LogFactory.getLog(TestEditLogToleration.class);
+
+  private static final int TOLERATION_LENGTH = 1024;
+  private static final byte[] PADS = {0, FSEditLog.OP_INVALID};
+  
+  private static final int LOOP = 8;
+  private static final Random RANDOM = new Random(); 
+
+  /** Base class for modifying edit log to simulate file corruption. */
+  static abstract class EditFileModifier {
+    void log(File f) {
+      LOG.info(getClass().getSimpleName() + ": length=" + f.length() + ", f=" + f);
+    }
+
+    /** Modify the edit file. */
+    abstract void modify(File editFile) throws IOException;
+
+    /** Is the modification tolerable? */
+    abstract boolean isTolerable();
+  }
+
+  /** NullModifier does not change the file at all for testing normal case. */
+  static class NullModifier extends EditFileModifier {
+    @Override
+    void modify(File f) throws IOException {log(f);}
+    @Override
+    boolean isTolerable() {return true;}
+  }
+
+  /** Truncate the edit file. */
+  static class Truncating extends EditFileModifier {
+    final int truncationLength;
+
+    /**
+     * @param truncationLength truncate the file by this length
+     */
+    Truncating(int truncationLength) {
+      this.truncationLength = truncationLength;
+    }
+
+    @Override
+    void modify(File f) throws IOException {
+      // truncate the file
+      log(f);
+      final RandomAccessFile raf = new RandomAccessFile(f, "rw");
+      raf.setLength(f.length() - truncationLength);
+      raf.close();
+      LOG.info(getClass().getSimpleName() + ": new length=" + f.length()
+          + ", truncationLength=" + truncationLength);
+    }
+    
+    @Override
+    boolean isTolerable() {
+      // Because the editlog is truncated, only the last remaining
+      // transaction could be incomplete and hence corrupt. Since
+      // TOLERATION_LENGTH is much larger than any transaction length,
+      // truncation is tolerable corruption.
+      return true;
+    }
+  }
+  
+  /**
+   * Add padding to the edit file for simulating normal or error padding.
+   * The padding could be the same padding (i.e. 0 or OP_INVALID) used
+   * in edit log preallocation (see EditLogFileOutputStream.preallcate()),
+   * or some other values.
+   * 
+   * This modifier changes the editlog to:
+   * Add (corruptionLeangth - 1) padding bytes, followed by a corrupt byte
+   * followed (paddinLength) padding bytes.
+   * 
+   * |- valid bytes -|- padding bytes -|- corrupt byte -|-- padding bytes --|
+   */
+  static class Padding extends EditFileModifier {
+    static final byte[] PAD_BUFFER = new byte[4096];
+    final int corruptionLength;
+    final int paddingLength;
+    final byte pad;
+
+    /**
+     * @param corruptionLength corrupt bytes
+     * @param paddingLength number padding bytes added
+     * @param pad what byte is used for padding
+     */
+    Padding(int corruptionLength, int paddingLength, byte pad) {
+      this.corruptionLength = corruptionLength;
+      this.paddingLength = paddingLength;
+      this.pad = pad;
+    }
+
+    @Override
+    void modify(File f) throws IOException {
+      log(f);
+
+      // Append padding
+      final RandomAccessFile raf = new RandomAccessFile(f, "rw");
+      raf.seek(f.length());
+      if (corruptionLength > 0) {
+        pad(raf, pad, corruptionLength - 1);
+        raf.write(0xAB);
+      }
+      pad(raf, pad, paddingLength);
+      raf.close();
+      LOG.info(getClass().getSimpleName() + ": new length=" + f.length()
+          + ", corruptionLength=" + corruptionLength
+          + ", paddingLength=" + paddingLength);
+    }
+    
+    @Override
+    boolean isTolerable() {
+      return corruptionLength <= TOLERATION_LENGTH;
+    }
+
+    private static void pad(final DataOutput out, final byte pad, int length
+        ) throws IOException {
+      Arrays.fill(PAD_BUFFER, pad);
+      for(; length > 0; ) {
+        final int n = length < PAD_BUFFER.length? length : PAD_BUFFER.length;
+        out.write(PAD_BUFFER, 0, n);
+        length -= n;
+      }
+    }
+  }
+  
+  /**
+   * Chain several modifier together for simulating behavior like
+   * truncate-and-then-pad.
+   */
+  static class ChainModifier extends EditFileModifier {
+    final List<EditFileModifier> modifers;
+
+    ChainModifier(EditFileModifier ... modifiers) {
+      this.modifers = Arrays.asList(modifiers);
+    }
+
+    @Override
+    void modify(File editFile) throws IOException {
+      for(EditFileModifier m : modifers) {
+        m.modify(editFile);
+      }
+    }
+
+    @Override
+    boolean isTolerable() {
+      // Note in some cases tolerable combination could result in intolerable
+      // modifier. Similarly intolerable combination could also result in
+      // tolerable modifier.
+      // The following tests ensure that such combination are not possible by
+      // choosing appropriate modifier properties
+      for(EditFileModifier m : modifers) {
+        if (!m.isTolerable()) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+
+  void runTest(EditFileModifier modifier) throws IOException {
+    //set toleration length
+    final Configuration conf = new Configuration();
+    conf.setInt(DFSConfigKeys.DFS_NAMENODE_EDITS_TOLERATION_LENGTH_KEY, TOLERATION_LENGTH);
+
+    final MiniDFSCluster cluster = new MiniDFSCluster(conf, 0, true, null);
+    try {
+      cluster.waitActive();
+
+      //add a few transactions and then shutdown namenode.
+      final FileSystem fs = cluster.getFileSystem();
+      fs.mkdirs(new Path("/user/foo"));
+      fs.mkdirs(new Path("/user/bar"));
+      cluster.shutdownNameNode();
+
+      //modify edit files
+      for(File dir : FSNamesystem.getNamespaceEditsDirs(conf)) {
+        final File editFile  = new File(new File(dir, "current"),
+            NameNodeFile.EDITS.getName());
+        assertTrue("Should exist: " + editFile, editFile.exists());
+
+        modifier.modify(editFile);
+      }
+
+      try {
+        //restart namenode.
+        cluster.restartNameNode();
+        
+        //No exception: the modification must be tolerable.
+        Assert.assertTrue(modifier.isTolerable());
+      } catch (IOException e) {
+        //Got an exception: the modification must be intolerable.
+        LOG.info("Got an exception", e);
+        Assert.assertFalse(modifier.isTolerable());
+      }
+    } finally {
+      cluster.shutdown();
+    }
+  }
+
+  @Test
+  public void testNoModification() throws IOException {
+    runTest(new NullModifier());
+  }
+
+  /** Test truncating some bytes. */
+  @Test
+  public void testTruncatedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      final int truncation = RANDOM.nextInt(100);
+      runTest(new Truncating(truncation));
+    }
+  }
+
+  /** Test padding some bytes with no corruption. */
+  @Test
+  public void testNormalPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP/2; i++) {
+      //zero corruption
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+
+      final Padding p = new Padding(0, padding, pad);
+      Assert.assertTrue(p.isTolerable());
+      runTest(p);
+    }
+  }
+
+  /** Test corruption and padding with corruption length <= toleration length. */
+  @Test
+  public void testTolerableErrorPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      //0 < corruption <= TOLERATION_LENGTH
+      final int corruption = RANDOM.nextInt(TOLERATION_LENGTH) + 1;
+      Assert.assertTrue(corruption > 0);
+      Assert.assertTrue(corruption <= TOLERATION_LENGTH);
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+
+      final Padding p = new Padding(corruption, padding, pad);
+      Assert.assertTrue(p.isTolerable());
+      runTest(p);
+    }
+  }
+
+  /** Test corruption and padding with corruption length > toleration length. */
+  @Test
+  public void testIntolerableErrorPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      //corruption > TOLERATION_LENGTH
+      final int corruption = RANDOM.nextInt(TOLERATION_LENGTH) + TOLERATION_LENGTH + 1;
+      Assert.assertTrue(corruption > TOLERATION_LENGTH);
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+
+      final Padding p = new Padding(corruption, padding, pad);
+      Assert.assertFalse(p.isTolerable());
+      runTest(p);
+    }
+  }
+
+  /** Test truncate and then pad. */
+  @Test
+  public void testTruncateAndNormalPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      //truncation
+      final int truncation = RANDOM.nextInt(100);
+      final Truncating t = new Truncating(truncation);
+
+      //padding with zero corruption
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+      final Padding p = new Padding(0, padding, pad);
+
+      //chain: truncate and then pad
+      final ChainModifier chain = new ChainModifier(t, p);
+      Assert.assertTrue(chain.isTolerable());
+      runTest(chain);
+    }
+  }
+
+  /** Test truncate and then pad with tolerable corruption. */
+  @Test
+  public void testTruncateAndTolerableErrorPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      //truncation
+      final int truncation = RANDOM.nextInt(100);
+      final Truncating t = new Truncating(truncation);
+
+      // padding with tolerable corruption (0 < corruption <= TOLERATION_LENGTH/2)
+      // Note the choice of padding here ensures that the corruption is tolerable
+      final int corruption = RANDOM.nextInt(TOLERATION_LENGTH >> 1) + 1;
+      Assert.assertTrue(corruption > 0);
+      Assert.assertTrue(corruption <= TOLERATION_LENGTH/2);
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+      final Padding p = new Padding(corruption, padding, pad);
+
+      //chain: truncate and then pad
+      final ChainModifier chain = new ChainModifier(t, p);
+      Assert.assertTrue(chain.isTolerable());
+      runTest(chain);
+    }
+  }
+
+  /** Test truncate and then pad with intolerable corruption. */
+  @Test
+  public void testTruncateAndIntolerableErrorPaddedEditLog() throws IOException {
+    for(int i = 0; i < LOOP; i++) {
+      //truncation
+      final int truncation = RANDOM.nextInt(100);
+      final Truncating t = new Truncating(truncation);
+
+      //padding with intolerable corruption (corruption > TOLERATION_LENGTH)
+      final int corruption = RANDOM.nextInt(TOLERATION_LENGTH) + TOLERATION_LENGTH + 1;
+      Assert.assertTrue(corruption > TOLERATION_LENGTH);
+      final int padding = RANDOM.nextInt(2*TOLERATION_LENGTH);
+      final byte pad = PADS[RANDOM.nextInt(PADS.length)];
+      final Padding p = new Padding(corruption, padding, pad);
+
+      //chain: truncate and then pad
+      final ChainModifier chain = new ChainModifier(t, p);
+      Assert.assertFalse(chain.isTolerable());
+      runTest(chain);
+    }
+  }
+}

Modified: hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java?rev=1349086&r1=1349085&r2=1349086&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java
(original)
+++ hadoop/common/branches/branch-1/src/test/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java
Tue Jun 12 01:29:24 2012
@@ -141,7 +141,7 @@ public class TestSecurityTokenEditLog ex
         File editFile = FSImage.getImageFile(it.next(), NameNodeFile.EDITS);
         System.out.println("Verifying file: " + editFile);
         int numEdits = FSEditLog.loadFSEdits(
-                                  new EditLogFileInputStream(editFile), null);
+            new EditLogFileInputStream(editFile), -1, null);
         assertTrue("Verification for " + editFile + " failed. " +
                    "Expected " + (NUM_THREADS * opsPerTrans * NUM_TRANSACTIONS + numKeys)
+ " transactions. "+
                    "Found " + numEdits + " transactions.",



Mime
View raw message