Skip to content

Commit b0a41de

Browse files
committed
HDFS-7385. ThreadLocal used in FSEditLog class causes FSImage permission mess up. Contributed by jiangyu.
1 parent 394ba94 commit b0a41de

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,9 @@ Release 2.6.0 - 2014-11-15
14461446

14471447
HDFS-7391. Renable SSLv2Hello in HttpFS. (rkanter via acmurthy)
14481448

1449+
HDFS-7385. ThreadLocal used in FSEditLog class causes FSImage permission mess
1450+
up. (jiangyu via cnauroth)
1451+
14491452
Release 2.5.2 - 2014-11-10
14501453

14511454
INCOMPATIBLE CHANGES

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLog.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ public void logOpenFile(String path, INodeFile newNode, boolean overwrite,
708708
Preconditions.checkArgument(newNode.isUnderConstruction());
709709
PermissionStatus permissions = newNode.getPermissionStatus();
710710
AddOp op = AddOp.getInstance(cache.get())
711+
.reset()
711712
.setInodeId(newNode.getId())
712713
.setPath(path)
713714
.setReplication(newNode.getFileReplication())
@@ -778,6 +779,7 @@ public void logUpdateBlocks(String path, INodeFile file, boolean toLogRpcIds) {
778779
public void logMkDir(String path, INode newNode) {
779780
PermissionStatus permissions = newNode.getPermissionStatus();
780781
MkdirOp op = MkdirOp.getInstance(cache.get())
782+
.reset()
781783
.setInodeId(newNode.getId())
782784
.setPath(path)
783785
.setTimestamp(newNode.getModificationTime())

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogOp.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ private AddCloseOp(FSEditLogOpCodes opCode) {
419419
assert(opCode == OP_ADD || opCode == OP_CLOSE);
420420
}
421421

422+
<T extends AddCloseOp> T reset() {
423+
this.aclEntries = null;
424+
this.xAttrs = null;
425+
return (T)this;
426+
}
427+
422428
<T extends AddCloseOp> T setInodeId(long inodeId) {
423429
this.inodeId = inodeId;
424430
return (T)this;
@@ -1410,6 +1416,12 @@ static MkdirOp getInstance(OpInstanceCache cache) {
14101416
return (MkdirOp)cache.get(OP_MKDIR);
14111417
}
14121418

1419+
MkdirOp reset() {
1420+
this.aclEntries = null;
1421+
this.xAttrs = null;
1422+
return this;
1423+
}
1424+
14131425
MkdirOp setInodeId(long inodeId) {
14141426
this.inodeId = inodeId;
14151427
return this;

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestEditLog.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
*/
1818
package org.apache.hadoop.hdfs.server.namenode;
1919

20+
import static org.apache.hadoop.fs.permission.AclEntryScope.*;
21+
import static org.apache.hadoop.fs.permission.AclEntryType.*;
22+
import static org.apache.hadoop.fs.permission.FsAction.*;
23+
import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.*;
2024
import static org.apache.hadoop.test.MetricsAsserts.assertCounter;
2125
import static org.apache.hadoop.test.MetricsAsserts.getMetrics;
2226
import static org.junit.Assert.assertEquals;
27+
import static org.junit.Assert.assertFalse;
2328
import static org.junit.Assert.assertNotNull;
2429
import static org.junit.Assert.assertTrue;
2530
import static org.junit.Assert.fail;
@@ -57,6 +62,7 @@
5762
import org.apache.hadoop.fs.FileSystem;
5863
import org.apache.hadoop.fs.FileUtil;
5964
import org.apache.hadoop.fs.Path;
65+
import org.apache.hadoop.fs.permission.AclEntry;
6066
import org.apache.hadoop.fs.permission.FsPermission;
6167
import org.apache.hadoop.fs.permission.PermissionStatus;
6268
import org.apache.hadoop.hdfs.DFSConfigKeys;
@@ -1501,4 +1507,65 @@ public void testManyEditLogSegments() throws IOException {
15011507
LOG.info(String.format("loaded %d edit log segments in %.2f seconds",
15021508
NUM_EDIT_LOG_ROLLS, delta));
15031509
}
1510+
1511+
/**
1512+
* Edit log op instances are cached internally using thread-local storage.
1513+
* This test checks that the cached instances are reset in between different
1514+
* transactions processed on the same thread, so that we don't accidentally
1515+
* apply incorrect attributes to an inode.
1516+
*
1517+
* @throws IOException if there is an I/O error
1518+
*/
1519+
@Test
1520+
public void testResetThreadLocalCachedOps() throws IOException {
1521+
Configuration conf = new HdfsConfiguration();
1522+
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
1523+
// Set single handler thread, so all transactions hit same thread-local ops.
1524+
conf.setInt(DFSConfigKeys.DFS_NAMENODE_HANDLER_COUNT_KEY, 1);
1525+
MiniDFSCluster cluster = null;
1526+
FileSystem fileSys = null;
1527+
try {
1528+
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
1529+
cluster.waitActive();
1530+
fileSys = cluster.getFileSystem();
1531+
1532+
// Create /dir1 with a default ACL.
1533+
Path dir1 = new Path("/dir1");
1534+
fileSys.mkdirs(dir1);
1535+
List<AclEntry> aclSpec = Lists.newArrayList(
1536+
aclEntry(DEFAULT, USER, "foo", READ_EXECUTE));
1537+
fileSys.modifyAclEntries(dir1, aclSpec);
1538+
1539+
// /dir1/dir2 is expected to clone the default ACL.
1540+
Path dir2 = new Path("/dir1/dir2");
1541+
fileSys.mkdirs(dir2);
1542+
1543+
// /dir1/file1 is expected to clone the default ACL.
1544+
Path file1 = new Path("/dir1/file1");
1545+
fileSys.create(file1).close();
1546+
1547+
// /dir3 is not a child of /dir1, so must not clone the default ACL.
1548+
Path dir3 = new Path("/dir3");
1549+
fileSys.mkdirs(dir3);
1550+
1551+
// /file2 is not a child of /dir1, so must not clone the default ACL.
1552+
Path file2 = new Path("/file2");
1553+
fileSys.create(file2).close();
1554+
1555+
// Restart and assert the above stated expectations.
1556+
IOUtils.cleanup(LOG, fileSys);
1557+
cluster.restartNameNode();
1558+
fileSys = cluster.getFileSystem();
1559+
assertFalse(fileSys.getAclStatus(dir1).getEntries().isEmpty());
1560+
assertFalse(fileSys.getAclStatus(dir2).getEntries().isEmpty());
1561+
assertFalse(fileSys.getAclStatus(file1).getEntries().isEmpty());
1562+
assertTrue(fileSys.getAclStatus(dir3).getEntries().isEmpty());
1563+
assertTrue(fileSys.getAclStatus(file2).getEntries().isEmpty());
1564+
} finally {
1565+
IOUtils.cleanup(LOG, fileSys);
1566+
if (cluster != null) {
1567+
cluster.shutdown();
1568+
}
1569+
}
1570+
}
15041571
}

0 commit comments

Comments
 (0)