HDFS-7463. Simplify FSNamesystem#getBlockLocationsUpdateTimes. Contributed by Haohui Mai.

This commit is contained in:
Haohui Mai 2014-12-10 23:01:17 -08:00
parent cb99f43305
commit d693a252bd
6 changed files with 121 additions and 128 deletions

View File

@ -449,6 +449,8 @@ Release 2.7.0 - UNRELEASED
HDFS-7498. Simplify the logic in INodesInPath. (jing9) HDFS-7498. Simplify the logic in INodesInPath. (jing9)
HDFS-7463. Simplify FSNamesystem#getBlockLocationsUpdateTimes. (wheat9)
OPTIMIZATIONS OPTIMIZATIONS
HDFS-7454. Reduce memory footprint for AclEntries in NameNode. HDFS-7454. Reduce memory footprint for AclEntries in NameNode.

View File

@ -1749,27 +1749,76 @@ private void setOwnerInt(final String srcArg, String username, String group)
logAuditEvent(true, "setOwner", srcArg, null, resultingStat); logAuditEvent(true, "setOwner", srcArg, null, resultingStat);
} }
static class GetBlockLocationsResult {
final INodesInPath iip;
final LocatedBlocks blocks;
boolean updateAccessTime() {
return iip != null;
}
private GetBlockLocationsResult(INodesInPath iip, LocatedBlocks blocks) {
this.iip = iip;
this.blocks = blocks;
}
}
/** /**
* Get block locations within the specified range. * Get block locations within the specified range.
* @see ClientProtocol#getBlockLocations(String, long, long) * @see ClientProtocol#getBlockLocations(String, long, long)
*/ */
LocatedBlocks getBlockLocations(String clientMachine, String src, LocatedBlocks getBlockLocations(String clientMachine, String src,
long offset, long length) throws AccessControlException, long offset, long length) throws IOException {
FileNotFoundException, UnresolvedLinkException, IOException { checkOperation(OperationCategory.READ);
LocatedBlocks blocks = getBlockLocations(src, offset, length, true, true, GetBlockLocationsResult res = null;
true); readLock();
try {
checkOperation(OperationCategory.READ);
res = getBlockLocations(src, offset, length, true, true);
} catch (AccessControlException e) {
logAuditEvent(false, "open", src);
throw e;
} finally {
readUnlock();
}
logAuditEvent(true, "open", src);
if (res == null) {
return null;
}
if (res.updateAccessTime()) {
writeLock();
final long now = now();
try {
checkOperation(OperationCategory.WRITE);
INode inode = res.iip.getLastINode();
boolean updateAccessTime = now > inode.getAccessTime() +
getAccessTimePrecision();
if (!isInSafeMode() && updateAccessTime) {
boolean changed = dir.setTimes(
inode, -1, now, false, res.iip.getLatestSnapshotId());
if (changed) {
getEditLog().logTimes(src, -1, now);
}
}
} catch (Throwable e) {
LOG.warn("Failed to update the access time of " + src, e);
} finally {
writeUnlock();
}
}
LocatedBlocks blocks = res.blocks;
if (blocks != null) { if (blocks != null) {
blockManager.getDatanodeManager().sortLocatedBlocks(clientMachine, blockManager.getDatanodeManager().sortLocatedBlocks(
blocks.getLocatedBlocks()); clientMachine, blocks.getLocatedBlocks());
// lastBlock is not part of getLocatedBlocks(), might need to sort it too // lastBlock is not part of getLocatedBlocks(), might need to sort it too
LocatedBlock lastBlock = blocks.getLastLocatedBlock(); LocatedBlock lastBlock = blocks.getLastLocatedBlock();
if (lastBlock != null) { if (lastBlock != null) {
ArrayList<LocatedBlock> lastBlockList = ArrayList<LocatedBlock> lastBlockList = Lists.newArrayList(lastBlock);
Lists.newArrayListWithCapacity(1); blockManager.getDatanodeManager().sortLocatedBlocks(
lastBlockList.add(lastBlock); clientMachine, lastBlockList);
blockManager.getDatanodeManager().sortLocatedBlocks(clientMachine,
lastBlockList);
} }
} }
return blocks; return blocks;
@ -1778,24 +1827,11 @@ LocatedBlocks getBlockLocations(String clientMachine, String src,
/** /**
* Get block locations within the specified range. * Get block locations within the specified range.
* @see ClientProtocol#getBlockLocations(String, long, long) * @see ClientProtocol#getBlockLocations(String, long, long)
* @throws FileNotFoundException, UnresolvedLinkException, IOException * @throws IOException
*/ */
LocatedBlocks getBlockLocations(String src, long offset, long length, GetBlockLocationsResult getBlockLocations(
boolean doAccessTime, boolean needBlockToken, boolean checkSafeMode) String src, long offset, long length, boolean needBlockToken,
throws FileNotFoundException, UnresolvedLinkException, IOException { boolean checkSafeMode) throws IOException {
try {
return getBlockLocationsInt(src, offset, length, doAccessTime,
needBlockToken, checkSafeMode);
} catch (AccessControlException e) {
logAuditEvent(false, "open", src);
throw e;
}
}
private LocatedBlocks getBlockLocationsInt(String src, long offset,
long length, boolean doAccessTime, boolean needBlockToken,
boolean checkSafeMode)
throws FileNotFoundException, UnresolvedLinkException, IOException {
if (offset < 0) { if (offset < 0) {
throw new HadoopIllegalArgumentException( throw new HadoopIllegalArgumentException(
"Negative offset is not supported. File: " + src); "Negative offset is not supported. File: " + src);
@ -1804,11 +1840,11 @@ private LocatedBlocks getBlockLocationsInt(String src, long offset,
throw new HadoopIllegalArgumentException( throw new HadoopIllegalArgumentException(
"Negative length is not supported. File: " + src); "Negative length is not supported. File: " + src);
} }
final LocatedBlocks ret = getBlockLocationsUpdateTimes(src, final GetBlockLocationsResult ret = getBlockLocationsInt(
offset, length, doAccessTime, needBlockToken); src, offset, length, needBlockToken);
logAuditEvent(true, "open", src);
if (checkSafeMode && isInSafeMode()) { if (checkSafeMode && isInSafeMode()) {
for (LocatedBlock b : ret.getLocatedBlocks()) { for (LocatedBlock b : ret.blocks.getLocatedBlocks()) {
// if safemode & no block locations yet then throw safemodeException // if safemode & no block locations yet then throw safemodeException
if ((b.getLocations() == null) || (b.getLocations().length == 0)) { if ((b.getLocations() == null) || (b.getLocations().length == 0)) {
SafeModeException se = new SafeModeException( SafeModeException se = new SafeModeException(
@ -1825,64 +1861,22 @@ private LocatedBlocks getBlockLocationsInt(String src, long offset,
return ret; return ret;
} }
/* private GetBlockLocationsResult getBlockLocationsInt(
* Get block locations within the specified range, updating the final String srcArg, long offset, long length, boolean needBlockToken)
* access times if necessary.
*/
private LocatedBlocks getBlockLocationsUpdateTimes(final String srcArg,
long offset, long length, boolean doAccessTime, boolean needBlockToken)
throws IOException { throws IOException {
String src = srcArg; String src = srcArg;
FSPermissionChecker pc = getPermissionChecker(); FSPermissionChecker pc = getPermissionChecker();
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src); byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
for (int attempt = 0; attempt < 2; attempt++) {
boolean isReadOp = (attempt == 0);
if (isReadOp) { // first attempt is with readlock
checkOperation(OperationCategory.READ);
readLock();
} else { // second attempt is with write lock
checkOperation(OperationCategory.WRITE);
writeLock(); // writelock is needed to set accesstime
}
try {
if (isReadOp) {
checkOperation(OperationCategory.READ);
} else {
checkOperation(OperationCategory.WRITE);
}
src = dir.resolvePath(pc, src, pathComponents); src = dir.resolvePath(pc, src, pathComponents);
final INodesInPath iip = dir.getINodesInPath(src, true); final INodesInPath iip = dir.getINodesInPath(src, true);
if (isPermissionEnabled) {
dir.checkPathAccess(pc, iip, FsAction.READ);
}
// if the namenode is in safemode, then do not update access time
if (isInSafeMode()) {
doAccessTime = false;
}
final INodeFile inode = INodeFile.valueOf(iip.getLastINode(), src); final INodeFile inode = INodeFile.valueOf(iip.getLastINode(), src);
if (isPermissionEnabled) { if (isPermissionEnabled) {
dir.checkPathAccess(pc, iip, FsAction.READ);
checkUnreadableBySuperuser(pc, inode, iip.getPathSnapshotId()); checkUnreadableBySuperuser(pc, inode, iip.getPathSnapshotId());
} }
if (!iip.isSnapshot() //snapshots are readonly, so don't update atime.
&& doAccessTime && isAccessTimeSupported()) { final long fileSize = iip.isSnapshot()
final long now = now(); ? inode.computeFileSize(iip.getPathSnapshotId())
if (now > inode.getAccessTime() + getAccessTimePrecision()) {
// if we have to set access time but we only have the readlock, then
// restart this entire operation with the writeLock.
if (isReadOp) {
continue;
}
boolean changed = dir.setTimes(inode, -1, now, false,
iip.getLatestSnapshotId());
if (changed) {
getEditLog().logTimes(src, -1, now);
}
}
}
final long fileSize = iip.isSnapshot() ?
inode.computeFileSize(iip.getPathSnapshotId())
: inode.computeFileSizeNotIncludingLastUcBlock(); : inode.computeFileSizeNotIncludingLastUcBlock();
boolean isUc = inode.isUnderConstruction(); boolean isUc = inode.isUnderConstruction();
if (iip.isSnapshot()) { if (iip.isSnapshot()) {
@ -1893,27 +1887,23 @@ && doAccessTime && isAccessTimeSupported()) {
} }
final FileEncryptionInfo feInfo = final FileEncryptionInfo feInfo =
FSDirectory.isReservedRawName(srcArg) ? FSDirectory.isReservedRawName(srcArg) ? null
null : dir.getFileEncryptionInfo(inode, iip.getPathSnapshotId(), : dir.getFileEncryptionInfo(inode, iip.getPathSnapshotId(), iip);
iip);
final LocatedBlocks blocks = blockManager.createLocatedBlocks(
inode.getBlocks(), fileSize, isUc, offset, length, needBlockToken,
iip.isSnapshot(), feInfo);
final LocatedBlocks blocks =
blockManager.createLocatedBlocks(inode.getBlocks(), fileSize,
isUc, offset, length, needBlockToken, iip.isSnapshot(), feInfo);
// Set caching information for the located blocks. // Set caching information for the located blocks.
for (LocatedBlock lb : blocks.getLocatedBlocks()) { for (LocatedBlock lb : blocks.getLocatedBlocks()) {
cacheManager.setCachedLocations(lb); cacheManager.setCachedLocations(lb);
} }
return blocks;
} finally { final long now = now();
if (isReadOp) { boolean updateAccessTime = isAccessTimeSupported() && !isInSafeMode()
readUnlock(); && !iip.isSnapshot()
} else { && now > inode.getAccessTime() + getAccessTimePrecision();
writeUnlock(); return new GetBlockLocationsResult(updateAccessTime ? iip : null, blocks);
}
}
}
return null; // can never reach here
} }
/** /**

View File

@ -443,12 +443,15 @@ void check(String parent, HdfsFileStatus file, Result res) throws IOException {
long fileLen = file.getLen(); long fileLen = file.getLen();
// Get block locations without updating the file access time // Get block locations without updating the file access time
// and without block access tokens // and without block access tokens
LocatedBlocks blocks; LocatedBlocks blocks = null;
FSNamesystem fsn = namenode.getNamesystem();
fsn.readLock();
try { try {
blocks = namenode.getNamesystem().getBlockLocations(path, 0, blocks = fsn.getBlockLocations(path, 0, fileLen, false, false).blocks;
fileLen, false, false, false);
} catch (FileNotFoundException fnfe) { } catch (FileNotFoundException fnfe) {
blocks = null; blocks = null;
} finally {
fsn.readUnlock();
} }
if (blocks == null) { // the file is deleted if (blocks == null) { // the file is deleted
return; return;

View File

@ -167,9 +167,7 @@ public void testReadSelectNonStaleDatanode() throws Exception {
if (stm != null) { if (stm != null) {
stm.close(); stm.close();
} }
if (client != null) {
client.close(); client.close();
}
cluster.shutdown(); cluster.shutdown();
} }
} }

View File

@ -64,8 +64,8 @@ public static FSNamesystem getNamesystem(NameNode namenode) {
*/ */
public static LocatedBlocks getBlockLocations(NameNode namenode, public static LocatedBlocks getBlockLocations(NameNode namenode,
String src, long offset, long length) throws IOException { String src, long offset, long length) throws IOException {
return namenode.getNamesystem().getBlockLocations( return namenode.getNamesystem().getBlockLocations("foo",
src, offset, length, false, true, true); src, offset, length);
} }
public static HdfsFileStatus getFileInfo(NameNode namenode, String src, public static HdfsFileStatus getFileInfo(NameNode namenode, String src,

View File

@ -996,9 +996,9 @@ public void testFsckFileNotFound() throws Exception {
DatanodeManager dnManager = mock(DatanodeManager.class); DatanodeManager dnManager = mock(DatanodeManager.class);
when(namenode.getNamesystem()).thenReturn(fsName); when(namenode.getNamesystem()).thenReturn(fsName);
when(fsName.getBlockLocations(anyString(), anyLong(), anyLong(), when(fsName.getBlockLocations(
anyBoolean(), anyBoolean(), anyBoolean())). anyString(), anyLong(), anyLong(), anyBoolean(), anyBoolean()))
thenThrow(new FileNotFoundException()) ; .thenThrow(new FileNotFoundException());
when(fsName.getBlockManager()).thenReturn(blockManager); when(fsName.getBlockManager()).thenReturn(blockManager);
when(blockManager.getDatanodeManager()).thenReturn(dnManager); when(blockManager.getDatanodeManager()).thenReturn(dnManager);