HDFS-7463. Simplify FSNamesystem#getBlockLocationsUpdateTimes. Contributed by Haohui Mai.
This commit is contained in:
parent
cb99f43305
commit
d693a252bd
|
@ -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.
|
||||||
|
|
|
@ -1749,27 +1749,76 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
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 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
/**
|
/**
|
||||||
* 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,16 +1840,16 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
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(
|
||||||
"Zero blocklocations for " + src, safeMode);
|
"Zero blocklocations for " + src, safeMode);
|
||||||
if (haEnabled && haContext != null &&
|
if (haEnabled && haContext != null &&
|
||||||
haContext.getState().getServiceState() == HAServiceState.ACTIVE) {
|
haContext.getState().getServiceState() == HAServiceState.ACTIVE) {
|
||||||
throw new RetriableException(se);
|
throw new RetriableException(se);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1825,95 +1861,49 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
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++) {
|
src = dir.resolvePath(pc, src, pathComponents);
|
||||||
boolean isReadOp = (attempt == 0);
|
final INodesInPath iip = dir.getINodesInPath(src, true);
|
||||||
if (isReadOp) { // first attempt is with readlock
|
final INodeFile inode = INodeFile.valueOf(iip.getLastINode(), src);
|
||||||
checkOperation(OperationCategory.READ);
|
if (isPermissionEnabled) {
|
||||||
readLock();
|
dir.checkPathAccess(pc, iip, FsAction.READ);
|
||||||
} else { // second attempt is with write lock
|
checkUnreadableBySuperuser(pc, inode, iip.getPathSnapshotId());
|
||||||
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);
|
|
||||||
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);
|
|
||||||
if (isPermissionEnabled) {
|
|
||||||
checkUnreadableBySuperuser(pc, inode, iip.getPathSnapshotId());
|
|
||||||
}
|
|
||||||
if (!iip.isSnapshot() //snapshots are readonly, so don't update atime.
|
|
||||||
&& doAccessTime && isAccessTimeSupported()) {
|
|
||||||
final long now = now();
|
|
||||||
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();
|
|
||||||
boolean isUc = inode.isUnderConstruction();
|
|
||||||
if (iip.isSnapshot()) {
|
|
||||||
// if src indicates a snapshot file, we need to make sure the returned
|
|
||||||
// blocks do not exceed the size of the snapshot file.
|
|
||||||
length = Math.min(length, fileSize - offset);
|
|
||||||
isUc = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final FileEncryptionInfo feInfo =
|
|
||||||
FSDirectory.isReservedRawName(srcArg) ?
|
|
||||||
null : dir.getFileEncryptionInfo(inode, iip.getPathSnapshotId(),
|
|
||||||
iip);
|
|
||||||
|
|
||||||
final LocatedBlocks blocks =
|
|
||||||
blockManager.createLocatedBlocks(inode.getBlocks(), fileSize,
|
|
||||||
isUc, offset, length, needBlockToken, iip.isSnapshot(), feInfo);
|
|
||||||
// Set caching information for the located blocks.
|
|
||||||
for (LocatedBlock lb: blocks.getLocatedBlocks()) {
|
|
||||||
cacheManager.setCachedLocations(lb);
|
|
||||||
}
|
|
||||||
return blocks;
|
|
||||||
} finally {
|
|
||||||
if (isReadOp) {
|
|
||||||
readUnlock();
|
|
||||||
} else {
|
|
||||||
writeUnlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null; // can never reach here
|
|
||||||
|
final long fileSize = iip.isSnapshot()
|
||||||
|
? inode.computeFileSize(iip.getPathSnapshotId())
|
||||||
|
: inode.computeFileSizeNotIncludingLastUcBlock();
|
||||||
|
boolean isUc = inode.isUnderConstruction();
|
||||||
|
if (iip.isSnapshot()) {
|
||||||
|
// if src indicates a snapshot file, we need to make sure the returned
|
||||||
|
// blocks do not exceed the size of the snapshot file.
|
||||||
|
length = Math.min(length, fileSize - offset);
|
||||||
|
isUc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final FileEncryptionInfo feInfo =
|
||||||
|
FSDirectory.isReservedRawName(srcArg) ? null
|
||||||
|
: dir.getFileEncryptionInfo(inode, iip.getPathSnapshotId(), iip);
|
||||||
|
|
||||||
|
final LocatedBlocks blocks = blockManager.createLocatedBlocks(
|
||||||
|
inode.getBlocks(), fileSize, isUc, offset, length, needBlockToken,
|
||||||
|
iip.isSnapshot(), feInfo);
|
||||||
|
|
||||||
|
// Set caching information for the located blocks.
|
||||||
|
for (LocatedBlock lb : blocks.getLocatedBlocks()) {
|
||||||
|
cacheManager.setCachedLocations(lb);
|
||||||
|
}
|
||||||
|
|
||||||
|
final long now = now();
|
||||||
|
boolean updateAccessTime = isAccessTimeSupported() && !isInSafeMode()
|
||||||
|
&& !iip.isSnapshot()
|
||||||
|
&& now > inode.getAccessTime() + getAccessTimePrecision();
|
||||||
|
return new GetBlockLocationsResult(updateAccessTime ? iip : null, blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -443,12 +443,15 @@ public class NamenodeFsck implements DataEncryptionKeyFactory {
|
||||||
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;
|
||||||
|
|
|
@ -167,9 +167,7 @@ public class TestGetBlocks {
|
||||||
if (stm != null) {
|
if (stm != null) {
|
||||||
stm.close();
|
stm.close();
|
||||||
}
|
}
|
||||||
if (client != null) {
|
client.close();
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ public class NameNodeAdapter {
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
|
|
|
@ -996,9 +996,9 @@ public class TestFsck {
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue