HDFS-10763. Open files can leak permanently due to inconsistent lease update. Contributed by Kihwal Lee.
This commit is contained in:
parent
7519956c30
commit
71d0e4fca7
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue