Author: cnauroth Date: Fri May 16 06:06:11 2014 New Revision: 1595113 URL: http://svn.apache.org/r1595113 Log: HDFS-6414. xattr modification operations are based on state of latest snapshot instead of current version of inode. Contributed by Andrew Wang.
Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/XAttrStorage.java hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt?rev=1595113&r1=1595112&r2=1595113&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-2006.txt Fri May 16 06:06:11 2014 @@ -64,3 +64,6 @@ HDFS-2006 (Unreleased) HDFS-6413. xattr names erroneously handled as case-insensitive. (Charles Lamb via cnauroth) + + HDFS-6414. xattr modification operations are based on state of latest + snapshot instead of current version of inode. (Andrew Wang via cnauroth) Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/XAttrStorage.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/XAttrStorage.java?rev=1595113&r1=1595112&r2=1595113&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/XAttrStorage.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/XAttrStorage.java Fri May 16 06:06:11 2014 @@ -60,21 +60,21 @@ public class XAttrStorage { * Update xattrs of inode. * @param inode INode to update * @param xAttrs to update xAttrs. - * @param snapshotId + * @param snapshotId id of the latest snapshot of the inode */ public static void updateINodeXAttrs(INode inode, List<XAttr> xAttrs, int snapshotId) throws QuotaExceededException { if (xAttrs == null || xAttrs.isEmpty()) { - if (inode.getXAttrFeature(snapshotId) != null) { + if (inode.getXAttrFeature() != null) { inode.removeXAttrFeature(snapshotId); } return; } ImmutableList<XAttr> newXAttrs = ImmutableList.copyOf(xAttrs); - if (inode.getXAttrFeature(snapshotId) != null) { + if (inode.getXAttrFeature() != null) { inode.removeXAttrFeature(snapshotId); } - inode.addXAttrFeature(new XAttrFeature(newXAttrs)); + inode.addXAttrFeature(new XAttrFeature(newXAttrs), snapshotId); } } Modified: hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java?rev=1595113&r1=1595112&r2=1595113&view=diff ============================================================================== --- hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java (original) +++ hadoop/common/branches/HDFS-2006/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/snapshot/TestXAttrWithSnapshot.java Fri May 16 06:06:11 2014 @@ -18,11 +18,16 @@ package org.apache.hadoop.hdfs.server.namenode.snapshot; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.util.EnumSet; import java.util.Map; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.XAttrSetFlag; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DistributedFileSystem; @@ -86,6 +91,80 @@ public class TestXAttrWithSnapshot { } /** + * Tests modifying xattrs on a directory that has been snapshotted + */ + @Test (timeout = 120000) + public void testModifyReadsCurrentState() throws Exception { + // Init + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700)); + SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName); + hdfs.setXAttr(path, name1, value1); + hdfs.setXAttr(path, name2, value2); + + // Verify that current path reflects xattrs, snapshot doesn't + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 2); + assertArrayEquals(value1, xattrs.get(name1)); + assertArrayEquals(value2, xattrs.get(name2)); + + xattrs = hdfs.getXAttrs(snapshotPath); + assertEquals(xattrs.size(), 0); + + // Modify each xattr and make sure it's reflected + hdfs.setXAttr(path, name1, value2, EnumSet.of(XAttrSetFlag.REPLACE)); + xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 2); + assertArrayEquals(value2, xattrs.get(name1)); + assertArrayEquals(value2, xattrs.get(name2)); + + hdfs.setXAttr(path, name2, value1, EnumSet.of(XAttrSetFlag.REPLACE)); + xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 2); + assertArrayEquals(value2, xattrs.get(name1)); + assertArrayEquals(value1, xattrs.get(name2)); + + // Paranoia checks + xattrs = hdfs.getXAttrs(snapshotPath); + assertEquals(xattrs.size(), 0); + + hdfs.removeXAttr(path, name1); + hdfs.removeXAttr(path, name2); + xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 0); + } + + /** + * Tests removing xattrs on a directory that has been snapshotted + */ + @Test (timeout = 120000) + public void testRemoveReadsCurrentState() throws Exception { + // Init + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0700)); + SnapshotTestHelper.createSnapshot(hdfs, path, snapshotName); + hdfs.setXAttr(path, name1, value1); + hdfs.setXAttr(path, name2, value2); + + // Verify that current path reflects xattrs, snapshot doesn't + Map<String, byte[]> xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 2); + assertArrayEquals(value1, xattrs.get(name1)); + assertArrayEquals(value2, xattrs.get(name2)); + + xattrs = hdfs.getXAttrs(snapshotPath); + assertEquals(xattrs.size(), 0); + + // Remove xattrs and verify one-by-one + hdfs.removeXAttr(path, name2); + xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 1); + assertArrayEquals(value1, xattrs.get(name1)); + + hdfs.removeXAttr(path, name1); + xattrs = hdfs.getXAttrs(path); + assertEquals(xattrs.size(), 0); + } + + /** * 1) Save xattrs, then create snapshot. Assert that inode of original and * snapshot have same xattrs. 2) Change the original xattrs, assert snapshot * still has old xattrs. @@ -215,6 +294,25 @@ public class TestXAttrWithSnapshot { hdfs.setXAttr(filePath, name2, value2); } + + /** + * Test that an exception is thrown when adding an XAttr Feature to + * a snapshotted path + */ + @Test + public void testSetXAttrAfterSnapshotExceedsQuota() throws Exception { + Path filePath = new Path(path, "file1"); + FileSystem.mkdirs(hdfs, path, FsPermission.createImmutable((short) 0755)); + hdfs.allowSnapshot(path); + hdfs.setQuota(path, 3, HdfsConstants.QUOTA_DONT_SET); + FileSystem.create(hdfs, filePath, + FsPermission.createImmutable((short) 0600)).close(); + hdfs.createSnapshot(path, snapshotName); + // This adds an XAttr feature, which can throw an exception + exception.expect(NSQuotaExceededException.class); + hdfs.setXAttr(filePath, name1, value1); + } + /** * Assert exception of removing xattr when exceeding quota. */