HDFS-15703. Don't generate edits for set operations that are no-op (#2508). Contributed by Daryn Sharp and Ahmed Hussein

This commit is contained in:
Ahmed Hussein 2020-12-02 15:38:20 -06:00 committed by GitHub
parent 2b5b556dd7
commit 60201cbf69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 7 deletions

View File

@ -56,15 +56,18 @@ static FileStatus setPermission(
throw new InvalidPathException(src); throw new InvalidPathException(src);
} }
INodesInPath iip; INodesInPath iip;
boolean changed;
fsd.writeLock(); fsd.writeLock();
try { try {
iip = fsd.resolvePath(pc, src, DirOp.WRITE); iip = fsd.resolvePath(pc, src, DirOp.WRITE);
fsd.checkOwner(pc, iip); fsd.checkOwner(pc, iip);
unprotectedSetPermission(fsd, iip, permission); changed = unprotectedSetPermission(fsd, iip, permission);
} finally { } finally {
fsd.writeUnlock(); fsd.writeUnlock();
} }
fsd.getEditLog().logSetPermissions(iip.getPath(), permission); if (changed) {
fsd.getEditLog().logSetPermissions(iip.getPath(), permission);
}
return fsd.getAuditFileInfo(iip); return fsd.getAuditFileInfo(iip);
} }
@ -75,6 +78,7 @@ static FileStatus setOwner(
throw new InvalidPathException(src); throw new InvalidPathException(src);
} }
INodesInPath iip; INodesInPath iip;
boolean changed;
fsd.writeLock(); fsd.writeLock();
try { try {
iip = fsd.resolvePath(pc, src, DirOp.WRITE); iip = fsd.resolvePath(pc, src, DirOp.WRITE);
@ -89,11 +93,13 @@ static FileStatus setOwner(
"User " + pc.getUser() + " does not belong to " + group); "User " + pc.getUser() + " does not belong to " + group);
} }
} }
unprotectedSetOwner(fsd, iip, username, group); changed = unprotectedSetOwner(fsd, iip, username, group);
} finally { } finally {
fsd.writeUnlock(); fsd.writeUnlock();
} }
fsd.getEditLog().logSetOwner(iip.getPath(), username, group); if (changed) {
fsd.getEditLog().logSetOwner(iip.getPath(), username, group);
}
return fsd.getAuditFileInfo(iip); return fsd.getAuditFileInfo(iip);
} }
@ -257,28 +263,32 @@ static void setQuota(FSDirectory fsd, FSPermissionChecker pc, String src,
} }
} }
static void unprotectedSetPermission( static boolean unprotectedSetPermission(
FSDirectory fsd, INodesInPath iip, FsPermission permissions) FSDirectory fsd, INodesInPath iip, FsPermission permissions)
throws FileNotFoundException, UnresolvedLinkException, throws FileNotFoundException, UnresolvedLinkException,
QuotaExceededException, SnapshotAccessControlException { QuotaExceededException, SnapshotAccessControlException {
assert fsd.hasWriteLock(); assert fsd.hasWriteLock();
final INode inode = FSDirectory.resolveLastINode(iip); final INode inode = FSDirectory.resolveLastINode(iip);
int snapshotId = iip.getLatestSnapshotId(); int snapshotId = iip.getLatestSnapshotId();
long oldPerm = inode.getPermissionLong();
inode.setPermission(permissions, snapshotId); inode.setPermission(permissions, snapshotId);
return oldPerm != inode.getPermissionLong();
} }
static void unprotectedSetOwner( static boolean unprotectedSetOwner(
FSDirectory fsd, INodesInPath iip, String username, String groupname) FSDirectory fsd, INodesInPath iip, String username, String groupname)
throws FileNotFoundException, UnresolvedLinkException, throws FileNotFoundException, UnresolvedLinkException,
QuotaExceededException, SnapshotAccessControlException { QuotaExceededException, SnapshotAccessControlException {
assert fsd.hasWriteLock(); assert fsd.hasWriteLock();
final INode inode = FSDirectory.resolveLastINode(iip); final INode inode = FSDirectory.resolveLastINode(iip);
long oldPerm = inode.getPermissionLong();
if (username != null) { if (username != null) {
inode.setUser(username, iip.getLatestSnapshotId()); inode.setUser(username, iip.getLatestSnapshotId());
} }
if (groupname != null) { if (groupname != null) {
inode.setGroup(groupname, iip.getLatestSnapshotId()); inode.setGroup(groupname, iip.getLatestSnapshotId());
} }
return oldPerm != inode.getPermissionLong();
} }
static boolean setTimes( static boolean setTimes(

View File

@ -20,8 +20,10 @@
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.PermissionStatus;
import org.apache.hadoop.hdfs.DFSUtil;
import org.apache.hadoop.hdfs.protocol.QuotaExceededException; import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager; import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -57,6 +59,54 @@ private boolean unprotectedSetTimes(long atime, long atime0, long precision,
return FSDirAttrOp.unprotectedSetTimes(fsd, iip, mtime, atime, force); return FSDirAttrOp.unprotectedSetTimes(fsd, iip, mtime, atime, force);
} }
private boolean unprotectedSetAttributes(short currPerm, short newPerm)
throws Exception {
return unprotectedSetAttributes(currPerm, newPerm, "user1", "user1",
false);
}
private boolean unprotectedSetAttributes(short currPerm, short newPerm,
String currUser, String newUser, boolean testChangeOwner)
throws Exception {
String groupName = "testGroup";
FsPermission originalPerm = new FsPermission(currPerm);
FsPermission updatedPerm = new FsPermission(newPerm);
FSNamesystem fsn = Mockito.mock(FSNamesystem.class);
SnapshotManager ssMgr = Mockito.mock(SnapshotManager.class);
FSDirectory fsd = Mockito.mock(FSDirectory.class);
INodesInPath iip = Mockito.mock(INodesInPath.class);
when(fsd.getFSNamesystem()).thenReturn(fsn);
when(fsn.getSnapshotManager()).thenReturn(ssMgr);
when(ssMgr.getSkipCaptureAccessTimeOnlyChange()).thenReturn(false);
when(fsd.getAccessTimePrecision()).thenReturn(1000L);
when(fsd.hasWriteLock()).thenReturn(Boolean.TRUE);
when(iip.getLatestSnapshotId()).thenReturn(0);
INode inode = new INodeDirectory(1000, DFSUtil.string2Bytes(""),
new PermissionStatus(currUser, "testGroup", originalPerm), 0L);
when(iip.getLastINode()).thenReturn(inode);
return testChangeOwner ? FSDirAttrOp.unprotectedSetOwner(fsd, iip, newUser,
groupName) : FSDirAttrOp.unprotectedSetPermission(fsd, iip,
updatedPerm);
}
@Test
public void testUnprotectedSetPermissions() throws Exception {
assertTrue("setPermissions return true for updated permissions",
unprotectedSetAttributes((short) 0777, (short) 0));
assertFalse("setPermissions should return false for same permissions",
unprotectedSetAttributes((short) 0777, (short) 0777));
}
@Test
public void testUnprotectedSetOwner() throws Exception {
assertTrue("SetOwner should return true for a new user",
unprotectedSetAttributes((short) 0777, (short) 0777, "user1",
"user2", true));
assertFalse("SetOwner should return false for same user",
unprotectedSetAttributes((short) 0777, (short) 0777, "user1",
"user1", true));
}
@Test @Test
public void testUnprotectedSetTimes() throws Exception { public void testUnprotectedSetTimes() throws Exception {
// atime < access time + precision // atime < access time + precision