Skip to content

Commit ed2a4db

Browse files
committed
HDFS-7385. ThreadLocal used in FSEditLog class causes FSImage permission mess up. Contributed by jiangyu.
(cherry picked from commit b0a41de) (cherry picked from commit 4e90015)
1 parent 4e9b46d commit ed2a4db

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
@@ -1023,6 +1023,9 @@ Release 2.6.0 - 2014-11-15
10231023

10241024
HDFS-7391. Renable SSLv2Hello in HttpFS. (rkanter via acmurthy)
10251025

1026+
HDFS-7385. ThreadLocal used in FSEditLog class causes FSImage permission mess
1027+
up. (jiangyu via cnauroth)
1028+
10261029
Release 2.5.2 - 2014-11-10
10271030

10281031
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
@@ -421,6 +421,12 @@ private AddCloseOp(FSEditLogOpCodes opCode) {
421421
assert(opCode == OP_ADD || opCode == OP_CLOSE);
422422
}
423423

424+
<T extends AddCloseOp> T reset() {
425+
this.aclEntries = null;
426+
this.xAttrs = null;
427+
return (T)this;
428+
}
429+
424430
<T extends AddCloseOp> T setInodeId(long inodeId) {
425431
this.inodeId = inodeId;
426432
return (T)this;
@@ -1412,6 +1418,12 @@ static MkdirOp getInstance(OpInstanceCache cache) {
14121418
return (MkdirOp)cache.get(OP_MKDIR);
14131419
}
14141420

1421+
MkdirOp reset() {
1422+
this.aclEntries = null;
1423+
this.xAttrs = null;
1424+
return this;
1425+
}
1426+
14151427
MkdirOp setInodeId(long inodeId) {
14161428
this.inodeId = inodeId;
14171429
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;
@@ -1499,4 +1505,65 @@ public void testManyEditLogSegments() throws IOException {
14991505
LOG.info(String.format("loaded %d edit log segments in %.2f seconds",
15001506
NUM_EDIT_LOG_ROLLS, delta));
15011507
}
1508+
1509+
/**
1510+
* Edit log op instances are cached internally using thread-local storage.
1511+
* This test checks that the cached instances are reset in between different
1512+
* transactions processed on the same thread, so that we don't accidentally
1513+
* apply incorrect attributes to an inode.
1514+
*
1515+
* @throws IOException if there is an I/O error
1516+
*/
1517+
@Test
1518+
public void testResetThreadLocalCachedOps() throws IOException {
1519+
Configuration conf = new HdfsConfiguration();
1520+
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
1521+
// Set single handler thread, so all transactions hit same thread-local ops.
1522+
conf.setInt(DFSConfigKeys.DFS_NAMENODE_HANDLER_COUNT_KEY, 1);
1523+
MiniDFSCluster cluster = null;
1524+
FileSystem fileSys = null;
1525+
try {
1526+
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
1527+
cluster.waitActive();
1528+
fileSys = cluster.getFileSystem();
1529+
1530+
// Create /dir1 with a default ACL.
1531+
Path dir1 = new Path("/dir1");
1532+
fileSys.mkdirs(dir1);
1533+
List<AclEntry> aclSpec = Lists.newArrayList(
1534+
aclEntry(DEFAULT, USER, "foo", READ_EXECUTE));
1535+
fileSys.modifyAclEntries(dir1, aclSpec);
1536+
1537+
// /dir1/dir2 is expected to clone the default ACL.
1538+
Path dir2 = new Path("/dir1/dir2");
1539+
fileSys.mkdirs(dir2);
1540+
1541+
// /dir1/file1 is expected to clone the default ACL.
1542+
Path file1 = new Path("/dir1/file1");
1543+
fileSys.create(file1).close();
1544+
1545+
// /dir3 is not a child of /dir1, so must not clone the default ACL.
1546+
Path dir3 = new Path("/dir3");
1547+
fileSys.mkdirs(dir3);
1548+
1549+
// /file2 is not a child of /dir1, so must not clone the default ACL.
1550+
Path file2 = new Path("/file2");
1551+
fileSys.create(file2).close();
1552+
1553+
// Restart and assert the above stated expectations.
1554+
IOUtils.cleanup(LOG, fileSys);
1555+
cluster.restartNameNode();
1556+
fileSys = cluster.getFileSystem();
1557+
assertFalse(fileSys.getAclStatus(dir1).getEntries().isEmpty());
1558+
assertFalse(fileSys.getAclStatus(dir2).getEntries().isEmpty());
1559+
assertFalse(fileSys.getAclStatus(file1).getEntries().isEmpty());
1560+
assertTrue(fileSys.getAclStatus(dir3).getEntries().isEmpty());
1561+
assertTrue(fileSys.getAclStatus(file2).getEntries().isEmpty());
1562+
} finally {
1563+
IOUtils.cleanup(LOG, fileSys);
1564+
if (cluster != null) {
1565+
cluster.shutdown();
1566+
}
1567+
}
1568+
}
15021569
}

0 commit comments

Comments
 (0)