|
@@ -19,6 +19,7 @@
|
|
|
package org.apache.hadoop.hdfs.server.namenode;
|
|
|
|
|
|
import static org.apache.hadoop.hdfs.server.common.Util.fileAsURI;
|
|
|
+import static org.apache.hadoop.util.Time.now;
|
|
|
import static org.junit.Assert.assertEquals;
|
|
|
import static org.mockito.Matchers.anyObject;
|
|
|
import static org.mockito.Mockito.mock;
|
|
@@ -29,14 +30,15 @@ import java.io.IOException;
|
|
|
|
|
|
import org.apache.hadoop.HadoopIllegalArgumentException;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.fs.Options.Rename;
|
|
|
import org.apache.hadoop.fs.permission.FsPermission;
|
|
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
|
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
|
|
-import org.apache.hadoop.hdfs.DFSUtil;
|
|
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
|
|
import org.apache.hadoop.hdfs.protocol.FSLimitException.MaxDirectoryItemsExceededException;
|
|
|
import org.apache.hadoop.hdfs.protocol.FSLimitException.PathComponentTooLongException;
|
|
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
|
|
+import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
|
|
|
import org.apache.hadoop.test.GenericTestUtils;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
@@ -50,7 +52,12 @@ public class TestFsLimits {
|
|
|
static PermissionStatus perms
|
|
|
= new PermissionStatus("admin", "admin", FsPermission.getDefault());
|
|
|
|
|
|
- static INodeDirectory rootInode;
|
|
|
+ static private FSImage getMockFSImage() {
|
|
|
+ FSEditLog editLog = mock(FSEditLog.class);
|
|
|
+ FSImage fsImage = mock(FSImage.class);
|
|
|
+ when(fsImage.getEditLog()).thenReturn(editLog);
|
|
|
+ return fsImage;
|
|
|
+ }
|
|
|
|
|
|
static private FSNamesystem getMockNamesystem() {
|
|
|
FSNamesystem fsn = mock(FSNamesystem.class);
|
|
@@ -64,8 +71,9 @@ public class TestFsLimits {
|
|
|
|
|
|
private static class MockFSDirectory extends FSDirectory {
|
|
|
public MockFSDirectory() throws IOException {
|
|
|
- super(new FSImage(conf), getMockNamesystem(), conf);
|
|
|
+ super(getMockFSImage(), getMockNamesystem(), conf);
|
|
|
setReady(fsIsReady);
|
|
|
+ NameNode.initMetrics(conf, NamenodeRole.NAMENODE);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -76,21 +84,18 @@ public class TestFsLimits {
|
|
|
fileAsURI(new File(MiniDFSCluster.getBaseDirectory(),
|
|
|
"namenode")).toString());
|
|
|
|
|
|
- rootInode = new INodeDirectory(getMockNamesystem().allocateNewInodeId(),
|
|
|
- INodeDirectory.ROOT_NAME, perms, 0L);
|
|
|
- inodes = new INode[]{ rootInode, null };
|
|
|
fs = null;
|
|
|
fsIsReady = true;
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void testNoLimits() throws Exception {
|
|
|
- addChildWithName("1", null);
|
|
|
- addChildWithName("22", null);
|
|
|
- addChildWithName("333", null);
|
|
|
- addChildWithName("4444", null);
|
|
|
- addChildWithName("55555", null);
|
|
|
- addChildWithName(HdfsConstants.DOT_SNAPSHOT_DIR,
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/22", null);
|
|
|
+ mkdirs("/333", null);
|
|
|
+ mkdirs("/4444", null);
|
|
|
+ mkdirs("/55555", null);
|
|
|
+ mkdirs("/1/" + HdfsConstants.DOT_SNAPSHOT_DIR,
|
|
|
HadoopIllegalArgumentException.class);
|
|
|
}
|
|
|
|
|
@@ -98,33 +103,65 @@ public class TestFsLimits {
|
|
|
public void testMaxComponentLength() throws Exception {
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_KEY, 2);
|
|
|
|
|
|
- addChildWithName("1", null);
|
|
|
- addChildWithName("22", null);
|
|
|
- addChildWithName("333", PathComponentTooLongException.class);
|
|
|
- addChildWithName("4444", PathComponentTooLongException.class);
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/22", null);
|
|
|
+ mkdirs("/333", PathComponentTooLongException.class);
|
|
|
+ mkdirs("/4444", PathComponentTooLongException.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testMaxComponentLengthRename() throws Exception {
|
|
|
+ conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_KEY, 2);
|
|
|
+
|
|
|
+ mkdirs("/5", null);
|
|
|
+ rename("/5", "/555", PathComponentTooLongException.class);
|
|
|
+ rename("/5", "/55", null);
|
|
|
+
|
|
|
+ mkdirs("/6", null);
|
|
|
+ deprecatedRename("/6", "/666", PathComponentTooLongException.class);
|
|
|
+ deprecatedRename("/6", "/66", null);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void testMaxDirItems() throws Exception {
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 2);
|
|
|
|
|
|
- addChildWithName("1", null);
|
|
|
- addChildWithName("22", null);
|
|
|
- addChildWithName("333", MaxDirectoryItemsExceededException.class);
|
|
|
- addChildWithName("4444", MaxDirectoryItemsExceededException.class);
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/22", null);
|
|
|
+ mkdirs("/333", MaxDirectoryItemsExceededException.class);
|
|
|
+ mkdirs("/4444", MaxDirectoryItemsExceededException.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testMaxDirItemsRename() throws Exception {
|
|
|
+ conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 2);
|
|
|
+
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/2", null);
|
|
|
+
|
|
|
+ mkdirs("/2/A", null);
|
|
|
+ rename("/2/A", "/A", MaxDirectoryItemsExceededException.class);
|
|
|
+ rename("/2/A", "/1/A", null);
|
|
|
+
|
|
|
+ mkdirs("/2/B", null);
|
|
|
+ deprecatedRename("/2/B", "/B", MaxDirectoryItemsExceededException.class);
|
|
|
+ deprecatedRename("/2/B", "/1/B", null);
|
|
|
+
|
|
|
+ rename("/1", "/3", null);
|
|
|
+ deprecatedRename("/2", "/4", null);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void testMaxDirItemsLimits() throws Exception {
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 0);
|
|
|
try {
|
|
|
- addChildWithName("1", null);
|
|
|
+ mkdirs("1", null);
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
GenericTestUtils.assertExceptionContains("Cannot set dfs", e);
|
|
|
}
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 64*100*1024);
|
|
|
try {
|
|
|
- addChildWithName("1", null);
|
|
|
+ mkdirs("1", null);
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
GenericTestUtils.assertExceptionContains("Cannot set dfs", e);
|
|
|
}
|
|
@@ -135,10 +172,10 @@ public class TestFsLimits {
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_COMPONENT_LENGTH_KEY, 3);
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 2);
|
|
|
|
|
|
- addChildWithName("1", null);
|
|
|
- addChildWithName("22", null);
|
|
|
- addChildWithName("333", MaxDirectoryItemsExceededException.class);
|
|
|
- addChildWithName("4444", PathComponentTooLongException.class);
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/22", null);
|
|
|
+ mkdirs("/333", MaxDirectoryItemsExceededException.class);
|
|
|
+ mkdirs("/4444", PathComponentTooLongException.class);
|
|
|
}
|
|
|
|
|
|
@Test
|
|
@@ -147,32 +184,55 @@ public class TestFsLimits {
|
|
|
conf.setInt(DFSConfigKeys.DFS_NAMENODE_MAX_DIRECTORY_ITEMS_KEY, 2);
|
|
|
fsIsReady = false;
|
|
|
|
|
|
- addChildWithName(HdfsConstants.DOT_SNAPSHOT_DIR,
|
|
|
+ mkdirs("/1", null);
|
|
|
+ mkdirs("/22", null);
|
|
|
+ mkdirs("/333", null);
|
|
|
+ mkdirs("/4444", null);
|
|
|
+ mkdirs("/1/" + HdfsConstants.DOT_SNAPSHOT_DIR,
|
|
|
HadoopIllegalArgumentException.class);
|
|
|
- addChildWithName("1", null);
|
|
|
- addChildWithName("22", null);
|
|
|
- addChildWithName("333", null);
|
|
|
- addChildWithName("4444", null);
|
|
|
}
|
|
|
|
|
|
- private void addChildWithName(String name, Class<?> expected)
|
|
|
+ private void mkdirs(String name, Class<?> expected)
|
|
|
throws Exception {
|
|
|
- // have to create after the caller has had a chance to set conf values
|
|
|
- if (fs == null) fs = new MockFSDirectory();
|
|
|
+ lazyInitFSDirectory();
|
|
|
+ Class<?> generated = null;
|
|
|
+ try {
|
|
|
+ fs.mkdirs(name, perms, false, now());
|
|
|
+ } catch (Throwable e) {
|
|
|
+ generated = e.getClass();
|
|
|
+ }
|
|
|
+ assertEquals(expected, generated);
|
|
|
+ }
|
|
|
|
|
|
- INode child = new INodeDirectory(getMockNamesystem().allocateNewInodeId(),
|
|
|
- DFSUtil.string2Bytes(name), perms, 0L);
|
|
|
-
|
|
|
+ private void rename(String src, String dst, Class<?> expected)
|
|
|
+ throws Exception {
|
|
|
+ lazyInitFSDirectory();
|
|
|
Class<?> generated = null;
|
|
|
try {
|
|
|
- fs.verifyMaxComponentLength(child.getLocalNameBytes(), inodes, 1);
|
|
|
- fs.verifyMaxDirItems(inodes, 1);
|
|
|
- fs.verifyINodeName(child.getLocalNameBytes());
|
|
|
+ fs.renameTo(src, dst, false, new Rename[] { });
|
|
|
+ } catch (Throwable e) {
|
|
|
+ generated = e.getClass();
|
|
|
+ }
|
|
|
+ assertEquals(expected, generated);
|
|
|
+ }
|
|
|
|
|
|
- rootInode.addChild(child);
|
|
|
+ @SuppressWarnings("deprecation")
|
|
|
+ private void deprecatedRename(String src, String dst, Class<?> expected)
|
|
|
+ throws Exception {
|
|
|
+ lazyInitFSDirectory();
|
|
|
+ Class<?> generated = null;
|
|
|
+ try {
|
|
|
+ fs.renameTo(src, dst, false);
|
|
|
} catch (Throwable e) {
|
|
|
generated = e.getClass();
|
|
|
}
|
|
|
assertEquals(expected, generated);
|
|
|
}
|
|
|
+
|
|
|
+ private static void lazyInitFSDirectory() throws IOException {
|
|
|
+ // have to create after the caller has had a chance to set conf values
|
|
|
+ if (fs == null) {
|
|
|
+ fs = new MockFSDirectory();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|