private boolean addStoredBlockInternal(Block block,
DatanodeDescriptor node,
DatanodeDescriptor delNodeHint,
boolean initialBlockReport) {
assert (hasWriteLock());
BlockInfo storedBlock = blocksMap.getStoredBlock(block);
if (storedBlock == null) {
// then we need to do some special processing.
storedBlock = blocksMap.getStoredBlockWithoutMatchingGS(block);
if (storedBlock == null) {
rejectAddStoredBlock(
new Block(block), node,
"Block not in blockMap with any generation stamp",
initialBlockReport);
return false;
}
INodeFile inode = storedBlock.getINode();
if (inode == null) {
rejectAddStoredBlock(
new Block(block), node,
"Block does not correspond to any file",
initialBlockReport);
return false;
}
boolean reportedOldGS = block.getGenerationStamp() < storedBlock.getGenerationStamp();
boolean reportedNewGS = block.getGenerationStamp() > storedBlock.getGenerationStamp();
boolean underConstruction = inode.isUnderConstruction();
boolean isLastBlock = inode.getLastBlock() != null &&
inode.getLastBlock().getBlockId() == block.getBlockId();
// We can report a stale generation stamp for the last block under construction,
// we just need to make sure it ends up in targets.
if (reportedOldGS && !(underConstruction && isLastBlock)) {
rejectAddStoredBlock(
new Block(block), node,
"Reported block has old generation stamp but is not the last block of " +
"an under-construction file. (current generation is " +
storedBlock.getGenerationStamp() + ")",
initialBlockReport);
return false;
}
// Don't add blocks to the DN when they're part of the in-progress last block
// and have an inconsistent generation stamp. Instead just add them to targets
// for recovery purposes. They will get added to the node when
// commitBlockSynchronization runs
if (underConstruction && isLastBlock && (reportedOldGS || reportedNewGS)) {
NameNode.stateChangeLog.info(
"BLOCK* NameSystem.addStoredBlock: "
+ "Targets updated: block " + block + " on " + node.getName() +
" is added as a target for block " + storedBlock + " with size " +
block.getNumBytes());
((INodeFileUnderConstruction)inode).addTarget(node);
return false;
}
}
INodeFile fileINode = storedBlock.getINode();
if (fileINode == null) {
rejectAddStoredBlock(
new Block(block), node,
"Block does not correspond to any file",
initialBlockReport);
return false;
}
assert storedBlock != null : "Block must be stored by now";
// add block to the data-node
boolean added = node.addBlock(storedBlock);
// Is the block being reported the last block of an underconstruction file?
boolean blockUnderConstruction = false;
if (fileINode.isUnderConstruction()) {
Block last = fileINode.getLastBlock();
if (last == null) {
// This should never happen, but better to handle it properly than to throw
// an NPE below.
LOG.error("Null blocks for reported block=" + block + " stored=" + storedBlock +
" inode=" + fileINode);
return false;
}
blockUnderConstruction = last.equals(storedBlock);
}
// block == storedBlock when this addStoredBlock is the result of a block report
if (block.getNumBytes() != storedBlock.getNumBytes()) {
if (!checkBlockSize(block, storedBlock.getINode())) {
try {
// New replica has an invalid block size. Mark it as corrupted.
LOG.warn("Mark new replica " + block + " from " + node.getName() +
"as corrupt because its length " + block.getNumBytes() +
" is not valid");
markBlockAsCorrupt(block, node);
} catch (IOException e) {
LOG.warn("Error in deleting bad block " + block + e);
}
} else {
long cursize = storedBlock.getNumBytes();
INodeFile file = storedBlock.getINode();
if (cursize == 0) {
storedBlock.setNumBytes(block.getNumBytes());
} else if (cursize != block.getNumBytes()) {
String logMsg = "Inconsistent size for block " + block +
" reported from " + node.getName() +
" current size is " + cursize +
" reported size is " + block.getNumBytes();
// If the block is still under construction this isn't likely
// to be a problem, so just log at INFO level.
if (blockUnderConstruction) {
if (cursize != 1) { // cursize == 1 implies block was fsynced
LOG.info(logMsg);
}
} else {
LOG.warn(logMsg);
}
try {
if (cursize > block.getNumBytes() && !blockUnderConstruction) {
// new replica is smaller in size than existing block.
// Mark the new replica as corrupt.
LOG.warn("Mark new replica " + block + " from " + node.getName() +
"as corrupt because its length is shorter than existing ones");
markBlockAsCorrupt(block, node);
} else {
// new replica is larger in size than existing block.
if (!blockUnderConstruction) {
// Mark pre-existing replicas as corrupt.
int numNodes = blocksMap.numNodes(block);
int count = 0;
DatanodeDescriptor nodes[] = new DatanodeDescriptor[numNodes];
Iterator<DatanodeDescriptor> it = blocksMap.nodeIterator(block);
for (; it != null && it.hasNext(); ) {
DatanodeDescriptor dd = it.next();
if (!dd.equals(node)) {
nodes[count++] = dd;
}
}
for (int j = 0; j < count; j++) {
LOG.warn("Mark existing replica " + block + " from " + node.getName() +
" as corrupt because its length is shorter than the new one");
markBlockAsCorrupt(block, nodes[j]);
}
}
//
// change the size of block in blocksMap
//
storedBlock.setNumBytes(block.getNumBytes());
}
} catch (IOException e) {
LOG.warn("Error in deleting bad block " + block + e);
}
}