HDFS-4507. Update quota verification for snapshots.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-2802@1451081 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e2a618e1cc
commit
c7cf85ccb4
|
@ -179,3 +179,5 @@ Branch-2802 Snapshot (Unreleased)
|
||||||
|
|
||||||
HDFS-4523. Fix INodeFile replacement, TestQuota and javac errors from trunk
|
HDFS-4523. Fix INodeFile replacement, TestQuota and javac errors from trunk
|
||||||
merge. (szetszwo)
|
merge. (szetszwo)
|
||||||
|
|
||||||
|
HDFS-4507. Update quota verification for snapshots. (szetszwo)
|
||||||
|
|
|
@ -20,7 +20,6 @@ package org.apache.hadoop.hdfs.protocol;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.fs.Path;
|
|
||||||
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
|
@ -48,21 +47,29 @@ public abstract class FSLimitException extends QuotaExceededException {
|
||||||
class PathComponentTooLongException extends FSLimitException {
|
class PathComponentTooLongException extends FSLimitException {
|
||||||
protected static final long serialVersionUID = 1L;
|
protected static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String childName;
|
||||||
|
|
||||||
protected PathComponentTooLongException() {}
|
protected PathComponentTooLongException() {}
|
||||||
|
|
||||||
protected PathComponentTooLongException(String msg) {
|
protected PathComponentTooLongException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PathComponentTooLongException(long quota, long count) {
|
public PathComponentTooLongException(long quota, long count,
|
||||||
|
String parentPath, String childName) {
|
||||||
super(quota, count);
|
super(quota, count);
|
||||||
|
setPathName(parentPath);
|
||||||
|
this.childName = childName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getParentPath() {
|
||||||
|
return pathName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
Path violator = new Path(pathName);
|
return "The maximum path component name limit of " + childName +
|
||||||
return "The maximum path component name limit of " + violator.getName() +
|
" in directory " + getParentPath() +
|
||||||
" in directory " + violator.getParent() +
|
|
||||||
" is exceeded: limit=" + quota + " length=" + count;
|
" is exceeded: limit=" + quota + " length=" + count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.apache.hadoop.classification.InterfaceStability;
|
||||||
public final class NSQuotaExceededException extends QuotaExceededException {
|
public final class NSQuotaExceededException extends QuotaExceededException {
|
||||||
protected static final long serialVersionUID = 1L;
|
protected static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
public NSQuotaExceededException() {}
|
public NSQuotaExceededException() {}
|
||||||
|
|
||||||
public NSQuotaExceededException(String msg) {
|
public NSQuotaExceededException(String msg) {
|
||||||
|
@ -40,11 +42,19 @@ public final class NSQuotaExceededException extends QuotaExceededException {
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
String msg = super.getMessage();
|
String msg = super.getMessage();
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
return "The NameSpace quota (directories and files)" +
|
msg = "The NameSpace quota (directories and files)" +
|
||||||
(pathName==null?"":(" of directory " + pathName)) +
|
(pathName==null?"":(" of directory " + pathName)) +
|
||||||
" is exceeded: quota=" + quota + " file count=" + count;
|
" is exceeded: quota=" + quota + " file count=" + count;
|
||||||
} else {
|
|
||||||
return msg;
|
if (prefix != null) {
|
||||||
|
msg = prefix + ": " + msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set a prefix for the error message. */
|
||||||
|
public void setMessagePrefix(final String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsLocatedFileStatus;
|
import org.apache.hadoop.hdfs.protocol.HdfsLocatedFileStatus;
|
||||||
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
|
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
||||||
|
@ -838,7 +839,8 @@ public class FSDirectory implements Closeable {
|
||||||
long dsDelta = (replication - oldRepl) * (fileNode.diskspaceConsumed()/oldRepl);
|
long dsDelta = (replication - oldRepl) * (fileNode.diskspaceConsumed()/oldRepl);
|
||||||
updateCount(inodesInPath, 0, dsDelta, true);
|
updateCount(inodesInPath, 0, dsDelta, true);
|
||||||
|
|
||||||
fileNode.setFileReplication(replication, inodesInPath.getLatestSnapshot());
|
fileNode = fileNode.setFileReplication(
|
||||||
|
replication, inodesInPath.getLatestSnapshot());
|
||||||
|
|
||||||
if (oldReplication != null) {
|
if (oldReplication != null) {
|
||||||
oldReplication[0] = oldRepl;
|
oldReplication[0] = oldRepl;
|
||||||
|
@ -877,7 +879,7 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
void setPermission(String src, FsPermission permission)
|
void setPermission(String src, FsPermission permission)
|
||||||
throws FileNotFoundException, UnresolvedLinkException,
|
throws FileNotFoundException, UnresolvedLinkException,
|
||||||
SnapshotAccessControlException {
|
NSQuotaExceededException, SnapshotAccessControlException {
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
unprotectedSetPermission(src, permission);
|
unprotectedSetPermission(src, permission);
|
||||||
|
@ -889,7 +891,7 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
void unprotectedSetPermission(String src, FsPermission permissions)
|
void unprotectedSetPermission(String src, FsPermission permissions)
|
||||||
throws FileNotFoundException, UnresolvedLinkException,
|
throws FileNotFoundException, UnresolvedLinkException,
|
||||||
SnapshotAccessControlException {
|
NSQuotaExceededException, SnapshotAccessControlException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
final INodesInPath inodesInPath = rootDir.getINodesInPath4Write(src, true);
|
final INodesInPath inodesInPath = rootDir.getINodesInPath4Write(src, true);
|
||||||
final INode inode = inodesInPath.getLastINode();
|
final INode inode = inodesInPath.getLastINode();
|
||||||
|
@ -901,7 +903,7 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
void setOwner(String src, String username, String groupname)
|
void setOwner(String src, String username, String groupname)
|
||||||
throws FileNotFoundException, UnresolvedLinkException,
|
throws FileNotFoundException, UnresolvedLinkException,
|
||||||
SnapshotAccessControlException {
|
NSQuotaExceededException, SnapshotAccessControlException {
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
unprotectedSetOwner(src, username, groupname);
|
unprotectedSetOwner(src, username, groupname);
|
||||||
|
@ -913,7 +915,7 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
void unprotectedSetOwner(String src, String username, String groupname)
|
void unprotectedSetOwner(String src, String username, String groupname)
|
||||||
throws FileNotFoundException, UnresolvedLinkException,
|
throws FileNotFoundException, UnresolvedLinkException,
|
||||||
SnapshotAccessControlException {
|
NSQuotaExceededException, SnapshotAccessControlException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
final INodesInPath inodesInPath = rootDir.getINodesInPath4Write(src, true);
|
final INodesInPath inodesInPath = rootDir.getINodesInPath4Write(src, true);
|
||||||
INode inode = inodesInPath.getLastINode();
|
INode inode = inodesInPath.getLastINode();
|
||||||
|
@ -932,7 +934,8 @@ public class FSDirectory implements Closeable {
|
||||||
* Concat all the blocks from srcs to trg and delete the srcs files
|
* Concat all the blocks from srcs to trg and delete the srcs files
|
||||||
*/
|
*/
|
||||||
public void concat(String target, String [] srcs)
|
public void concat(String target, String [] srcs)
|
||||||
throws UnresolvedLinkException, SnapshotAccessControlException {
|
throws UnresolvedLinkException, NSQuotaExceededException,
|
||||||
|
SnapshotAccessControlException {
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
// actual move
|
// actual move
|
||||||
|
@ -956,7 +959,8 @@ public class FSDirectory implements Closeable {
|
||||||
* NOTE: - it does not update quota (not needed for concat)
|
* NOTE: - it does not update quota (not needed for concat)
|
||||||
*/
|
*/
|
||||||
public void unprotectedConcat(String target, String [] srcs, long timestamp)
|
public void unprotectedConcat(String target, String [] srcs, long timestamp)
|
||||||
throws UnresolvedLinkException, SnapshotAccessControlException {
|
throws UnresolvedLinkException, NSQuotaExceededException,
|
||||||
|
SnapshotAccessControlException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
if (NameNode.stateChangeLog.isDebugEnabled()) {
|
if (NameNode.stateChangeLog.isDebugEnabled()) {
|
||||||
NameNode.stateChangeLog.debug("DIR* FSNamesystem.concat to "+target);
|
NameNode.stateChangeLog.debug("DIR* FSNamesystem.concat to "+target);
|
||||||
|
@ -1093,8 +1097,8 @@ public class FSDirectory implements Closeable {
|
||||||
* @param mtime the time the inode is removed
|
* @param mtime the time the inode is removed
|
||||||
* @throws SnapshotAccessControlException if path is in RO snapshot
|
* @throws SnapshotAccessControlException if path is in RO snapshot
|
||||||
*/
|
*/
|
||||||
void unprotectedDelete(String src, long mtime)
|
void unprotectedDelete(String src, long mtime) throws UnresolvedLinkException,
|
||||||
throws UnresolvedLinkException, SnapshotAccessControlException {
|
NSQuotaExceededException, SnapshotAccessControlException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
|
BlocksMapUpdateInfo collectedBlocks = new BlocksMapUpdateInfo();
|
||||||
|
|
||||||
|
@ -1116,7 +1120,8 @@ public class FSDirectory implements Closeable {
|
||||||
* @return the number of inodes deleted; 0 if no inodes are deleted.
|
* @return the number of inodes deleted; 0 if no inodes are deleted.
|
||||||
*/
|
*/
|
||||||
int unprotectedDelete(INodesInPath inodesInPath,
|
int unprotectedDelete(INodesInPath inodesInPath,
|
||||||
BlocksMapUpdateInfo collectedBlocks, long mtime) {
|
BlocksMapUpdateInfo collectedBlocks, long mtime)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
|
|
||||||
// check if target node exists
|
// check if target node exists
|
||||||
|
@ -1812,37 +1817,62 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that filesystem limit constraints are not violated
|
* Verify that filesystem limit constraints are not violated
|
||||||
* @throws PathComponentTooLongException child's name is too long
|
|
||||||
* @throws MaxDirectoryItemsExceededException items per directory is exceeded
|
|
||||||
*/
|
*/
|
||||||
protected <T extends INode> void verifyFsLimits(INode[] pathComponents,
|
void verifyFsLimits(INode[] pathComponents, int pos, INode child)
|
||||||
int pos, T child) throws FSLimitException {
|
throws FSLimitException {
|
||||||
boolean includeChildName = false;
|
verifyMaxComponentLength(child.getLocalName(), pathComponents, pos);
|
||||||
try {
|
verifyMaxDirItems(pathComponents, pos);
|
||||||
if (maxComponentLength != 0) {
|
}
|
||||||
int length = child.getLocalName().length();
|
|
||||||
if (length > maxComponentLength) {
|
/**
|
||||||
includeChildName = true;
|
* Verify child's name for fs limit.
|
||||||
throw new PathComponentTooLongException(maxComponentLength, length);
|
* @throws PathComponentTooLongException child's name is too long.
|
||||||
}
|
*/
|
||||||
|
public void verifyMaxComponentLength(String childName,
|
||||||
|
Object parentPath, int pos) throws PathComponentTooLongException {
|
||||||
|
if (maxComponentLength == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int length = childName.length();
|
||||||
|
if (length > maxComponentLength) {
|
||||||
|
final String p = parentPath instanceof INode[]?
|
||||||
|
getFullPathName((INode[])parentPath, pos - 1): (String)parentPath;
|
||||||
|
final PathComponentTooLongException e = new PathComponentTooLongException(
|
||||||
|
maxComponentLength, length, p, childName);
|
||||||
|
if (ready) {
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
// Do not throw if edits log is still being processed
|
||||||
|
NameNode.LOG.error("FSDirectory.verifyMaxComponentLength: "
|
||||||
|
+ e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
if (maxDirItems != 0) {
|
}
|
||||||
INodeDirectory parent = (INodeDirectory)pathComponents[pos-1];
|
}
|
||||||
int count = parent.getChildrenList(null).size();
|
|
||||||
if (count >= maxDirItems) {
|
/**
|
||||||
throw new MaxDirectoryItemsExceededException(maxDirItems, count);
|
* Verify children size for fs limit.
|
||||||
}
|
* @throws MaxDirectoryItemsExceededException too many children.
|
||||||
|
*/
|
||||||
|
private void verifyMaxDirItems(INode[] pathComponents, int pos)
|
||||||
|
throws MaxDirectoryItemsExceededException {
|
||||||
|
if (maxDirItems == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final INodeDirectory parent = (INodeDirectory)pathComponents[pos-1];
|
||||||
|
final int count = parent.getChildrenList(null).size();
|
||||||
|
if (count >= maxDirItems) {
|
||||||
|
final MaxDirectoryItemsExceededException e
|
||||||
|
= new MaxDirectoryItemsExceededException(maxDirItems, count);
|
||||||
|
if (ready) {
|
||||||
|
e.setPathName(getFullPathName(pathComponents, pos - 1));
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
// Do not throw if edits log is still being processed
|
||||||
|
NameNode.LOG.error("FSDirectory.verifyMaxDirItems: "
|
||||||
|
+ e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
} catch (FSLimitException e) {
|
|
||||||
String badPath = getFullPathName(pathComponents, pos-1);
|
|
||||||
if (includeChildName) {
|
|
||||||
badPath += Path.SEPARATOR + child.getLocalName();
|
|
||||||
}
|
|
||||||
e.setPathName(badPath);
|
|
||||||
// Do not throw if edits log is still being processed
|
|
||||||
if (ready) throw(e);
|
|
||||||
// log pre-existing paths that exceed limits
|
|
||||||
NameNode.LOG.error("FSDirectory.verifyFsLimits - " + e.getLocalizedMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1900,20 +1930,22 @@ public class FSDirectory implements Closeable {
|
||||||
* Remove the last inode in the path from the namespace.
|
* Remove the last inode in the path from the namespace.
|
||||||
* Count of each ancestor with quota is also updated.
|
* Count of each ancestor with quota is also updated.
|
||||||
* @return the removed node; null if the removal fails.
|
* @return the removed node; null if the removal fails.
|
||||||
|
* @throws NSQuotaExceededException
|
||||||
*/
|
*/
|
||||||
private INode removeLastINode(final INodesInPath inodesInPath) {
|
private INode removeLastINode(final INodesInPath inodesInPath)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
final Snapshot latestSnapshot = inodesInPath.getLatestSnapshot();
|
||||||
final INode[] inodes = inodesInPath.getINodes();
|
final INode[] inodes = inodesInPath.getINodes();
|
||||||
final int pos = inodes.length - 1;
|
final int pos = inodes.length - 1;
|
||||||
final boolean removed = ((INodeDirectory)inodes[pos-1]).removeChild(
|
final boolean removed = ((INodeDirectory)inodes[pos-1]).removeChild(
|
||||||
inodes[pos], inodesInPath.getLatestSnapshot());
|
inodes[pos], latestSnapshot);
|
||||||
if (removed) {
|
if (removed && latestSnapshot == null) {
|
||||||
inodesInPath.setINode(pos - 1, inodes[pos].getParent());
|
inodesInPath.setINode(pos - 1, inodes[pos].getParent());
|
||||||
final Quota.Counts counts = inodes[pos].computeQuotaUsage();
|
final Quota.Counts counts = inodes[pos].computeQuotaUsage();
|
||||||
updateCountNoQuotaCheck(inodesInPath, pos,
|
updateCountNoQuotaCheck(inodesInPath, pos,
|
||||||
-counts.get(Quota.NAMESPACE), -counts.get(Quota.DISKSPACE));
|
-counts.get(Quota.NAMESPACE), -counts.get(Quota.DISKSPACE));
|
||||||
return inodes[pos];
|
|
||||||
}
|
}
|
||||||
return null;
|
return removed? inodes[pos]: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1986,7 +2018,7 @@ public class FSDirectory implements Closeable {
|
||||||
final Snapshot latest = iip.getLatestSnapshot();
|
final Snapshot latest = iip.getLatestSnapshot();
|
||||||
if (dirNode instanceof INodeDirectoryWithQuota) {
|
if (dirNode instanceof INodeDirectoryWithQuota) {
|
||||||
// a directory with quota; so set the quota to the new value
|
// a directory with quota; so set the quota to the new value
|
||||||
((INodeDirectoryWithQuota)dirNode).setQuota(nsQuota, dsQuota, latest);
|
((INodeDirectoryWithQuota)dirNode).setQuota(nsQuota, dsQuota);
|
||||||
if (!dirNode.isQuotaSet() && latest == null) {
|
if (!dirNode.isQuotaSet() && latest == null) {
|
||||||
// will not come here for root because root's nsQuota is always set
|
// will not come here for root because root's nsQuota is always set
|
||||||
return dirNode.replaceSelf4INodeDirectory();
|
return dirNode.replaceSelf4INodeDirectory();
|
||||||
|
@ -2033,7 +2065,7 @@ public class FSDirectory implements Closeable {
|
||||||
* Sets the access time on the file/directory. Logs it in the transaction log.
|
* Sets the access time on the file/directory. Logs it in the transaction log.
|
||||||
*/
|
*/
|
||||||
void setTimes(String src, INode inode, long mtime, long atime, boolean force,
|
void setTimes(String src, INode inode, long mtime, long atime, boolean force,
|
||||||
Snapshot latest) {
|
Snapshot latest) throws NSQuotaExceededException {
|
||||||
boolean status = false;
|
boolean status = false;
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
|
@ -2047,7 +2079,7 @@ public class FSDirectory implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean unprotectedSetTimes(String src, long mtime, long atime, boolean force)
|
boolean unprotectedSetTimes(String src, long mtime, long atime, boolean force)
|
||||||
throws UnresolvedLinkException {
|
throws UnresolvedLinkException, NSQuotaExceededException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
final INodesInPath i = getLastINodeInPath(src);
|
final INodesInPath i = getLastINodeInPath(src);
|
||||||
return unprotectedSetTimes(src, i.getLastINode(), mtime, atime, force,
|
return unprotectedSetTimes(src, i.getLastINode(), mtime, atime, force,
|
||||||
|
@ -2055,7 +2087,8 @@ public class FSDirectory implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean unprotectedSetTimes(String src, INode inode, long mtime,
|
private boolean unprotectedSetTimes(String src, INode inode, long mtime,
|
||||||
long atime, boolean force, Snapshot latest) {
|
long atime, boolean force, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
assert hasWriteLock();
|
assert hasWriteLock();
|
||||||
boolean status = false;
|
boolean status = false;
|
||||||
if (mtime != -1) {
|
if (mtime != -1) {
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.util.Time.now;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -28,28 +30,26 @@ import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
|
import org.apache.hadoop.hdfs.HAUtil;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.protocol.LayoutVersion;
|
import org.apache.hadoop.hdfs.protocol.LayoutVersion;
|
||||||
import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
|
import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
|
||||||
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
|
||||||
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
|
||||||
import org.apache.hadoop.hdfs.server.common.InconsistentFSStateException;
|
import org.apache.hadoop.hdfs.server.common.InconsistentFSStateException;
|
||||||
import org.apache.hadoop.hdfs.server.common.Storage;
|
import org.apache.hadoop.hdfs.server.common.Storage;
|
||||||
import org.apache.hadoop.hdfs.server.common.Storage.FormatConfirmable;
|
import org.apache.hadoop.hdfs.server.common.Storage.FormatConfirmable;
|
||||||
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
|
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
|
||||||
import org.apache.hadoop.hdfs.server.common.Storage.StorageState;
|
import org.apache.hadoop.hdfs.server.common.Storage.StorageState;
|
||||||
import org.apache.hadoop.hdfs.server.common.Util;
|
import org.apache.hadoop.hdfs.server.common.Util;
|
||||||
import static org.apache.hadoop.util.Time.now;
|
|
||||||
|
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.NamenodeRole;
|
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.StartupOption;
|
|
||||||
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
|
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeFile;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.CheckpointCommand;
|
import org.apache.hadoop.hdfs.server.protocol.CheckpointCommand;
|
||||||
|
@ -62,9 +62,6 @@ import org.apache.hadoop.hdfs.util.MD5FileUtils;
|
||||||
import org.apache.hadoop.io.MD5Hash;
|
import org.apache.hadoop.io.MD5Hash;
|
||||||
import org.apache.hadoop.util.IdGenerator;
|
import org.apache.hadoop.util.IdGenerator;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
|
||||||
import org.apache.hadoop.hdfs.HAUtil;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
@ -726,7 +723,8 @@ public class FSImage implements Closeable {
|
||||||
return lastAppliedTxId - prevLastAppliedTxId;
|
return lastAppliedTxId - prevLastAppliedTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update the count of each directory with quota in the namespace
|
/**
|
||||||
|
* Update the count of each directory with quota in the namespace.
|
||||||
* A directory's count is defined as the total number inodes in the tree
|
* A directory's count is defined as the total number inodes in the tree
|
||||||
* rooted at the directory.
|
* rooted at the directory.
|
||||||
*
|
*
|
||||||
|
@ -734,39 +732,22 @@ public class FSImage implements Closeable {
|
||||||
* throw QuotaExceededException.
|
* throw QuotaExceededException.
|
||||||
*/
|
*/
|
||||||
static void updateCountForQuota(INodeDirectoryWithQuota root) {
|
static void updateCountForQuota(INodeDirectoryWithQuota root) {
|
||||||
updateCountForINodeWithQuota(root, new Quota.Counts(), new Stack<INode>());
|
updateCountForQuotaRecursively(root, new Quota.Counts());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static void updateCountForQuotaRecursively(INodeDirectory dir,
|
||||||
* Update the count of the directory if it has a quota and return the count
|
Quota.Counts counts) {
|
||||||
*
|
|
||||||
* This does not throw a QuotaExceededException. This is just an update
|
|
||||||
* of of existing state and throwing QuotaExceededException does not help
|
|
||||||
* with fixing the state, if there is a problem.
|
|
||||||
*
|
|
||||||
* @param dir the root of the tree that represents the directory
|
|
||||||
* @param counters counters for name space and disk space
|
|
||||||
* @param stack INodes for the each of components in the path.
|
|
||||||
*/
|
|
||||||
private static void updateCountForINodeWithQuota(INodeDirectory dir,
|
|
||||||
Quota.Counts counts, Stack<INode> stack) {
|
|
||||||
// The stack is not needed since we could use the 'parent' field in INode.
|
|
||||||
// However, using 'parent' is not recommended.
|
|
||||||
stack.push(dir);
|
|
||||||
|
|
||||||
final long parentNamespace = counts.get(Quota.NAMESPACE);
|
final long parentNamespace = counts.get(Quota.NAMESPACE);
|
||||||
final long parentDiskspace = counts.get(Quota.DISKSPACE);
|
final long parentDiskspace = counts.get(Quota.DISKSPACE);
|
||||||
|
|
||||||
counts.add(Quota.NAMESPACE, 1);
|
dir.computeQuotaUsage4CurrentDirectory(counts);
|
||||||
|
|
||||||
for (INode child : dir.getChildrenList(null)) {
|
for (INode child : dir.getChildrenList(null)) {
|
||||||
if (child.isDirectory()) {
|
if (child.isDirectory()) {
|
||||||
updateCountForINodeWithQuota((INodeDirectory)child, counts, stack);
|
updateCountForQuotaRecursively((INodeDirectory)child, counts);
|
||||||
} else {
|
} else {
|
||||||
// file or symlink: count here to reduce recursive calls.
|
// file or symlink: count here to reduce recursive calls.
|
||||||
counts.add(Quota.NAMESPACE, 1);
|
child.computeQuotaUsage(counts, false);
|
||||||
if (child.isFile()) {
|
|
||||||
counts.add(Quota.DISKSPACE, ((INodeFile)child).diskspaceConsumed());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,24 +755,20 @@ public class FSImage implements Closeable {
|
||||||
// check if quota is violated. It indicates a software bug.
|
// check if quota is violated. It indicates a software bug.
|
||||||
final long namespace = counts.get(Quota.NAMESPACE) - parentNamespace;
|
final long namespace = counts.get(Quota.NAMESPACE) - parentNamespace;
|
||||||
if (Quota.isViolated(dir.getNsQuota(), namespace)) {
|
if (Quota.isViolated(dir.getNsQuota(), namespace)) {
|
||||||
final INode[] inodes = stack.toArray(new INode[stack.size()]);
|
|
||||||
LOG.error("BUG: Namespace quota violation in image for "
|
LOG.error("BUG: Namespace quota violation in image for "
|
||||||
+ FSDirectory.getFullPathName(inodes, inodes.length)
|
+ dir.getFullPathName()
|
||||||
+ " quota = " + dir.getNsQuota() + " < consumed = " + namespace);
|
+ " quota = " + dir.getNsQuota() + " < consumed = " + namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
final long diskspace = counts.get(Quota.DISKSPACE) - parentDiskspace;
|
final long diskspace = counts.get(Quota.DISKSPACE) - parentDiskspace;
|
||||||
if (Quota.isViolated(dir.getDsQuota(), diskspace)) {
|
if (Quota.isViolated(dir.getDsQuota(), diskspace)) {
|
||||||
final INode[] inodes = stack.toArray(new INode[stack.size()]);
|
|
||||||
LOG.error("BUG: Diskspace quota violation in image for "
|
LOG.error("BUG: Diskspace quota violation in image for "
|
||||||
+ FSDirectory.getFullPathName(inodes, inodes.length)
|
+ dir.getFullPathName()
|
||||||
+ " quota = " + dir.getDsQuota() + " < consumed = " + diskspace);
|
+ " quota = " + dir.getDsQuota() + " < consumed = " + diskspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
((INodeDirectoryWithQuota)dir).setSpaceConsumed(namespace, diskspace);
|
((INodeDirectoryWithQuota)dir).setSpaceConsumed(namespace, diskspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -319,7 +319,7 @@ public class FSImageFormat {
|
||||||
long dsQuota = root.getDsQuota();
|
long dsQuota = root.getDsQuota();
|
||||||
FSDirectory fsDir = namesystem.dir;
|
FSDirectory fsDir = namesystem.dir;
|
||||||
if (nsQuota != -1 || dsQuota != -1) {
|
if (nsQuota != -1 || dsQuota != -1) {
|
||||||
fsDir.rootDir.setQuota(nsQuota, dsQuota, null);
|
fsDir.rootDir.setQuota(nsQuota, dsQuota);
|
||||||
}
|
}
|
||||||
fsDir.rootDir.cloneModificationTime(root);
|
fsDir.rootDir.cloneModificationTime(root);
|
||||||
fsDir.rootDir.clonePermissionStatus(root);
|
fsDir.rootDir.clonePermissionStatus(root);
|
||||||
|
@ -503,7 +503,7 @@ public class FSImageFormat {
|
||||||
*/
|
*/
|
||||||
private void addToParent(INodeDirectory parent, INode child) {
|
private void addToParent(INodeDirectory parent, INode child) {
|
||||||
// NOTE: This does not update space counts for parents
|
// NOTE: This does not update space counts for parents
|
||||||
if (!parent.addChild(child, false, null)) {
|
if (!parent.addChild(child)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
namesystem.dir.cacheName(child);
|
namesystem.dir.cacheName(child);
|
||||||
|
|
|
@ -32,12 +32,14 @@ import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.diff.Diff;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.diff.Diff;
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.primitives.SignedBytes;
|
import com.google.common.primitives.SignedBytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,11 +160,8 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
public final PermissionStatus getPermissionStatus() {
|
public final PermissionStatus getPermissionStatus() {
|
||||||
return getPermissionStatus(null);
|
return getPermissionStatus(null);
|
||||||
}
|
}
|
||||||
private INode updatePermissionStatus(PermissionStatusFormat f, long n,
|
private void updatePermissionStatus(PermissionStatusFormat f, long n) {
|
||||||
Snapshot latest) {
|
this.permission = f.combine(n, permission);
|
||||||
final INode nodeToUpdate = recordModification(latest);
|
|
||||||
nodeToUpdate.permission = f.combine(n, permission);
|
|
||||||
return nodeToUpdate;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param snapshot
|
* @param snapshot
|
||||||
|
@ -183,9 +182,16 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
return getUserName(null);
|
return getUserName(null);
|
||||||
}
|
}
|
||||||
/** Set user */
|
/** Set user */
|
||||||
protected INode setUser(String user, Snapshot latest) {
|
final void setUser(String user) {
|
||||||
int n = SerialNumberManager.INSTANCE.getUserSerialNumber(user);
|
int n = SerialNumberManager.INSTANCE.getUserSerialNumber(user);
|
||||||
return updatePermissionStatus(PermissionStatusFormat.USER, n, latest);
|
updatePermissionStatus(PermissionStatusFormat.USER, n);
|
||||||
|
}
|
||||||
|
/** Set user */
|
||||||
|
final INode setUser(String user, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
final INode nodeToUpdate = recordModification(latest);
|
||||||
|
nodeToUpdate.setUser(user);
|
||||||
|
return nodeToUpdate;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param snapshot
|
* @param snapshot
|
||||||
|
@ -206,9 +212,16 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
return getGroupName(null);
|
return getGroupName(null);
|
||||||
}
|
}
|
||||||
/** Set group */
|
/** Set group */
|
||||||
protected INode setGroup(String group, Snapshot latest) {
|
final void setGroup(String group) {
|
||||||
int n = SerialNumberManager.INSTANCE.getGroupSerialNumber(group);
|
int n = SerialNumberManager.INSTANCE.getGroupSerialNumber(group);
|
||||||
return updatePermissionStatus(PermissionStatusFormat.GROUP, n, latest);
|
updatePermissionStatus(PermissionStatusFormat.GROUP, n);
|
||||||
|
}
|
||||||
|
/** Set group */
|
||||||
|
final INode setGroup(String group, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
final INode nodeToUpdate = recordModification(latest);
|
||||||
|
nodeToUpdate.setGroup(group);
|
||||||
|
return nodeToUpdate;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param snapshot
|
* @param snapshot
|
||||||
|
@ -232,9 +245,16 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
return (short)PermissionStatusFormat.MODE.retrieve(permission);
|
return (short)PermissionStatusFormat.MODE.retrieve(permission);
|
||||||
}
|
}
|
||||||
/** Set the {@link FsPermission} of this {@link INode} */
|
/** Set the {@link FsPermission} of this {@link INode} */
|
||||||
INode setPermission(FsPermission permission, Snapshot latest) {
|
void setPermission(FsPermission permission) {
|
||||||
final short mode = permission.toShort();
|
final short mode = permission.toShort();
|
||||||
return updatePermissionStatus(PermissionStatusFormat.MODE, mode, latest);
|
updatePermissionStatus(PermissionStatusFormat.MODE, mode);
|
||||||
|
}
|
||||||
|
/** Set the {@link FsPermission} of this {@link INode} */
|
||||||
|
INode setPermission(FsPermission permission, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
final INode nodeToUpdate = recordModification(latest);
|
||||||
|
nodeToUpdate.setPermission(permission);
|
||||||
|
return nodeToUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,7 +283,8 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
* However, in some cases, this inode may be replaced with a new inode
|
* However, in some cases, this inode may be replaced with a new inode
|
||||||
* for maintaining snapshots. The current inode is then the new inode.
|
* for maintaining snapshots. The current inode is then the new inode.
|
||||||
*/
|
*/
|
||||||
abstract INode recordModification(final Snapshot latest);
|
abstract INode recordModification(final Snapshot latest)
|
||||||
|
throws NSQuotaExceededException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether it's a file.
|
* Check whether it's a file.
|
||||||
|
@ -335,7 +356,7 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
* @return the number of deleted inodes in the subtree.
|
* @return the number of deleted inodes in the subtree.
|
||||||
*/
|
*/
|
||||||
public abstract int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public abstract int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
BlocksMapUpdateInfo collectedBlocks);
|
BlocksMapUpdateInfo collectedBlocks) throws NSQuotaExceededException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy self and clear everything! If the INode is a file, this method
|
* Destroy self and clear everything! If the INode is a file, this method
|
||||||
|
@ -427,6 +448,16 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
*/
|
*/
|
||||||
public abstract Content.Counts computeContentSummary(Content.Counts counts);
|
public abstract Content.Counts computeContentSummary(Content.Counts counts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check and add namespace consumed to itself and the ancestors.
|
||||||
|
* @throws NSQuotaExceededException if quote is violated.
|
||||||
|
*/
|
||||||
|
public void addNamespaceConsumed(int delta) throws NSQuotaExceededException {
|
||||||
|
if (parent != null) {
|
||||||
|
parent.addNamespaceConsumed(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the quota set for this inode
|
* Get the quota set for this inode
|
||||||
* @return the quota if it is set; -1 otherwise
|
* @return the quota if it is set; -1 otherwise
|
||||||
|
@ -447,7 +478,7 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
* Count subtree {@link Quota#NAMESPACE} and {@link Quota#DISKSPACE} usages.
|
* Count subtree {@link Quota#NAMESPACE} and {@link Quota#DISKSPACE} usages.
|
||||||
*/
|
*/
|
||||||
final Quota.Counts computeQuotaUsage() {
|
final Quota.Counts computeQuotaUsage() {
|
||||||
return computeQuotaUsage(new Quota.Counts());
|
return computeQuotaUsage(new Quota.Counts(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -456,7 +487,8 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
* @param counts The subtree counts for returning.
|
* @param counts The subtree counts for returning.
|
||||||
* @return The same objects as the counts parameter.
|
* @return The same objects as the counts parameter.
|
||||||
*/
|
*/
|
||||||
abstract Quota.Counts computeQuotaUsage(Quota.Counts counts);
|
public abstract Quota.Counts computeQuotaUsage(Quota.Counts counts,
|
||||||
|
boolean useCache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return null if the local name is null; otherwise, return the local name.
|
* @return null if the local name is null; otherwise, return the local name.
|
||||||
|
@ -574,8 +606,9 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update modification time if it is larger than the current value. */
|
/** Update modification time if it is larger than the current value. */
|
||||||
public final INode updateModificationTime(long mtime, Snapshot latest) {
|
public final INode updateModificationTime(long mtime, Snapshot latest)
|
||||||
assert isDirectory();
|
throws NSQuotaExceededException {
|
||||||
|
Preconditions.checkState(isDirectory());
|
||||||
if (mtime <= modificationTime) {
|
if (mtime <= modificationTime) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -586,12 +619,15 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
this.modificationTime = that.modificationTime;
|
this.modificationTime = that.modificationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the last modification time of inode. */
|
||||||
* Always set the last modification time of inode.
|
public final void setModificationTime(long modificationTime) {
|
||||||
*/
|
this.modificationTime = modificationTime;
|
||||||
public final INode setModificationTime(long modtime, Snapshot latest) {
|
}
|
||||||
|
/** Set the last modification time of inode. */
|
||||||
|
public final INode setModificationTime(long modificationTime, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
final INode nodeToUpdate = recordModification(latest);
|
final INode nodeToUpdate = recordModification(latest);
|
||||||
nodeToUpdate.modificationTime = modtime;
|
nodeToUpdate.setModificationTime(modificationTime);
|
||||||
return nodeToUpdate;
|
return nodeToUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,9 +653,16 @@ public abstract class INode implements Diff.Element<byte[]> {
|
||||||
/**
|
/**
|
||||||
* Set last access time of inode.
|
* Set last access time of inode.
|
||||||
*/
|
*/
|
||||||
public INode setAccessTime(long atime, Snapshot latest) {
|
public void setAccessTime(long accessTime) {
|
||||||
|
this.accessTime = accessTime;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set last access time of inode.
|
||||||
|
*/
|
||||||
|
public INode setAccessTime(long accessTime, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
final INode nodeToUpdate = recordModification(latest);
|
final INode nodeToUpdate = recordModification(latest);
|
||||||
nodeToUpdate.accessTime = atime;
|
nodeToUpdate.setAccessTime(accessTime);
|
||||||
return nodeToUpdate;
|
return nodeToUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.hadoop.fs.UnresolvedLinkException;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.UnresolvedPathException;
|
import org.apache.hadoop.hdfs.protocol.UnresolvedPathException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectorySnapshottable;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.INodeDirectorySnapshottable;
|
||||||
|
@ -97,18 +98,12 @@ public class INodeDirectory extends INode {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertChildrenNonNull() {
|
|
||||||
if (children == null) {
|
|
||||||
throw new AssertionError("children is null: " + this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int searchChildren(byte[] name) {
|
private int searchChildren(byte[] name) {
|
||||||
return Collections.binarySearch(children, name);
|
return children == null? -1: Collections.binarySearch(children, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int searchChildrenForExistingINode(final INode inode) {
|
private int searchChildrenForExistingINode(final INode inode) {
|
||||||
assertChildrenNonNull();
|
Preconditions.checkNotNull(children);
|
||||||
final byte[] name = inode.getLocalNameBytes();
|
final byte[] name = inode.getLocalNameBytes();
|
||||||
final int i = searchChildren(name);
|
final int i = searchChildren(name);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
|
@ -124,7 +119,8 @@ public class INodeDirectory extends INode {
|
||||||
* @param child the child inode to be removed
|
* @param child the child inode to be removed
|
||||||
* @param latest See {@link INode#recordModification(Snapshot)}.
|
* @param latest See {@link INode#recordModification(Snapshot)}.
|
||||||
*/
|
*/
|
||||||
public boolean removeChild(INode child, Snapshot latest) {
|
public boolean removeChild(INode child, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (isInLatestSnapshot(latest)) {
|
if (isInLatestSnapshot(latest)) {
|
||||||
return replaceSelf4INodeDirectoryWithSnapshot()
|
return replaceSelf4INodeDirectoryWithSnapshot()
|
||||||
.removeChild(child, latest);
|
.removeChild(child, latest);
|
||||||
|
@ -142,7 +138,7 @@ public class INodeDirectory extends INode {
|
||||||
* @return true if the child is removed; false if the child is not found.
|
* @return true if the child is removed; false if the child is not found.
|
||||||
*/
|
*/
|
||||||
protected final boolean removeChild(final INode child) {
|
protected final boolean removeChild(final INode child) {
|
||||||
assertChildrenNonNull();
|
Preconditions.checkNotNull(children);
|
||||||
final int i = searchChildren(child.getLocalNameBytes());
|
final int i = searchChildren(child.getLocalNameBytes());
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -165,7 +161,7 @@ public class INodeDirectory extends INode {
|
||||||
* {@link INodeDirectoryWithSnapshot} depending on the latest snapshot.
|
* {@link INodeDirectoryWithSnapshot} depending on the latest snapshot.
|
||||||
*/
|
*/
|
||||||
INodeDirectoryWithQuota replaceSelf4Quota(final Snapshot latest,
|
INodeDirectoryWithQuota replaceSelf4Quota(final Snapshot latest,
|
||||||
final long nsQuota, final long dsQuota) {
|
final long nsQuota, final long dsQuota) throws NSQuotaExceededException {
|
||||||
Preconditions.checkState(!(this instanceof INodeDirectoryWithQuota),
|
Preconditions.checkState(!(this instanceof INodeDirectoryWithQuota),
|
||||||
"this is already an INodeDirectoryWithQuota, this=%s", this);
|
"this is already an INodeDirectoryWithQuota, this=%s", this);
|
||||||
|
|
||||||
|
@ -176,13 +172,13 @@ public class INodeDirectory extends INode {
|
||||||
return q;
|
return q;
|
||||||
} else {
|
} else {
|
||||||
final INodeDirectoryWithSnapshot s = new INodeDirectoryWithSnapshot(this);
|
final INodeDirectoryWithSnapshot s = new INodeDirectoryWithSnapshot(this);
|
||||||
s.setQuota(nsQuota, dsQuota, null);
|
s.setQuota(nsQuota, dsQuota);
|
||||||
return replaceSelf(s).saveSelf2Snapshot(latest, this);
|
return replaceSelf(s).saveSelf2Snapshot(latest, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** Replace itself with an {@link INodeDirectorySnapshottable}. */
|
/** Replace itself with an {@link INodeDirectorySnapshottable}. */
|
||||||
public INodeDirectorySnapshottable replaceSelf4INodeDirectorySnapshottable(
|
public INodeDirectorySnapshottable replaceSelf4INodeDirectorySnapshottable(
|
||||||
Snapshot latest) {
|
Snapshot latest) throws NSQuotaExceededException {
|
||||||
Preconditions.checkState(!(this instanceof INodeDirectorySnapshottable),
|
Preconditions.checkState(!(this instanceof INodeDirectorySnapshottable),
|
||||||
"this is already an INodeDirectorySnapshottable, this=%s", this);
|
"this is already an INodeDirectorySnapshottable, this=%s", this);
|
||||||
final INodeDirectorySnapshottable s = new INodeDirectorySnapshottable(this);
|
final INodeDirectorySnapshottable s = new INodeDirectorySnapshottable(this);
|
||||||
|
@ -213,7 +209,7 @@ public class INodeDirectory extends INode {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceChild(final INode oldChild, final INode newChild) {
|
public void replaceChild(final INode oldChild, final INode newChild) {
|
||||||
assertChildrenNonNull();
|
Preconditions.checkNotNull(children);
|
||||||
final int i = searchChildrenForExistingINode(newChild);
|
final int i = searchChildrenForExistingINode(newChild);
|
||||||
final INode removed = children.set(i, newChild);
|
final INode removed = children.set(i, newChild);
|
||||||
Preconditions.checkState(removed == oldChild);
|
Preconditions.checkState(removed == oldChild);
|
||||||
|
@ -247,7 +243,8 @@ public class INodeDirectory extends INode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeDirectory recordModification(Snapshot latest) {
|
public INodeDirectory recordModification(Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
return isInLatestSnapshot(latest)?
|
return isInLatestSnapshot(latest)?
|
||||||
replaceSelf4INodeDirectoryWithSnapshot().recordModification(latest)
|
replaceSelf4INodeDirectoryWithSnapshot().recordModification(latest)
|
||||||
: this;
|
: this;
|
||||||
|
@ -259,7 +256,7 @@ public class INodeDirectory extends INode {
|
||||||
* @return the child inode, which may be replaced.
|
* @return the child inode, which may be replaced.
|
||||||
*/
|
*/
|
||||||
public INode saveChild2Snapshot(final INode child, final Snapshot latest,
|
public INode saveChild2Snapshot(final INode child, final Snapshot latest,
|
||||||
final INode snapshotCopy) {
|
final INode snapshotCopy) throws NSQuotaExceededException {
|
||||||
if (latest == null) {
|
if (latest == null) {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
@ -387,11 +384,11 @@ public class INodeDirectory extends INode {
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
existing.addNode(curNode);
|
existing.addNode(curNode);
|
||||||
}
|
}
|
||||||
if (curNode instanceof INodeDirectorySnapshottable) {
|
if (curNode instanceof INodeDirectoryWithSnapshot) {
|
||||||
//if the path is a non-snapshot path, update the latest snapshot.
|
//if the path is a non-snapshot path, update the latest snapshot.
|
||||||
if (!existing.isSnapshot()) {
|
if (!existing.isSnapshot()) {
|
||||||
existing.updateLatestSnapshot(
|
existing.updateLatestSnapshot(
|
||||||
((INodeDirectorySnapshottable)curNode).getLastSnapshot());
|
((INodeDirectoryWithSnapshot)curNode).getLastSnapshot());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curNode.isSymlink() && (!lastComp || (lastComp && resolveLink))) {
|
if (curNode.isSymlink() && (!lastComp || (lastComp && resolveLink))) {
|
||||||
|
@ -488,64 +485,64 @@ public class INodeDirectory extends INode {
|
||||||
* otherwise, return true;
|
* otherwise, return true;
|
||||||
*/
|
*/
|
||||||
public boolean addChild(INode node, final boolean setModTime,
|
public boolean addChild(INode node, final boolean setModTime,
|
||||||
final Snapshot latest) {
|
final Snapshot latest) throws NSQuotaExceededException {
|
||||||
if (isInLatestSnapshot(latest)) {
|
|
||||||
return replaceSelf4INodeDirectoryWithSnapshot()
|
|
||||||
.addChild(node, setModTime, latest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (children == null) {
|
|
||||||
children = new ArrayList<INode>(DEFAULT_FILES_PER_DIRECTORY);
|
|
||||||
}
|
|
||||||
final int low = searchChildren(node.getLocalNameBytes());
|
final int low = searchChildren(node.getLocalNameBytes());
|
||||||
if (low >= 0) {
|
if (low >= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
node.parent = this;
|
|
||||||
children.add(-low - 1, node);
|
if (isInLatestSnapshot(latest)) {
|
||||||
// update modification time of the parent directory
|
return replaceSelf4INodeDirectoryWithSnapshot()
|
||||||
if (setModTime) {
|
.addChild(node, setModTime, latest);
|
||||||
updateModificationTime(node.getModificationTime(), latest);
|
|
||||||
}
|
}
|
||||||
if (node.getGroupName() == null) {
|
addChild(node, low);
|
||||||
node.setGroup(getGroupName(), null);
|
if (setModTime) {
|
||||||
|
// update modification time of the parent directory
|
||||||
|
updateModificationTime(node.getModificationTime(), latest);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add new INode to the file tree.
|
/** The same as addChild(node, false, null, false) */
|
||||||
* Find the parent and insert
|
public boolean addChild(INode node) {
|
||||||
*
|
final int low = searchChildren(node.getLocalNameBytes());
|
||||||
* @param path file path
|
if (low >= 0) {
|
||||||
* @param newNode INode to be added
|
|
||||||
* @return false if the node already exists; otherwise, return true;
|
|
||||||
* @throws FileNotFoundException if parent does not exist or
|
|
||||||
* @throws UnresolvedLinkException if any path component is a symbolic link
|
|
||||||
* is not a directory.
|
|
||||||
*/
|
|
||||||
boolean addINode(String path, INode newNode
|
|
||||||
) throws FileNotFoundException, PathIsNotDirectoryException,
|
|
||||||
UnresolvedLinkException {
|
|
||||||
byte[][] pathComponents = getPathComponents(path);
|
|
||||||
if (pathComponents.length < 2) { // add root
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
newNode.setLocalName(pathComponents[pathComponents.length - 1]);
|
addChild(node, low);
|
||||||
// insert into the parent children list
|
return true;
|
||||||
final INodesInPath iip = getExistingPathINodes(pathComponents, 2, false);
|
}
|
||||||
final INodeDirectory parent = INodeDirectory.valueOf(iip.getINode(0),
|
|
||||||
pathComponents);
|
/**
|
||||||
return parent.addChild(newNode, true, iip.getLatestSnapshot());
|
* Add the node to the children list at the given insertion point.
|
||||||
|
* The basic add method which actually calls children.add(..).
|
||||||
|
*/
|
||||||
|
private void addChild(final INode node, final int insertionPoint) {
|
||||||
|
if (children == null) {
|
||||||
|
children = new ArrayList<INode>(DEFAULT_FILES_PER_DIRECTORY);
|
||||||
|
}
|
||||||
|
node.parent = this;
|
||||||
|
children.add(-insertionPoint - 1, node);
|
||||||
|
|
||||||
|
if (node.getGroupName() == null) {
|
||||||
|
node.setGroup(getGroupName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Quota.Counts computeQuotaUsage(Quota.Counts counts) {
|
public Quota.Counts computeQuotaUsage(Quota.Counts counts, boolean useCache) {
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
for (INode child : children) {
|
for (INode child : children) {
|
||||||
child.computeQuotaUsage(counts);
|
child.computeQuotaUsage(counts, useCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return computeQuotaUsage4CurrentDirectory(counts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add quota usage for this inode excluding children. */
|
||||||
|
public Quota.Counts computeQuotaUsage4CurrentDirectory(Quota.Counts counts) {
|
||||||
counts.add(Quota.NAMESPACE, 1);
|
counts.add(Quota.NAMESPACE, 1);
|
||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
@ -582,15 +579,15 @@ public class INodeDirectory extends INode {
|
||||||
: ReadOnlyList.Util.asReadOnlyList(children);
|
: ReadOnlyList.Util.asReadOnlyList(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the children list. */
|
/** Set the children list to null. */
|
||||||
public void setChildren(List<INode> children) {
|
public void clearChildren() {
|
||||||
this.children = children;
|
this.children = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearReferences() {
|
public void clearReferences() {
|
||||||
super.clearReferences();
|
super.clearReferences();
|
||||||
setChildren(null);
|
clearChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -598,7 +595,8 @@ public class INodeDirectory extends INode {
|
||||||
* recursively down the subtree.
|
* recursively down the subtree.
|
||||||
*/
|
*/
|
||||||
public int cleanSubtreeRecursively(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtreeRecursively(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
// in case of deletion snapshot, since this call happens after we modify
|
// in case of deletion snapshot, since this call happens after we modify
|
||||||
// the diff list, the snapshot to be deleted has been combined or renamed
|
// the diff list, the snapshot to be deleted has been combined or renamed
|
||||||
|
@ -624,7 +622,8 @@ public class INodeDirectory extends INode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
if (prior == null && snapshot == null) {
|
if (prior == null && snapshot == null) {
|
||||||
// destroy the whole subtree and collect blocks that should be deleted
|
// destroy the whole subtree and collect blocks that should be deleted
|
||||||
|
@ -870,7 +869,7 @@ public class INodeDirectory extends INode {
|
||||||
super.dumpTreeRecursively(out, prefix, snapshot);
|
super.dumpTreeRecursively(out, prefix, snapshot);
|
||||||
out.print(", childrenSize=" + getChildrenList(snapshot).size());
|
out.print(", childrenSize=" + getChildrenList(snapshot).size());
|
||||||
if (this instanceof INodeDirectoryWithQuota) {
|
if (this instanceof INodeDirectoryWithQuota) {
|
||||||
// out.print(((INodeDirectoryWithQuota)this).quotaString());
|
out.print(((INodeDirectoryWithQuota)this).quotaString());
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.hadoop.hdfs.protocol.DSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory INode class that has a quota restriction
|
* Directory INode class that has a quota restriction
|
||||||
|
@ -87,18 +86,21 @@ public class INodeDirectoryWithQuota extends INodeDirectory {
|
||||||
* @param nsQuota Namespace quota to be set
|
* @param nsQuota Namespace quota to be set
|
||||||
* @param dsQuota diskspace quota to be set
|
* @param dsQuota diskspace quota to be set
|
||||||
*/
|
*/
|
||||||
public void setQuota(long nsQuota, long dsQuota, Snapshot latest) {
|
public void setQuota(long nsQuota, long dsQuota) {
|
||||||
final INodeDirectoryWithQuota nodeToUpdate
|
this.nsQuota = nsQuota;
|
||||||
= (INodeDirectoryWithQuota)recordModification(latest);
|
this.dsQuota = dsQuota;
|
||||||
nodeToUpdate.nsQuota = nsQuota;
|
|
||||||
nodeToUpdate.dsQuota = dsQuota;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Quota.Counts computeQuotaUsage(Quota.Counts counts) {
|
public final Quota.Counts computeQuotaUsage(Quota.Counts counts,
|
||||||
// use cache value
|
boolean useCache) {
|
||||||
counts.add(Quota.NAMESPACE, namespace);
|
if (useCache) {
|
||||||
counts.add(Quota.DISKSPACE, diskspace);
|
// use cache value
|
||||||
|
counts.add(Quota.NAMESPACE, namespace);
|
||||||
|
counts.add(Quota.DISKSPACE, diskspace);
|
||||||
|
} else {
|
||||||
|
super.computeQuotaUsage(counts, false);
|
||||||
|
}
|
||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +123,9 @@ public class INodeDirectoryWithQuota extends INodeDirectory {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDiskspace(final long computed) {
|
private void checkDiskspace(final long computed) {
|
||||||
if (-1 != getDsQuota() && diskspaceConsumed() != computed) {
|
if (-1 != getDsQuota() && diskspace != computed) {
|
||||||
NameNode.LOG.error("BUG: Inconsistent diskspace for directory "
|
NameNode.LOG.error("BUG: Inconsistent diskspace for directory "
|
||||||
+ getFullPathName() + ". Cached = " + diskspaceConsumed()
|
+ getFullPathName() + ". Cached = " + diskspace
|
||||||
+ " != Computed = " + computed);
|
+ " != Computed = " + computed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,10 +137,25 @@ public class INodeDirectoryWithQuota extends INodeDirectory {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
long diskspaceConsumed() {
|
@Override
|
||||||
return diskspace;
|
public final void addNamespaceConsumed(final int delta)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
if (isQuotaSet()) {
|
||||||
|
// The following steps are important:
|
||||||
|
// check quotas in this inode and all ancestors before changing counts
|
||||||
|
// so that no change is made if there is any quota violation.
|
||||||
|
|
||||||
|
// (1) verify quota in this inode
|
||||||
|
verifyNamespaceQuota(delta);
|
||||||
|
// (2) verify quota and then add count in ancestors
|
||||||
|
super.addNamespaceConsumed(delta);
|
||||||
|
// (3) add count in this inode
|
||||||
|
namespace += delta;
|
||||||
|
} else {
|
||||||
|
super.addNamespaceConsumed(delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update the size of the tree
|
/** Update the size of the tree
|
||||||
*
|
*
|
||||||
* @param nsDelta the change of the tree size
|
* @param nsDelta the change of the tree size
|
||||||
|
@ -162,13 +179,19 @@ public class INodeDirectoryWithQuota extends INodeDirectory {
|
||||||
this.diskspace = diskspace;
|
this.diskspace = diskspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Verify if the namespace quota is violated after applying delta. */
|
||||||
|
void verifyNamespaceQuota(long delta) throws NSQuotaExceededException {
|
||||||
|
if (Quota.isViolated(nsQuota, namespace, delta)) {
|
||||||
|
throw new NSQuotaExceededException(nsQuota, namespace + delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Verify if the namespace count disk space satisfies the quota restriction
|
/** Verify if the namespace count disk space satisfies the quota restriction
|
||||||
* @throws QuotaExceededException if the given quota is less than the count
|
* @throws QuotaExceededException if the given quota is less than the count
|
||||||
*/
|
*/
|
||||||
void verifyQuota(long nsDelta, long dsDelta) throws QuotaExceededException {
|
void verifyQuota(long nsDelta, long dsDelta) throws QuotaExceededException {
|
||||||
if (Quota.isViolated(nsQuota, namespace, nsDelta)) {
|
verifyNamespaceQuota(nsDelta);
|
||||||
throw new NSQuotaExceededException(nsQuota, namespace + nsDelta);
|
|
||||||
}
|
|
||||||
if (Quota.isViolated(dsQuota, diskspace, dsDelta)) {
|
if (Quota.isViolated(dsQuota, diskspace, dsDelta)) {
|
||||||
throw new DSQuotaExceededException(dsQuota, diskspace + dsDelta);
|
throw new DSQuotaExceededException(dsQuota, diskspace + dsDelta);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockCollection;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockCollection;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
||||||
|
@ -132,7 +133,8 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeFile recordModification(final Snapshot latest) {
|
public INodeFile recordModification(final Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
return isInLatestSnapshot(latest)?
|
return isInLatestSnapshot(latest)?
|
||||||
parent.replaceChild4INodeFileWithSnapshot(this)
|
parent.replaceChild4INodeFileWithSnapshot(this)
|
||||||
.recordModification(latest)
|
.recordModification(latest)
|
||||||
|
@ -145,7 +147,18 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
* the {@link FsAction#EXECUTE} action, if any, is ignored.
|
* the {@link FsAction#EXECUTE} action, if any, is ignored.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
final INode setPermission(FsPermission permission, Snapshot latest) {
|
final void setPermission(FsPermission permission) {
|
||||||
|
super.setPermission(permission.applyUMask(UMASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link FsPermission} of this {@link INodeFile}.
|
||||||
|
* Since this is a file,
|
||||||
|
* the {@link FsAction#EXECUTE} action, if any, is ignored.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
final INode setPermission(FsPermission permission, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
return super.setPermission(permission.applyUMask(UMASK), latest);
|
return super.setPermission(permission.applyUMask(UMASK), latest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,15 +183,19 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
: getFileReplication(null);
|
: getFileReplication(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFileReplication(short replication, Snapshot latest) {
|
/** Set the replication factor of this file. */
|
||||||
final INodeFile nodeToUpdate = recordModification(latest);
|
public final void setFileReplication(short replication) {
|
||||||
if (nodeToUpdate != this) {
|
|
||||||
nodeToUpdate.setFileReplication(replication, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
header = HeaderFormat.combineReplication(header, replication);
|
header = HeaderFormat.combineReplication(header, replication);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set the replication factor of this file. */
|
||||||
|
public final INodeFile setFileReplication(short replication, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
final INodeFile nodeToUpdate = recordModification(latest);
|
||||||
|
nodeToUpdate.setFileReplication(replication);
|
||||||
|
return nodeToUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return preferred block size (in bytes) of the file. */
|
/** @return preferred block size (in bytes) of the file. */
|
||||||
@Override
|
@Override
|
||||||
public long getPreferredBlockSize() {
|
public long getPreferredBlockSize() {
|
||||||
|
@ -253,7 +270,8 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (snapshot == null && prior == null) {
|
if (snapshot == null && prior == null) {
|
||||||
// this only happens when deleting the current file
|
// this only happens when deleting the current file
|
||||||
return destroyAndCollectBlocks(collectedBlocks);
|
return destroyAndCollectBlocks(collectedBlocks);
|
||||||
|
@ -282,7 +300,8 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Quota.Counts computeQuotaUsage(Quota.Counts counts) {
|
public final Quota.Counts computeQuotaUsage(Quota.Counts counts,
|
||||||
|
boolean useCache) {
|
||||||
counts.add(Quota.NAMESPACE, this instanceof FileWithSnapshot?
|
counts.add(Quota.NAMESPACE, this instanceof FileWithSnapshot?
|
||||||
((FileWithSnapshot)this).getDiffs().asList().size() + 1: 1);
|
((FileWithSnapshot)this).getDiffs().asList().size() + 1: 1);
|
||||||
counts.add(Quota.DISKSPACE, diskspaceConsumed());
|
counts.add(Quota.DISKSPACE, diskspaceConsumed());
|
||||||
|
@ -397,7 +416,7 @@ public class INodeFile extends INode implements BlockCollection {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
long diskspaceConsumed() {
|
final long diskspaceConsumed() {
|
||||||
// use preferred block size for the last block if it is under construction
|
// use preferred block size for the last block if it is under construction
|
||||||
return computeFileSize(true, true) * getBlockReplication();
|
return computeFileSize(true, true) * getBlockReplication();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Arrays;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfo;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockInfoUnderConstruction;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
||||||
|
@ -131,7 +132,8 @@ public class INodeFileUnderConstruction extends INodeFile implements MutableBloc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeFileUnderConstruction recordModification(final Snapshot latest) {
|
public INodeFileUnderConstruction recordModification(final Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
return isInLatestSnapshot(latest)?
|
return isInLatestSnapshot(latest)?
|
||||||
parent.replaceChild4INodeFileUcWithSnapshot(this)
|
parent.replaceChild4INodeFileUcWithSnapshot(this)
|
||||||
.recordModification(latest)
|
.recordModification(latest)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.PrintWriter;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ public class INodeSymlink extends INode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
INode recordModification(Snapshot latest) {
|
INode recordModification(Snapshot latest) throws NSQuotaExceededException {
|
||||||
return isInLatestSnapshot(latest)?
|
return isInLatestSnapshot(latest)?
|
||||||
parent.saveChild2Snapshot(this, latest, new INodeSymlink(this))
|
parent.saveChild2Snapshot(this, latest, new INodeSymlink(this))
|
||||||
: this;
|
: this;
|
||||||
|
@ -77,7 +78,8 @@ public class INodeSymlink extends INode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Quota.Counts computeQuotaUsage(final Quota.Counts counts) {
|
public Quota.Counts computeQuotaUsage(Quota.Counts counts,
|
||||||
|
boolean updateCache) {
|
||||||
counts.add(Quota.NAMESPACE, 1);
|
counts.add(Quota.NAMESPACE, 1);
|
||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
|
import org.apache.hadoop.hdfs.server.namenode.INode.BlocksMapUpdateInfo;
|
||||||
|
|
||||||
|
@ -48,9 +49,11 @@ abstract class AbstractINodeDiffList<N extends INode,
|
||||||
return Collections.unmodifiableList(diffs);
|
return Collections.unmodifiableList(diffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** clear the diff list */
|
/** clear the diff list, */
|
||||||
void clear() {
|
int clear() {
|
||||||
|
final int n = diffs.size();
|
||||||
diffs.clear();
|
diffs.clear();
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,7 +105,9 @@ abstract class AbstractINodeDiffList<N extends INode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add an {@link AbstractINodeDiff} for the given snapshot. */
|
/** Add an {@link AbstractINodeDiff} for the given snapshot. */
|
||||||
final D addDiff(Snapshot latest, N currentINode) {
|
final D addDiff(Snapshot latest, N currentINode)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
|
currentINode.addNamespaceConsumed(1);
|
||||||
return addLast(factory.createDiff(latest, currentINode));
|
return addLast(factory.createDiff(latest, currentINode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,14 +225,25 @@ abstract class AbstractINodeDiffList<N extends INode,
|
||||||
* Check if the latest snapshot diff exists. If not, add it.
|
* Check if the latest snapshot diff exists. If not, add it.
|
||||||
* @return the latest snapshot diff, which is never null.
|
* @return the latest snapshot diff, which is never null.
|
||||||
*/
|
*/
|
||||||
final D checkAndAddLatestSnapshotDiff(Snapshot latest, N currentINode) {
|
final D checkAndAddLatestSnapshotDiff(Snapshot latest, N currentINode)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
final D last = getLast();
|
final D last = getLast();
|
||||||
return last != null && last.snapshot.equals(latest)? last
|
if (last != null
|
||||||
: addDiff(latest, currentINode);
|
&& Snapshot.ID_COMPARATOR.compare(last.getSnapshot(), latest) >= 0) {
|
||||||
|
return last;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return addDiff(latest, currentINode);
|
||||||
|
} catch(NSQuotaExceededException e) {
|
||||||
|
e.setMessagePrefix("Failed to record modification for snapshot");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save the snapshot copy to the latest snapshot. */
|
/** Save the snapshot copy to the latest snapshot. */
|
||||||
public void saveSelf2Snapshot(Snapshot latest, N currentINode, N snapshotCopy) {
|
public void saveSelf2Snapshot(Snapshot latest, N currentINode, N snapshotCopy)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
checkAndAddLatestSnapshotDiff(latest, currentINode).saveSnapshotCopy(
|
checkAndAddLatestSnapshotDiff(latest, currentINode).saveSnapshotCopy(
|
||||||
snapshotCopy, factory, currentINode);
|
snapshotCopy, factory, currentINode);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Map;
|
||||||
import org.apache.hadoop.HadoopIllegalArgumentException;
|
import org.apache.hadoop.HadoopIllegalArgumentException;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
|
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport;
|
||||||
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffReportEntry;
|
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffReportEntry;
|
||||||
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType;
|
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType;
|
||||||
|
@ -270,7 +271,8 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a snapshot. */
|
/** Add a snapshot. */
|
||||||
Snapshot addSnapshot(int id, String name) throws SnapshotException {
|
Snapshot addSnapshot(int id, String name)
|
||||||
|
throws SnapshotException, NSQuotaExceededException {
|
||||||
//check snapshot quota
|
//check snapshot quota
|
||||||
final int n = getNumSnapshots();
|
final int n = getNumSnapshots();
|
||||||
if (n + 1 > snapshotQuota) {
|
if (n + 1 > snapshotQuota) {
|
||||||
|
@ -315,7 +317,11 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
} else {
|
} else {
|
||||||
final Snapshot snapshot = snapshotsByNames.remove(i);
|
final Snapshot snapshot = snapshotsByNames.remove(i);
|
||||||
Snapshot prior = Snapshot.findLatestSnapshot(this, snapshot);
|
Snapshot prior = Snapshot.findLatestSnapshot(this, snapshot);
|
||||||
cleanSubtree(snapshot, prior, collectedBlocks);
|
try {
|
||||||
|
cleanSubtree(snapshot, prior, collectedBlocks);
|
||||||
|
} catch(NSQuotaExceededException e) {
|
||||||
|
LOG.error("BUG: removeSnapshot increases namespace usage.", e);
|
||||||
|
}
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,7 +433,7 @@ public class INodeDirectorySnapshottable extends INodeDirectoryWithSnapshot {
|
||||||
* Replace itself with {@link INodeDirectoryWithSnapshot} or
|
* Replace itself with {@link INodeDirectoryWithSnapshot} or
|
||||||
* {@link INodeDirectory} depending on the latest snapshot.
|
* {@link INodeDirectory} depending on the latest snapshot.
|
||||||
*/
|
*/
|
||||||
void replaceSelf(final Snapshot latest) {
|
void replaceSelf(final Snapshot latest) throws NSQuotaExceededException {
|
||||||
if (latest == null) {
|
if (latest == null) {
|
||||||
Preconditions.checkState(getLastSnapshot() == null,
|
Preconditions.checkState(getLastSnapshot() == null,
|
||||||
"latest == null but getLastSnapshot() != null, this=%s", this);
|
"latest == null but getLastSnapshot() != null, this=%s", this);
|
||||||
|
|
|
@ -25,10 +25,12 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffReportEntry;
|
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffReportEntry;
|
||||||
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType;
|
import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization;
|
import org.apache.hadoop.hdfs.server.namenode.FSImageSerialization;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.Quota;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
import org.apache.hadoop.hdfs.server.namenode.INode.Content.CountsMap.Key;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeDirectoryWithQuota;
|
import org.apache.hadoop.hdfs.server.namenode.INodeDirectoryWithQuota;
|
||||||
|
@ -79,7 +81,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
for (INode c : createdList) {
|
for (INode c : createdList) {
|
||||||
removedNum += c.destroyAndCollectBlocks(collectedBlocks);
|
removedNum += c.destroyAndCollectBlocks(collectedBlocks);
|
||||||
// if c is also contained in the children list, remove it
|
// if c is also contained in the children list, remove it
|
||||||
currentINode.removeChild(c, null);
|
currentINode.removeChild(c);
|
||||||
}
|
}
|
||||||
createdList.clear();
|
createdList.clear();
|
||||||
return removedNum;
|
return removedNum;
|
||||||
|
@ -353,7 +355,7 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
new INodeDirectoryWithQuota(currentDir, false,
|
new INodeDirectoryWithQuota(currentDir, false,
|
||||||
currentDir.getNsQuota(), currentDir.getDsQuota())
|
currentDir.getNsQuota(), currentDir.getDsQuota())
|
||||||
: new INodeDirectory(currentDir, false);
|
: new INodeDirectory(currentDir, false);
|
||||||
copy.setChildren(null);
|
copy.clearChildren();
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,21 +464,23 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeDirectoryWithSnapshot recordModification(final Snapshot latest) {
|
public INodeDirectoryWithSnapshot recordModification(final Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
return isInLatestSnapshot(latest)?
|
return isInLatestSnapshot(latest)?
|
||||||
saveSelf2Snapshot(latest, null): this;
|
saveSelf2Snapshot(latest, null): this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save the snapshot copy to the latest snapshot. */
|
/** Save the snapshot copy to the latest snapshot. */
|
||||||
public INodeDirectoryWithSnapshot saveSelf2Snapshot(
|
public INodeDirectoryWithSnapshot saveSelf2Snapshot(
|
||||||
final Snapshot latest, final INodeDirectory snapshotCopy) {
|
final Snapshot latest, final INodeDirectory snapshotCopy)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
diffs.saveSelf2Snapshot(latest, this, snapshotCopy);
|
diffs.saveSelf2Snapshot(latest, this, snapshotCopy);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INode saveChild2Snapshot(final INode child, final Snapshot latest,
|
public INode saveChild2Snapshot(final INode child, final Snapshot latest,
|
||||||
final INode snapshotCopy) {
|
final INode snapshotCopy) throws NSQuotaExceededException {
|
||||||
Preconditions.checkArgument(!child.isDirectory(),
|
Preconditions.checkArgument(!child.isDirectory(),
|
||||||
"child is a directory, child=%s", child);
|
"child is a directory, child=%s", child);
|
||||||
if (latest == null) {
|
if (latest == null) {
|
||||||
|
@ -494,7 +498,8 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addChild(INode inode, boolean setModTime, Snapshot latest) {
|
public boolean addChild(INode inode, boolean setModTime, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
ChildrenDiff diff = null;
|
ChildrenDiff diff = null;
|
||||||
Integer undoInfo = null;
|
Integer undoInfo = null;
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
|
@ -509,7 +514,8 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeChild(INode child, Snapshot latest) {
|
public boolean removeChild(INode child, Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
ChildrenDiff diff = null;
|
ChildrenDiff diff = null;
|
||||||
UndoInfo<INode> undoInfo = null;
|
UndoInfo<INode> undoInfo = null;
|
||||||
if (latest != null) {
|
if (latest != null) {
|
||||||
|
@ -605,7 +611,8 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (snapshot == null) { // delete the current directory
|
if (snapshot == null) { // delete the current directory
|
||||||
recordModification(prior);
|
recordModification(prior);
|
||||||
|
@ -637,11 +644,24 @@ public class INodeDirectoryWithSnapshot extends INodeDirectoryWithQuota {
|
||||||
for (DirectoryDiff diff : diffs) {
|
for (DirectoryDiff diff : diffs) {
|
||||||
total += diff.destroyAndCollectBlocks(this, collectedBlocks);
|
total += diff.destroyAndCollectBlocks(this, collectedBlocks);
|
||||||
}
|
}
|
||||||
diffs.clear();
|
total += diffs.clear();
|
||||||
total += super.destroyAndCollectBlocks(collectedBlocks);
|
total += super.destroyAndCollectBlocks(collectedBlocks);
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Quota.Counts computeQuotaUsage4CurrentDirectory(Quota.Counts counts) {
|
||||||
|
super.computeQuotaUsage4CurrentDirectory(counts);
|
||||||
|
|
||||||
|
for(DirectoryDiff d : diffs) {
|
||||||
|
for(INode deleted : d.getChildrenDiff().getDeletedList()) {
|
||||||
|
deleted.computeQuotaUsage(counts, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counts.add(Quota.NAMESPACE, diffs.asList().size());
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.CountsMap computeContentSummary(
|
public Content.CountsMap computeContentSummary(
|
||||||
final Content.CountsMap countsMap) {
|
final Content.CountsMap countsMap) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.hadoop.hdfs.server.namenode.snapshot;
|
package org.apache.hadoop.hdfs.server.namenode.snapshot;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFileUnderConstruction;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFileUnderConstruction;
|
||||||
|
@ -75,8 +76,8 @@ public class INodeFileUnderConstructionWithSnapshot
|
||||||
assertAllBlocksComplete();
|
assertAllBlocksComplete();
|
||||||
final long atime = getModificationTime();
|
final long atime = getModificationTime();
|
||||||
final INodeFileWithSnapshot f = new INodeFileWithSnapshot(this, getDiffs());
|
final INodeFileWithSnapshot f = new INodeFileWithSnapshot(this, getDiffs());
|
||||||
f.setModificationTime(mtime, null);
|
f.setModificationTime(mtime);
|
||||||
f.setAccessTime(atime, null);
|
f.setAccessTime(atime);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ public class INodeFileUnderConstructionWithSnapshot
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeFileUnderConstructionWithSnapshot recordModification(
|
public INodeFileUnderConstructionWithSnapshot recordModification(
|
||||||
final Snapshot latest) {
|
final Snapshot latest) throws NSQuotaExceededException {
|
||||||
if (isInLatestSnapshot(latest)) {
|
if (isInLatestSnapshot(latest)) {
|
||||||
diffs.saveSelf2Snapshot(latest, this, null);
|
diffs.saveSelf2Snapshot(latest, this, null);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,8 @@ public class INodeFileUnderConstructionWithSnapshot
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (snapshot == null) { // delete the current file
|
if (snapshot == null) { // delete the current file
|
||||||
recordModification(prior);
|
recordModification(prior);
|
||||||
isCurrentFileDeleted = true;
|
isCurrentFileDeleted = true;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.hadoop.hdfs.server.namenode.snapshot;
|
package org.apache.hadoop.hdfs.server.namenode.snapshot;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
import org.apache.hadoop.hdfs.server.namenode.INodeFile;
|
||||||
|
|
||||||
|
@ -64,7 +65,8 @@ public class INodeFileWithSnapshot extends INodeFile
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public INodeFileWithSnapshot recordModification(final Snapshot latest) {
|
public INodeFileWithSnapshot recordModification(final Snapshot latest)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (isInLatestSnapshot(latest)) {
|
if (isInLatestSnapshot(latest)) {
|
||||||
diffs.saveSelf2Snapshot(latest, this, null);
|
diffs.saveSelf2Snapshot(latest, this, null);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +85,8 @@ public class INodeFileWithSnapshot extends INodeFile
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
public int cleanSubtree(final Snapshot snapshot, Snapshot prior,
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks)
|
||||||
|
throws NSQuotaExceededException {
|
||||||
if (snapshot == null) { // delete the current file
|
if (snapshot == null) { // delete the current file
|
||||||
recordModification(prior);
|
recordModification(prior);
|
||||||
isCurrentFileDeleted = true;
|
isCurrentFileDeleted = true;
|
||||||
|
@ -98,8 +101,8 @@ public class INodeFileWithSnapshot extends INodeFile
|
||||||
public int destroyAndCollectBlocks(
|
public int destroyAndCollectBlocks(
|
||||||
final BlocksMapUpdateInfo collectedBlocks) {
|
final BlocksMapUpdateInfo collectedBlocks) {
|
||||||
Preconditions.checkState(this.isCurrentFileDeleted);
|
Preconditions.checkState(this.isCurrentFileDeleted);
|
||||||
diffs.clear();
|
final int n = diffs.clear();
|
||||||
return super.destroyAndCollectBlocks(collectedBlocks);
|
return n + super.destroyAndCollectBlocks(collectedBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -129,6 +129,8 @@ public class SnapshotManager implements SnapshotStats {
|
||||||
final INodesInPath i = fsdir.getINodesInPath4Write(path);
|
final INodesInPath i = fsdir.getINodesInPath4Write(path);
|
||||||
final INodeDirectorySnapshottable srcRoot
|
final INodeDirectorySnapshottable srcRoot
|
||||||
= INodeDirectorySnapshottable.valueOf(i.getLastINode(), path);
|
= INodeDirectorySnapshottable.valueOf(i.getLastINode(), path);
|
||||||
|
|
||||||
|
fsdir.verifyMaxComponentLength(snapshotName, path, 0);
|
||||||
srcRoot.addSnapshot(snapshotCounter, snapshotName);
|
srcRoot.addSnapshot(snapshotCounter, snapshotName);
|
||||||
|
|
||||||
//create success, update id
|
//create success, update id
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -59,7 +57,6 @@ public class TestFSImageWithSnapshot {
|
||||||
static final int BLOCKSIZE = 1024;
|
static final int BLOCKSIZE = 1024;
|
||||||
static final long txid = 1;
|
static final long txid = 1;
|
||||||
|
|
||||||
private final Path rootDir = new Path("/");
|
|
||||||
private final Path dir = new Path("/TestSnapshot");
|
private final Path dir = new Path("/TestSnapshot");
|
||||||
private static String testDir =
|
private static String testDir =
|
||||||
System.getProperty("test.build.data", "build/test/data");
|
System.getProperty("test.build.data", "build/test/data");
|
||||||
|
@ -114,10 +111,7 @@ public class TestFSImageWithSnapshot {
|
||||||
*/
|
*/
|
||||||
private File dumpTree2File(String fileSuffix) throws IOException {
|
private File dumpTree2File(String fileSuffix) throws IOException {
|
||||||
File file = getDumpTreeFile(testDir, fileSuffix);
|
File file = getDumpTreeFile(testDir, fileSuffix);
|
||||||
PrintWriter out = new PrintWriter(new FileWriter(file, false), true);
|
SnapshotTestHelper.dumpTree2File(fsn.getFSDirectory(), file);
|
||||||
fsn.getFSDirectory().getINode(rootDir.toString())
|
|
||||||
.dumpTreeRecursively(out, new StringBuilder(), null);
|
|
||||||
out.close();
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +149,8 @@ public class TestFSImageWithSnapshot {
|
||||||
fsn.getFSDirectory().writeLock();
|
fsn.getFSDirectory().writeLock();
|
||||||
try {
|
try {
|
||||||
loader.load(imageFile);
|
loader.load(imageFile);
|
||||||
|
FSImage.updateCountForQuota(
|
||||||
|
(INodeDirectoryWithQuota)fsn.getFSDirectory().getINode("/"));
|
||||||
} finally {
|
} finally {
|
||||||
fsn.getFSDirectory().writeUnlock();
|
fsn.getFSDirectory().writeUnlock();
|
||||||
fsn.writeUnlock();
|
fsn.writeUnlock();
|
||||||
|
|
|
@ -160,7 +160,7 @@ public class TestFsLimits {
|
||||||
Class<?> generated = null;
|
Class<?> generated = null;
|
||||||
try {
|
try {
|
||||||
fs.verifyFsLimits(inodes, 1, child);
|
fs.verifyFsLimits(inodes, 1, child);
|
||||||
rootInode.addChild(child, false, null);
|
rootInode.addChild(child);
|
||||||
} catch (QuotaExceededException e) {
|
} catch (QuotaExceededException e) {
|
||||||
generated = e.getClass();
|
generated = e.getClass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,11 +149,11 @@ public class TestINodeFile {
|
||||||
assertEquals("f", inf.getFullPathName());
|
assertEquals("f", inf.getFullPathName());
|
||||||
assertEquals("", inf.getLocalParentDir());
|
assertEquals("", inf.getLocalParentDir());
|
||||||
|
|
||||||
dir.addChild(inf, false, null);
|
dir.addChild(inf);
|
||||||
assertEquals("d"+Path.SEPARATOR+"f", inf.getFullPathName());
|
assertEquals("d"+Path.SEPARATOR+"f", inf.getFullPathName());
|
||||||
assertEquals("d", inf.getLocalParentDir());
|
assertEquals("d", inf.getLocalParentDir());
|
||||||
|
|
||||||
root.addChild(dir, false, null);
|
root.addChild(dir);
|
||||||
assertEquals(Path.SEPARATOR+"d"+Path.SEPARATOR+"f", inf.getFullPathName());
|
assertEquals(Path.SEPARATOR+"d"+Path.SEPARATOR+"f", inf.getFullPathName());
|
||||||
assertEquals(Path.SEPARATOR+"d", dir.getFullPathName());
|
assertEquals(Path.SEPARATOR+"d", dir.getFullPathName());
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -48,6 +49,7 @@ import org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceStorage;
|
||||||
import org.apache.hadoop.hdfs.server.datanode.DataBlockScanner;
|
import org.apache.hadoop.hdfs.server.datanode.DataBlockScanner;
|
||||||
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
||||||
import org.apache.hadoop.hdfs.server.datanode.DirectoryScanner;
|
import org.apache.hadoop.hdfs.server.datanode.DirectoryScanner;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
||||||
|
@ -128,6 +130,8 @@ public class SnapshotTestHelper {
|
||||||
assertTrue(hdfs.exists(snapshotRoot));
|
assertTrue(hdfs.exists(snapshotRoot));
|
||||||
hdfs.allowSnapshot(snapshotRoot.toString());
|
hdfs.allowSnapshot(snapshotRoot.toString());
|
||||||
hdfs.createSnapshot(snapshotRoot, snapshotName);
|
hdfs.createSnapshot(snapshotRoot, snapshotName);
|
||||||
|
// set quota to a large value for testing counts
|
||||||
|
hdfs.setQuota(snapshotRoot, Long.MAX_VALUE-1, Long.MAX_VALUE-1);
|
||||||
return SnapshotTestHelper.getSnapshotRoot(snapshotRoot, snapshotName);
|
return SnapshotTestHelper.getSnapshotRoot(snapshotRoot, snapshotName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +196,11 @@ public class SnapshotTestHelper {
|
||||||
}
|
}
|
||||||
private static void compareDumpedTreeInFile(File file1, File file2,
|
private static void compareDumpedTreeInFile(File file1, File file2,
|
||||||
boolean print) throws IOException {
|
boolean print) throws IOException {
|
||||||
|
if (print) {
|
||||||
|
printFile(file1);
|
||||||
|
printFile(file2);
|
||||||
|
}
|
||||||
|
|
||||||
BufferedReader reader1 = new BufferedReader(new FileReader(file1));
|
BufferedReader reader1 = new BufferedReader(new FileReader(file1));
|
||||||
BufferedReader reader2 = new BufferedReader(new FileReader(file2));
|
BufferedReader reader2 = new BufferedReader(new FileReader(file2));
|
||||||
try {
|
try {
|
||||||
|
@ -238,6 +247,25 @@ public class SnapshotTestHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void printFile(File f) throws IOException {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("File: " + f);
|
||||||
|
BufferedReader in = new BufferedReader(new FileReader(f));
|
||||||
|
try {
|
||||||
|
for(String line; (line = in.readLine()) != null; ) {
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dumpTree2File(FSDirectory fsdir, File f) throws IOException{
|
||||||
|
final PrintWriter out = new PrintWriter(new FileWriter(f, false), true);
|
||||||
|
fsdir.getINode("/").dumpTreeRecursively(out, new StringBuilder(), null);
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the path for a snapshot file.
|
* Generate the path for a snapshot file.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,8 +31,11 @@ import org.apache.hadoop.hdfs.DFSTestUtil;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
import org.apache.hadoop.hdfs.server.namenode.INodeDirectory;
|
||||||
|
import org.apache.hadoop.ipc.RemoteException;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
@ -165,6 +168,65 @@ public class TestNestedSnapshots {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSnapshotWithQuota() throws Exception {
|
||||||
|
final String dirStr = "/testSnapshotWithQuota/dir";
|
||||||
|
final Path dir = new Path(dirStr);
|
||||||
|
hdfs.mkdirs(dir, new FsPermission((short)0777));
|
||||||
|
hdfs.allowSnapshot(dirStr);
|
||||||
|
|
||||||
|
// set namespace quota
|
||||||
|
final int NS_QUOTA = 6;
|
||||||
|
hdfs.setQuota(dir, NS_QUOTA, HdfsConstants.QUOTA_DONT_SET);
|
||||||
|
|
||||||
|
// create object to use up the quota.
|
||||||
|
final Path foo = new Path(dir, "foo");
|
||||||
|
final Path f1 = new Path(foo, "f1");
|
||||||
|
DFSTestUtil.createFile(hdfs, f1, BLOCKSIZE, REPLICATION, SEED);
|
||||||
|
hdfs.createSnapshot(dir, "s0");
|
||||||
|
final Path f2 = new Path(foo, "f2");
|
||||||
|
DFSTestUtil.createFile(hdfs, f2, BLOCKSIZE, REPLICATION, SEED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// normal create file should fail with quota
|
||||||
|
final Path f3 = new Path(foo, "f3");
|
||||||
|
DFSTestUtil.createFile(hdfs, f3, BLOCKSIZE, REPLICATION, SEED);
|
||||||
|
Assert.fail();
|
||||||
|
} catch(NSQuotaExceededException e) {
|
||||||
|
SnapshotTestHelper.LOG.info("The exception is expected.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// createSnapshot should fail with quota
|
||||||
|
hdfs.createSnapshot(dir, "s1");
|
||||||
|
Assert.fail();
|
||||||
|
} catch(RemoteException re) {
|
||||||
|
final IOException ioe = re.unwrapRemoteException();
|
||||||
|
if (ioe instanceof NSQuotaExceededException) {
|
||||||
|
SnapshotTestHelper.LOG.info("The exception is expected.", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// setPermission f1 should fail with quote since it cannot add diff.
|
||||||
|
hdfs.setPermission(f1, new FsPermission((short)0));
|
||||||
|
Assert.fail();
|
||||||
|
} catch(RemoteException re) {
|
||||||
|
final IOException ioe = re.unwrapRemoteException();
|
||||||
|
if (ioe instanceof NSQuotaExceededException) {
|
||||||
|
SnapshotTestHelper.LOG.info("The exception is expected.", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPermission f2 since it was created after the snapshot
|
||||||
|
hdfs.setPermission(f2, new FsPermission((short)0));
|
||||||
|
|
||||||
|
// increase quota and retry the commands.
|
||||||
|
hdfs.setQuota(dir, NS_QUOTA + 2, HdfsConstants.QUOTA_DONT_SET);
|
||||||
|
hdfs.createSnapshot(dir, "s1");
|
||||||
|
hdfs.setPermission(foo, new FsPermission((short)0444));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test {@link Snapshot#ID_COMPARATOR}.
|
* Test {@link Snapshot#ID_COMPARATOR}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,8 +21,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
@ -171,7 +169,7 @@ public class TestSnapshot {
|
||||||
private File getDumpTreeFile(String dir, String suffix) {
|
private File getDumpTreeFile(String dir, String suffix) {
|
||||||
return new File(dir, String.format("dumptree_%s", suffix));
|
return new File(dir, String.format("dumptree_%s", suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restart the cluster to check edit log applying and fsimage saving/loading
|
* Restart the cluster to check edit log applying and fsimage saving/loading
|
||||||
*/
|
*/
|
||||||
|
@ -180,10 +178,7 @@ public class TestSnapshot {
|
||||||
File fsnMiddle = getDumpTreeFile(testDir, "middle");
|
File fsnMiddle = getDumpTreeFile(testDir, "middle");
|
||||||
File fsnAfter = getDumpTreeFile(testDir, "after");
|
File fsnAfter = getDumpTreeFile(testDir, "after");
|
||||||
|
|
||||||
String rootDir = "/";
|
SnapshotTestHelper.dumpTree2File(fsdir, fsnBefore);
|
||||||
PrintWriter out = new PrintWriter(new FileWriter(fsnBefore, false), true);
|
|
||||||
fsdir.getINode(rootDir).dumpTreeRecursively(out, new StringBuilder(), null);
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
cluster = new MiniDFSCluster.Builder(conf).format(false)
|
cluster = new MiniDFSCluster.Builder(conf).format(false)
|
||||||
|
@ -191,11 +186,8 @@ public class TestSnapshot {
|
||||||
cluster.waitActive();
|
cluster.waitActive();
|
||||||
fsn = cluster.getNamesystem();
|
fsn = cluster.getNamesystem();
|
||||||
hdfs = cluster.getFileSystem();
|
hdfs = cluster.getFileSystem();
|
||||||
// later check fsnMiddle to see if the edit log is recorded and applied
|
// later check fsnMiddle to see if the edit log is applied correctly
|
||||||
// correctly
|
SnapshotTestHelper.dumpTree2File(fsdir, fsnMiddle);
|
||||||
out = new PrintWriter(new FileWriter(fsnMiddle, false), true);
|
|
||||||
fsdir.getINode(rootDir).dumpTreeRecursively(out, new StringBuilder(), null);
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
// save namespace and restart cluster
|
// save namespace and restart cluster
|
||||||
hdfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
|
hdfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
|
||||||
|
@ -208,9 +200,7 @@ public class TestSnapshot {
|
||||||
fsn = cluster.getNamesystem();
|
fsn = cluster.getNamesystem();
|
||||||
hdfs = cluster.getFileSystem();
|
hdfs = cluster.getFileSystem();
|
||||||
// dump the namespace loaded from fsimage
|
// dump the namespace loaded from fsimage
|
||||||
out = new PrintWriter(new FileWriter(fsnAfter, false), true);
|
SnapshotTestHelper.dumpTree2File(fsdir, fsnAfter);
|
||||||
fsdir.getINode(rootDir).dumpTreeRecursively(out, new StringBuilder(), null);
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
SnapshotTestHelper.compareDumpedTreeInFile(fsnBefore, fsnMiddle);
|
SnapshotTestHelper.compareDumpedTreeInFile(fsnBefore, fsnMiddle);
|
||||||
SnapshotTestHelper.compareDumpedTreeInFile(fsnBefore, fsnAfter);
|
SnapshotTestHelper.compareDumpedTreeInFile(fsnBefore, fsnAfter);
|
||||||
|
|
|
@ -301,7 +301,7 @@ public class TestDiff {
|
||||||
Assert.assertTrue(i >= 0);
|
Assert.assertTrue(i >= 0);
|
||||||
final INodeDirectory oldinode = (INodeDirectory)current.get(i);
|
final INodeDirectory oldinode = (INodeDirectory)current.get(i);
|
||||||
final INodeDirectory newinode = new INodeDirectory(oldinode, false);
|
final INodeDirectory newinode = new INodeDirectory(oldinode, false);
|
||||||
newinode.updateModificationTime(oldinode.getModificationTime() + 1, null);
|
newinode.setModificationTime(oldinode.getModificationTime() + 1);
|
||||||
|
|
||||||
current.set(i, newinode);
|
current.set(i, newinode);
|
||||||
if (diff != null) {
|
if (diff != null) {
|
||||||
|
|
Loading…
Reference in New Issue