HDFS-4112. A few improvements on INodeDirectory include adding a utility method for casting; avoiding creation of new empty lists; cleaning up some code and rewriting some javadoc.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1402599 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2d74f68054
commit
0e796b61e8
|
@ -421,6 +421,10 @@ Release 2.0.3-alpha - Unreleased
|
|||
HDFS-4107. Add utility methods for casting INode to INodeFile and
|
||||
INodeFileUnderConstruction. (szetszwo)
|
||||
|
||||
HDFS-4112. A few improvements on INodeDirectory include adding a utility
|
||||
method for casting; avoiding creation of new empty lists; cleaning up
|
||||
some code and rewriting some javadoc. (szetszwo)
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
BUG FIXES
|
||||
|
|
|
@ -696,7 +696,7 @@ public class FSDirectory implements Closeable {
|
|||
throw new FileAlreadyExistsException(error);
|
||||
}
|
||||
List<INode> children = dstInode.isDirectory() ?
|
||||
((INodeDirectory) dstInode).getChildrenRaw() : null;
|
||||
((INodeDirectory) dstInode).getChildren() : null;
|
||||
if (children != null && children.size() != 0) {
|
||||
error = "rename cannot overwrite non empty destination directory "
|
||||
+ dst;
|
||||
|
@ -1019,35 +1019,21 @@ public class FSDirectory implements Closeable {
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Return if a directory is empty or not **/
|
||||
boolean isDirEmpty(String src) throws UnresolvedLinkException {
|
||||
boolean dirNotEmpty = true;
|
||||
if (!isDir(src)) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @return true if the path is a non-empty directory; otherwise, return false.
|
||||
*/
|
||||
boolean isNonEmptyDirectory(String path) throws UnresolvedLinkException {
|
||||
readLock();
|
||||
try {
|
||||
INode targetNode = rootDir.getNode(src, false);
|
||||
assert targetNode != null : "should be taken care in isDir() above";
|
||||
if (((INodeDirectory)targetNode).getChildren().size() != 0) {
|
||||
dirNotEmpty = false;
|
||||
final INode inode = rootDir.getNode(path, false);
|
||||
if (inode == null || !inode.isDirectory()) {
|
||||
//not found or not a directory
|
||||
return false;
|
||||
}
|
||||
return ((INodeDirectory)inode).getChildrenList().size() != 0;
|
||||
} finally {
|
||||
readUnlock();
|
||||
}
|
||||
return dirNotEmpty;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
try {
|
||||
return isDirEmpty("/");
|
||||
} catch (UnresolvedLinkException e) {
|
||||
if(NameNode.stateChangeLog.isDebugEnabled()) {
|
||||
NameNode.stateChangeLog.debug("/ cannot be a symlink");
|
||||
}
|
||||
assert false : "/ cannot be a symlink";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1171,7 +1157,7 @@ public class FSDirectory implements Closeable {
|
|||
targetNode, needLocation)}, 0);
|
||||
}
|
||||
INodeDirectory dirInode = (INodeDirectory)targetNode;
|
||||
List<INode> contents = dirInode.getChildren();
|
||||
List<INode> contents = dirInode.getChildrenList();
|
||||
int startChild = dirInode.nextChild(startAfter);
|
||||
int totalNumChildren = contents.size();
|
||||
int numOfListing = Math.min(totalNumChildren-startChild, this.lsLimit);
|
||||
|
@ -1683,7 +1669,7 @@ public class FSDirectory implements Closeable {
|
|||
}
|
||||
if (maxDirItems != 0) {
|
||||
INodeDirectory parent = (INodeDirectory)pathComponents[pos-1];
|
||||
int count = parent.getChildren().size();
|
||||
int count = parent.getChildrenList().size();
|
||||
if (count >= maxDirItems) {
|
||||
throw new MaxDirectoryItemsExceededException(maxDirItems, count);
|
||||
}
|
||||
|
@ -1832,7 +1818,7 @@ public class FSDirectory implements Closeable {
|
|||
* INode. using 'parent' is not currently recommended. */
|
||||
nodesInPath.add(dir);
|
||||
|
||||
for (INode child : dir.getChildren()) {
|
||||
for (INode child : dir.getChildrenList()) {
|
||||
if (child.isDirectory()) {
|
||||
updateCountForINodeWithQuota((INodeDirectory)child,
|
||||
counts, nodesInPath);
|
||||
|
|
|
@ -246,10 +246,8 @@ class FSImageFormat {
|
|||
private int loadDirectory(DataInputStream in) throws IOException {
|
||||
String parentPath = FSImageSerialization.readString(in);
|
||||
FSDirectory fsDir = namesystem.dir;
|
||||
INode parent = fsDir.rootDir.getNode(parentPath, true);
|
||||
if (parent == null || !parent.isDirectory()) {
|
||||
throw new IOException("Path " + parentPath + "is not a directory.");
|
||||
}
|
||||
final INodeDirectory parent = INodeDirectory.valueOf(
|
||||
fsDir.rootDir.getNode(parentPath, true), parentPath);
|
||||
|
||||
int numChildren = in.readInt();
|
||||
for(int i=0; i<numChildren; i++) {
|
||||
|
@ -259,7 +257,7 @@ class FSImageFormat {
|
|||
INode newNode = loadINode(in); // read rest of inode
|
||||
|
||||
// add to parent
|
||||
namesystem.dir.addToParent(localName, (INodeDirectory)parent, newNode, false);
|
||||
namesystem.dir.addToParent(localName, parent, newNode, false);
|
||||
}
|
||||
return numChildren;
|
||||
}
|
||||
|
@ -532,7 +530,7 @@ class FSImageFormat {
|
|||
private void saveImage(ByteBuffer currentDirName,
|
||||
INodeDirectory current,
|
||||
DataOutputStream out) throws IOException {
|
||||
List<INode> children = current.getChildrenRaw();
|
||||
List<INode> children = current.getChildren();
|
||||
if (children == null || children.isEmpty())
|
||||
return;
|
||||
// print prefix (parent directory name)
|
||||
|
|
|
@ -2676,7 +2676,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
|||
if (isInSafeMode()) {
|
||||
throw new SafeModeException("Cannot delete " + src, safeMode);
|
||||
}
|
||||
if (!recursive && !dir.isDirEmpty(src)) {
|
||||
if (!recursive && dir.isNonEmptyDirectory(src)) {
|
||||
throw new IOException(src + " is non empty");
|
||||
}
|
||||
if (enforcePermission && isPermissionEnabled) {
|
||||
|
|
|
@ -173,7 +173,7 @@ class FSPermissionChecker {
|
|||
INodeDirectory d = directories.pop();
|
||||
check(d, access);
|
||||
|
||||
for(INode child : d.getChildren()) {
|
||||
for(INode child : d.getChildrenList()) {
|
||||
if (child.isDirectory()) {
|
||||
directories.push((INodeDirectory)child);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
*/
|
||||
package org.apache.hadoop.hdfs.server.namenode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
|
@ -39,7 +41,8 @@ import com.google.common.primitives.SignedBytes;
|
|||
*/
|
||||
@InterfaceAudience.Private
|
||||
abstract class INode implements Comparable<byte[]> {
|
||||
/*
|
||||
static final List<INode> EMPTY_LIST = Collections.unmodifiableList(new ArrayList<INode>());
|
||||
/**
|
||||
* The inode name is in java UTF8 encoding;
|
||||
* The name in HdfsFileStatus should keep the same encoding as this.
|
||||
* if this encoding is changed, implicitly getFileInfo and listStatus in
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.hadoop.hdfs.server.namenode;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -32,6 +33,18 @@ import org.apache.hadoop.hdfs.protocol.UnresolvedPathException;
|
|||
* Directory INode class.
|
||||
*/
|
||||
class INodeDirectory extends INode {
|
||||
/** Cast INode to INodeDirectory. */
|
||||
public static INodeDirectory valueOf(INode inode, String path
|
||||
) throws IOException {
|
||||
if (inode == null) {
|
||||
throw new IOException("Directory does not exist: " + path);
|
||||
}
|
||||
if (!inode.isDirectory()) {
|
||||
throw new IOException("Path is not a directory: " + path);
|
||||
}
|
||||
return (INodeDirectory)inode;
|
||||
}
|
||||
|
||||
protected static final int DEFAULT_FILES_PER_DIRECTORY = 5;
|
||||
final static String ROOT_NAME = "";
|
||||
|
||||
|
@ -112,11 +125,11 @@ class INodeDirectory extends INode {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the INode of the last component in components, or null if the last
|
||||
* @return the INode of the last component in components, or null if the last
|
||||
* component does not exist.
|
||||
*/
|
||||
private INode getNode(byte[][] components, boolean resolveLink)
|
||||
throws UnresolvedLinkException {
|
||||
private INode getNode(byte[][] components, boolean resolveLink
|
||||
) throws UnresolvedLinkException {
|
||||
INode[] inode = new INode[1];
|
||||
getExistingPathINodes(components, inode, resolveLink);
|
||||
return inode[0];
|
||||
|
@ -299,10 +312,7 @@ class INodeDirectory extends INode {
|
|||
<T extends INode> T addNode(String path, T newNode
|
||||
) throws FileNotFoundException, UnresolvedLinkException {
|
||||
byte[][] pathComponents = getPathComponents(path);
|
||||
if(addToParent(pathComponents, newNode,
|
||||
true) == null)
|
||||
return null;
|
||||
return newNode;
|
||||
return addToParent(pathComponents, newNode, true) == null? null: newNode;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,10 +336,9 @@ class INodeDirectory extends INode {
|
|||
return parent;
|
||||
}
|
||||
|
||||
INodeDirectory getParent(byte[][] pathComponents)
|
||||
throws FileNotFoundException, UnresolvedLinkException {
|
||||
int pathLen = pathComponents.length;
|
||||
if (pathLen < 2) // add root
|
||||
INodeDirectory getParent(byte[][] pathComponents
|
||||
) throws FileNotFoundException, UnresolvedLinkException {
|
||||
if (pathComponents.length < 2) // add root
|
||||
return null;
|
||||
// Gets the parent INode
|
||||
INode[] inodes = new INode[2];
|
||||
|
@ -355,21 +364,15 @@ class INodeDirectory extends INode {
|
|||
* @throws FileNotFoundException if parent does not exist or
|
||||
* is not a directory.
|
||||
*/
|
||||
INodeDirectory addToParent( byte[][] pathComponents,
|
||||
INode newNode,
|
||||
boolean propagateModTime
|
||||
) throws FileNotFoundException,
|
||||
UnresolvedLinkException {
|
||||
|
||||
int pathLen = pathComponents.length;
|
||||
if (pathLen < 2) // add root
|
||||
INodeDirectory addToParent(byte[][] pathComponents, INode newNode,
|
||||
boolean propagateModTime) throws FileNotFoundException, UnresolvedLinkException {
|
||||
if (pathComponents.length < 2) { // add root
|
||||
return null;
|
||||
newNode.name = pathComponents[pathLen-1];
|
||||
}
|
||||
newNode.name = pathComponents[pathComponents.length - 1];
|
||||
// insert into the parent children list
|
||||
INodeDirectory parent = getParent(pathComponents);
|
||||
if(parent.addChild(newNode, propagateModTime) == null)
|
||||
return null;
|
||||
return parent;
|
||||
return parent.addChild(newNode, propagateModTime) == null? null: parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -415,11 +418,15 @@ class INodeDirectory extends INode {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return an empty list if the children list is null;
|
||||
* otherwise, return the children list.
|
||||
* The returned list should not be modified.
|
||||
*/
|
||||
List<INode> getChildren() {
|
||||
return children==null ? new ArrayList<INode>() : children;
|
||||
public List<INode> getChildrenList() {
|
||||
return children==null ? EMPTY_LIST : children;
|
||||
}
|
||||
List<INode> getChildrenRaw() {
|
||||
/** @return the children list which is possibly null. */
|
||||
public List<INode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,14 @@ public class TestINodeFile {
|
|||
} catch(FileNotFoundException fnfe) {
|
||||
assertTrue(fnfe.getMessage().contains("File does not exist"));
|
||||
}
|
||||
|
||||
//cast to INodeDirectory, should fail
|
||||
try {
|
||||
INodeDirectory.valueOf(from, path);
|
||||
fail();
|
||||
} catch(IOException ioe) {
|
||||
assertTrue(ioe.getMessage().contains("Directory does not exist"));
|
||||
}
|
||||
}
|
||||
|
||||
{//cast from INodeFile
|
||||
|
@ -251,6 +259,14 @@ public class TestINodeFile {
|
|||
} catch(IOException ioe) {
|
||||
assertTrue(ioe.getMessage().contains("File is not under construction"));
|
||||
}
|
||||
|
||||
//cast to INodeDirectory, should fail
|
||||
try {
|
||||
INodeDirectory.valueOf(from, path);
|
||||
fail();
|
||||
} catch(IOException ioe) {
|
||||
assertTrue(ioe.getMessage().contains("Path is not a directory"));
|
||||
}
|
||||
}
|
||||
|
||||
{//cast from INodeFileUnderConstruction
|
||||
|
@ -265,6 +281,14 @@ public class TestINodeFile {
|
|||
final INodeFileUnderConstruction u = INodeFileUnderConstruction.valueOf(
|
||||
from, path);
|
||||
assertTrue(u == from);
|
||||
|
||||
//cast to INodeDirectory, should fail
|
||||
try {
|
||||
INodeDirectory.valueOf(from, path);
|
||||
fail();
|
||||
} catch(IOException ioe) {
|
||||
assertTrue(ioe.getMessage().contains("Path is not a directory"));
|
||||
}
|
||||
}
|
||||
|
||||
{//cast from INodeDirectory
|
||||
|
@ -285,6 +309,10 @@ public class TestINodeFile {
|
|||
} catch(FileNotFoundException fnfe) {
|
||||
assertTrue(fnfe.getMessage().contains("Path is not a file"));
|
||||
}
|
||||
|
||||
//cast to INodeDirectory, should success
|
||||
final INodeDirectory d = INodeDirectory.valueOf(from, path);
|
||||
assertTrue(d == from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue