HDFS-10763. Open files can leak permanently due to inconsistent lease update. Contributed by Kihwal Lee.

This commit is contained in:
Kihwal Lee 2016-08-15 17:40:07 -05:00
parent 7519956c30
commit 71d0e4fca7
4 changed files with 57 additions and 4 deletions

View File

@ -255,6 +255,9 @@ Release 2.7.3 - UNRELEASED
HDFS-9696. Garbage snapshot records linger forever. (kihwal)
HDFS-10763. Open files can leak permanently due to inconsistent lease
update. (kihwal)
Release 2.7.2 - 2016-01-25
INCOMPATIBLE CHANGES

View File

@ -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,20 @@ 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());
fsn.leaseManager.addLease(uc.getClientName(), file.getFullPathName());
}
}
@ -346,6 +351,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) {

View File

@ -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);

View File

@ -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();
}
}
}
}