Repository: hadoop Updated Branches: refs/heads/branch-2.7 eae9b691c -> 61e1348fe
HDFS-10763. Open files can leak permanently due to inconsistent lease update. Contributed by Kihwal Lee. Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/61e1348f Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/61e1348f Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/61e1348f Branch: refs/heads/branch-2.7 Commit: 61e1348fe479872b0eb1b53c50b248b33b37d77b Parents: eae9b69 Author: Kihwal Lee <kih...@apache.org> Authored: Thu Aug 18 16:38:25 2016 -0500 Committer: Kihwal Lee <kih...@apache.org> Committed: Thu Aug 18 16:39:35 2016 -0500 ---------------------------------------------------------------------- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 3 ++ .../server/namenode/FSImageFormatPBINode.java | 17 ++++++-- .../hdfs/server/namenode/FSNamesystem.java | 3 +- .../hdfs/server/namenode/TestLeaseManager.java | 43 ++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hadoop/blob/61e1348f/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt ---------------------------------------------------------------------- diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index 0ff7bba..5ca44be 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -18,6 +18,9 @@ Release 2.7.4 - UNRELEASED HDFS-10691. FileDistribution fails in hdfs oiv command due to ArrayIndexOutOfBoundsException. (Yiqun Lin via aajisaka) + HDFS-10763. Open files can leak permanently due to inconsistent + lease update (kihwal) + Release 2.7.3 - UNRELEASED INCOMPATIBLE CHANGES http://git-wip-us.apache.org/repos/asf/hadoop/blob/61e1348f/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java ---------------------------------------------------------------------- diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java index dfd150a..ed941ef 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java @@ -220,11 +220,13 @@ public final class FSImageFormatPBINode { private final FSDirectory dir; private final FSNamesystem fsn; private final FSImageFormatProtobuf.Loader parent; + private final List<INodeFile> ucFiles; Loader(FSNamesystem fsn, final FSImageFormatProtobuf.Loader parent) { this.fsn = fsn; this.dir = fsn.dir; this.parent = parent; + this.ucFiles = new ArrayList<INodeFile>(); } void loadINodeDirectorySection(InputStream in) throws IOException { @@ -268,17 +270,25 @@ public final class FSImageFormatPBINode { * Load the under-construction files section, and update the lease map */ void loadFilesUnderConstructionSection(InputStream in) throws IOException { + // This section is consumed, but not actually used for restoring leases. while (true) { FileUnderConstructionEntry entry = FileUnderConstructionEntry .parseDelimitedFrom(in); if (entry == null) { break; } - // update the lease manager - INodeFile file = dir.getInode(entry.getInodeId()).asFile(); + } + + // Add a lease for each and every file under construction. + for (INodeFile file : ucFiles) { FileUnderConstructionFeature uc = file.getFileUnderConstructionFeature(); Preconditions.checkState(uc != null); // file must be under-construction - fsn.leaseManager.addLease(uc.getClientName(), entry.getFullPath()); + String path = file.getFullPathName(); + // Skip the deleted files in snapshot. This leaks UC inodes that are + // deleted from the current view. + if (path.startsWith("/")) { + fsn.leaseManager.addLease(uc.getClientName(), path); + } } } @@ -346,6 +356,7 @@ public final class FSImageFormatPBINode { // under-construction information if (f.hasFileUC()) { + ucFiles.add(file); INodeSection.FileUnderConstructionFeature uc = f.getFileUC(); file.toUnderConstruction(uc.getClientName(), uc.getClientMachine()); if (blocks.length > 0) { http://git-wip-us.apache.org/repos/asf/hadoop/blob/61e1348f/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java ---------------------------------------------------------------------- diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java index bef296a..3887ac3 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java @@ -4205,7 +4205,6 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean, throw new IOException("Cannot finalize file " + src + " because it is not under construction"); } - leaseManager.removeLease(uc.getClientName(), src); pendingFile.recordModification(latestSnapshot); @@ -4214,6 +4213,8 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean, // since we just remove the uc feature from pendingFile pendingFile.toCompleteFile(now()); + leaseManager.removeLease(uc.getClientName(), src); + waitForLoadingFSImage(); // close file and persist block allocations for this file closeFile(src, pendingFile); http://git-wip-us.apache.org/repos/asf/hadoop/blob/61e1348f/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestLeaseManager.java ---------------------------------------------------------------------- diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestLeaseManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestLeaseManager.java index 2f114a7..570a5a5 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestLeaseManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestLeaseManager.java @@ -21,9 +21,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.Path; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hdfs.DistributedFileSystem; import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction; import org.junit.Test; import org.mockito.Mockito; @@ -81,4 +85,43 @@ public class TestLeaseManager { //Initiate a call to checkLease. This should exit within the test timeout lm.checkLeases(); } + + /** + * Make sure the lease is restored even if only the inode has the record. + */ + @Test + public void testLeaseRestorationOnRestart() throws Exception { + MiniDFSCluster cluster = null; + try { + cluster = new MiniDFSCluster.Builder(new HdfsConfiguration()) + .numDataNodes(1).build(); + DistributedFileSystem dfs = cluster.getFileSystem(); + + // Create an empty file + String path = "/testLeaseRestorationOnRestart"; + FSDataOutputStream out = dfs.create(new Path(path)); + + // Remove the lease from the lease manager, but leave it in the inode. + FSDirectory dir = cluster.getNamesystem().getFSDirectory(); + INodeFile file = dir.getINode(path).asFile(); + cluster.getNamesystem().leaseManager.removeLease( + file.getFileUnderConstructionFeature().getClientName(), path); + + // Save a fsimage. + dfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); + cluster.getNameNodeRpc().saveNamespace(); + dfs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); + + // Restart the namenode. + cluster.restartNameNode(true); + + // Check whether the lease manager has the lease + assertNotNull("Lease should exist", + cluster.getNamesystem().leaseManager.getLeaseByPath(path)); + } finally { + if (cluster != null) { + cluster.shutdown(); + } + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org For additional commands, e-mail: common-commits-h...@hadoop.apache.org