|
@@ -895,9 +895,11 @@ public class BlockManager {
|
|
* Mark the block belonging to datanode as corrupt
|
|
* Mark the block belonging to datanode as corrupt
|
|
* @param blk Block to be marked as corrupt
|
|
* @param blk Block to be marked as corrupt
|
|
* @param dn Datanode which holds the corrupt replica
|
|
* @param dn Datanode which holds the corrupt replica
|
|
|
|
+ * @param reason a textual reason why the block should be marked corrupt,
|
|
|
|
+ * for logging purposes
|
|
*/
|
|
*/
|
|
public void findAndMarkBlockAsCorrupt(final ExtendedBlock blk,
|
|
public void findAndMarkBlockAsCorrupt(final ExtendedBlock blk,
|
|
- final DatanodeInfo dn) throws IOException {
|
|
|
|
|
|
+ final DatanodeInfo dn, String reason) throws IOException {
|
|
assert namesystem.hasWriteLock();
|
|
assert namesystem.hasWriteLock();
|
|
final BlockInfo storedBlock = getStoredBlock(blk.getLocalBlock());
|
|
final BlockInfo storedBlock = getStoredBlock(blk.getLocalBlock());
|
|
if (storedBlock == null) {
|
|
if (storedBlock == null) {
|
|
@@ -909,11 +911,12 @@ public class BlockManager {
|
|
+ blk + " not found.");
|
|
+ blk + " not found.");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- markBlockAsCorrupt(storedBlock, dn);
|
|
|
|
|
|
+ markBlockAsCorrupt(storedBlock, dn, reason);
|
|
}
|
|
}
|
|
|
|
|
|
private void markBlockAsCorrupt(BlockInfo storedBlock,
|
|
private void markBlockAsCorrupt(BlockInfo storedBlock,
|
|
- DatanodeInfo dn) throws IOException {
|
|
|
|
|
|
+ DatanodeInfo dn,
|
|
|
|
+ String reason) throws IOException {
|
|
assert storedBlock != null : "storedBlock should not be null";
|
|
assert storedBlock != null : "storedBlock should not be null";
|
|
DatanodeDescriptor node = getDatanodeManager().getDatanode(dn);
|
|
DatanodeDescriptor node = getDatanodeManager().getDatanode(dn);
|
|
if (node == null) {
|
|
if (node == null) {
|
|
@@ -937,7 +940,7 @@ public class BlockManager {
|
|
node.addBlock(storedBlock);
|
|
node.addBlock(storedBlock);
|
|
|
|
|
|
// Add this replica to corruptReplicas Map
|
|
// Add this replica to corruptReplicas Map
|
|
- corruptReplicas.addToCorruptReplicasMap(storedBlock, node);
|
|
|
|
|
|
+ corruptReplicas.addToCorruptReplicasMap(storedBlock, node, reason);
|
|
if (countNodes(storedBlock).liveReplicas() >= inode.getReplication()) {
|
|
if (countNodes(storedBlock).liveReplicas() >= inode.getReplication()) {
|
|
// the block is over-replicated so invalidate the replicas immediately
|
|
// the block is over-replicated so invalidate the replicas immediately
|
|
invalidateBlock(storedBlock, node);
|
|
invalidateBlock(storedBlock, node);
|
|
@@ -1380,6 +1383,21 @@ public class BlockManager {
|
|
this.reportedState = reportedState;
|
|
this.reportedState = reportedState;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * BlockToMarkCorrupt is used to build the "toCorrupt" list, which is a
|
|
|
|
+ * list of blocks that should be considered corrupt due to a block report.
|
|
|
|
+ */
|
|
|
|
+ private static class BlockToMarkCorrupt {
|
|
|
|
+ final BlockInfo blockInfo;
|
|
|
|
+ final String reason;
|
|
|
|
+
|
|
|
|
+ BlockToMarkCorrupt(BlockInfo blockInfo, String reason) {
|
|
|
|
+ super();
|
|
|
|
+ this.blockInfo = blockInfo;
|
|
|
|
+ this.reason = reason;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
/**
|
|
* The given datanode is reporting all its blocks.
|
|
* The given datanode is reporting all its blocks.
|
|
@@ -1478,7 +1496,7 @@ public class BlockManager {
|
|
Collection<BlockInfo> toAdd = new LinkedList<BlockInfo>();
|
|
Collection<BlockInfo> toAdd = new LinkedList<BlockInfo>();
|
|
Collection<Block> toRemove = new LinkedList<Block>();
|
|
Collection<Block> toRemove = new LinkedList<Block>();
|
|
Collection<Block> toInvalidate = new LinkedList<Block>();
|
|
Collection<Block> toInvalidate = new LinkedList<Block>();
|
|
- Collection<BlockInfo> toCorrupt = new LinkedList<BlockInfo>();
|
|
|
|
|
|
+ Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>();
|
|
Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>();
|
|
Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>();
|
|
reportDiff(node, report, toAdd, toRemove, toInvalidate, toCorrupt, toUC);
|
|
reportDiff(node, report, toAdd, toRemove, toInvalidate, toCorrupt, toUC);
|
|
|
|
|
|
@@ -1498,8 +1516,8 @@ public class BlockManager {
|
|
+ " does not belong to any file.");
|
|
+ " does not belong to any file.");
|
|
addToInvalidates(b, node);
|
|
addToInvalidates(b, node);
|
|
}
|
|
}
|
|
- for (BlockInfo b : toCorrupt) {
|
|
|
|
- markBlockAsCorrupt(b, node);
|
|
|
|
|
|
+ for (BlockToMarkCorrupt b : toCorrupt) {
|
|
|
|
+ markBlockAsCorrupt(b.blockInfo, node, b.reason);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1540,14 +1558,16 @@ public class BlockManager {
|
|
|
|
|
|
// If block is corrupt, mark it and continue to next block.
|
|
// If block is corrupt, mark it and continue to next block.
|
|
BlockUCState ucState = storedBlock.getBlockUCState();
|
|
BlockUCState ucState = storedBlock.getBlockUCState();
|
|
- if (isReplicaCorrupt(iblk, reportedState, storedBlock, ucState, node)) {
|
|
|
|
|
|
+ BlockToMarkCorrupt c = checkReplicaCorrupt(
|
|
|
|
+ iblk, reportedState, storedBlock, ucState, node);
|
|
|
|
+ if (c != null) {
|
|
if (namesystem.isInStandbyState()) {
|
|
if (namesystem.isInStandbyState()) {
|
|
// In the Standby, we may receive a block report for a file that we
|
|
// In the Standby, we may receive a block report for a file that we
|
|
// just have an out-of-date gen-stamp or state for, for example.
|
|
// just have an out-of-date gen-stamp or state for, for example.
|
|
queueReportedBlock(node, iblk, reportedState,
|
|
queueReportedBlock(node, iblk, reportedState,
|
|
QUEUE_REASON_CORRUPT_STATE);
|
|
QUEUE_REASON_CORRUPT_STATE);
|
|
} else {
|
|
} else {
|
|
- markBlockAsCorrupt(storedBlock, node);
|
|
|
|
|
|
+ markBlockAsCorrupt(c.blockInfo, node, c.reason);
|
|
}
|
|
}
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
@@ -1570,7 +1590,7 @@ public class BlockManager {
|
|
Collection<BlockInfo> toAdd, // add to DatanodeDescriptor
|
|
Collection<BlockInfo> toAdd, // add to DatanodeDescriptor
|
|
Collection<Block> toRemove, // remove from DatanodeDescriptor
|
|
Collection<Block> toRemove, // remove from DatanodeDescriptor
|
|
Collection<Block> toInvalidate, // should be removed from DN
|
|
Collection<Block> toInvalidate, // should be removed from DN
|
|
- Collection<BlockInfo> toCorrupt, // add to corrupt replicas list
|
|
|
|
|
|
+ Collection<BlockToMarkCorrupt> toCorrupt, // add to corrupt replicas list
|
|
Collection<StatefulBlockInfo> toUC) { // add to under-construction list
|
|
Collection<StatefulBlockInfo> toUC) { // add to under-construction list
|
|
// place a delimiter in the list which separates blocks
|
|
// place a delimiter in the list which separates blocks
|
|
// that have been reported from those that have not
|
|
// that have been reported from those that have not
|
|
@@ -1638,7 +1658,7 @@ public class BlockManager {
|
|
final Block block, final ReplicaState reportedState,
|
|
final Block block, final ReplicaState reportedState,
|
|
final Collection<BlockInfo> toAdd,
|
|
final Collection<BlockInfo> toAdd,
|
|
final Collection<Block> toInvalidate,
|
|
final Collection<Block> toInvalidate,
|
|
- final Collection<BlockInfo> toCorrupt,
|
|
|
|
|
|
+ final Collection<BlockToMarkCorrupt> toCorrupt,
|
|
final Collection<StatefulBlockInfo> toUC) {
|
|
final Collection<StatefulBlockInfo> toUC) {
|
|
|
|
|
|
if(LOG.isDebugEnabled()) {
|
|
if(LOG.isDebugEnabled()) {
|
|
@@ -1677,16 +1697,17 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
return storedBlock;
|
|
return storedBlock;
|
|
}
|
|
}
|
|
|
|
|
|
- if (isReplicaCorrupt(block, reportedState, storedBlock, ucState, dn)) {
|
|
|
|
|
|
+ BlockToMarkCorrupt c = checkReplicaCorrupt(
|
|
|
|
+ block, reportedState, storedBlock, ucState, dn);
|
|
|
|
+ if (c != null) {
|
|
if (namesystem.isInStandbyState()) {
|
|
if (namesystem.isInStandbyState()) {
|
|
// If the block is an out-of-date generation stamp or state,
|
|
// If the block is an out-of-date generation stamp or state,
|
|
// but we're the standby, we shouldn't treat it as corrupt,
|
|
// but we're the standby, we shouldn't treat it as corrupt,
|
|
// but instead just queue it for later processing.
|
|
// but instead just queue it for later processing.
|
|
queueReportedBlock(dn, storedBlock, reportedState,
|
|
queueReportedBlock(dn, storedBlock, reportedState,
|
|
QUEUE_REASON_CORRUPT_STATE);
|
|
QUEUE_REASON_CORRUPT_STATE);
|
|
-
|
|
|
|
} else {
|
|
} else {
|
|
- toCorrupt.add(storedBlock);
|
|
|
|
|
|
+ toCorrupt.add(c);
|
|
}
|
|
}
|
|
return storedBlock;
|
|
return storedBlock;
|
|
}
|
|
}
|
|
@@ -1773,8 +1794,11 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
* as switch statements, on the theory that it is easier to understand
|
|
* as switch statements, on the theory that it is easier to understand
|
|
* the combinatorics of reportedState and ucState that way. It should be
|
|
* the combinatorics of reportedState and ucState that way. It should be
|
|
* at least as efficient as boolean expressions.
|
|
* at least as efficient as boolean expressions.
|
|
|
|
+ *
|
|
|
|
+ * @return a BlockToMarkCorrupt object, or null if the replica is not corrupt
|
|
*/
|
|
*/
|
|
- private boolean isReplicaCorrupt(Block iblk, ReplicaState reportedState,
|
|
|
|
|
|
+ private BlockToMarkCorrupt checkReplicaCorrupt(
|
|
|
|
+ Block iblk, ReplicaState reportedState,
|
|
BlockInfo storedBlock, BlockUCState ucState,
|
|
BlockInfo storedBlock, BlockUCState ucState,
|
|
DatanodeDescriptor dn) {
|
|
DatanodeDescriptor dn) {
|
|
switch(reportedState) {
|
|
switch(reportedState) {
|
|
@@ -1782,17 +1806,31 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
switch(ucState) {
|
|
switch(ucState) {
|
|
case COMPLETE:
|
|
case COMPLETE:
|
|
case COMMITTED:
|
|
case COMMITTED:
|
|
- return (storedBlock.getGenerationStamp() != iblk.getGenerationStamp()
|
|
|
|
- || storedBlock.getNumBytes() != iblk.getNumBytes());
|
|
|
|
|
|
+ if (storedBlock.getGenerationStamp() != iblk.getGenerationStamp()) {
|
|
|
|
+ return new BlockToMarkCorrupt(storedBlock,
|
|
|
|
+ "block is " + ucState + " and reported genstamp " +
|
|
|
|
+ iblk.getGenerationStamp() + " does not match " +
|
|
|
|
+ "genstamp in block map " + storedBlock.getGenerationStamp());
|
|
|
|
+ } else if (storedBlock.getNumBytes() != iblk.getNumBytes()) {
|
|
|
|
+ return new BlockToMarkCorrupt(storedBlock,
|
|
|
|
+ "block is " + ucState + " and reported length " +
|
|
|
|
+ iblk.getNumBytes() + " does not match " +
|
|
|
|
+ "length in block map " + storedBlock.getNumBytes());
|
|
|
|
+ } else {
|
|
|
|
+ return null; // not corrupt
|
|
|
|
+ }
|
|
default:
|
|
default:
|
|
- return false;
|
|
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
case RBW:
|
|
case RBW:
|
|
case RWR:
|
|
case RWR:
|
|
if (!storedBlock.isComplete()) {
|
|
if (!storedBlock.isComplete()) {
|
|
- return false;
|
|
|
|
|
|
+ return null; // not corrupt
|
|
} else if (storedBlock.getGenerationStamp() != iblk.getGenerationStamp()) {
|
|
} else if (storedBlock.getGenerationStamp() != iblk.getGenerationStamp()) {
|
|
- return true;
|
|
|
|
|
|
+ return new BlockToMarkCorrupt(storedBlock,
|
|
|
|
+ "reported " + reportedState + " replica with genstamp " +
|
|
|
|
+ iblk.getGenerationStamp() + " does not match COMPLETE block's " +
|
|
|
|
+ "genstamp in block map " + storedBlock.getGenerationStamp());
|
|
} else { // COMPLETE block, same genstamp
|
|
} else { // COMPLETE block, same genstamp
|
|
if (reportedState == ReplicaState.RBW) {
|
|
if (reportedState == ReplicaState.RBW) {
|
|
// If it's a RBW report for a COMPLETE block, it may just be that
|
|
// If it's a RBW report for a COMPLETE block, it may just be that
|
|
@@ -1802,18 +1840,22 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
LOG.info("Received an RBW replica for block " + storedBlock +
|
|
LOG.info("Received an RBW replica for block " + storedBlock +
|
|
" on " + dn.getName() + ": ignoring it, since the block is " +
|
|
" on " + dn.getName() + ": ignoring it, since the block is " +
|
|
"complete with the same generation stamp.");
|
|
"complete with the same generation stamp.");
|
|
- return false;
|
|
|
|
|
|
+ return null;
|
|
} else {
|
|
} else {
|
|
- return true;
|
|
|
|
|
|
+ return new BlockToMarkCorrupt(storedBlock,
|
|
|
|
+ "reported replica has invalid state " + reportedState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case RUR: // should not be reported
|
|
case RUR: // should not be reported
|
|
case TEMPORARY: // should not be reported
|
|
case TEMPORARY: // should not be reported
|
|
default:
|
|
default:
|
|
- LOG.warn("Unexpected replica state " + reportedState
|
|
|
|
- + " for block: " + storedBlock +
|
|
|
|
- " on " + dn.getName() + " size " + storedBlock.getNumBytes());
|
|
|
|
- return true;
|
|
|
|
|
|
+ String msg = "Unexpected replica state " + reportedState
|
|
|
|
+ + " for block: " + storedBlock +
|
|
|
|
+ " on " + dn.getName() + " size " + storedBlock.getNumBytes();
|
|
|
|
+ // log here at WARN level since this is really a broken HDFS
|
|
|
|
+ // invariant
|
|
|
|
+ LOG.warn(msg);
|
|
|
|
+ return new BlockToMarkCorrupt(storedBlock, msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2406,7 +2448,7 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
// blockReceived reports a finalized block
|
|
// blockReceived reports a finalized block
|
|
Collection<BlockInfo> toAdd = new LinkedList<BlockInfo>();
|
|
Collection<BlockInfo> toAdd = new LinkedList<BlockInfo>();
|
|
Collection<Block> toInvalidate = new LinkedList<Block>();
|
|
Collection<Block> toInvalidate = new LinkedList<Block>();
|
|
- Collection<BlockInfo> toCorrupt = new LinkedList<BlockInfo>();
|
|
|
|
|
|
+ Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>();
|
|
Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>();
|
|
Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>();
|
|
processReportedBlock(node, block, reportedState,
|
|
processReportedBlock(node, block, reportedState,
|
|
toAdd, toInvalidate, toCorrupt, toUC);
|
|
toAdd, toInvalidate, toCorrupt, toUC);
|
|
@@ -2427,8 +2469,8 @@ assert storedBlock.findDatanode(dn) < 0 : "Block " + block
|
|
+ " does not belong to any file.");
|
|
+ " does not belong to any file.");
|
|
addToInvalidates(b, node);
|
|
addToInvalidates(b, node);
|
|
}
|
|
}
|
|
- for (BlockInfo b : toCorrupt) {
|
|
|
|
- markBlockAsCorrupt(b, node);
|
|
|
|
|
|
+ for (BlockToMarkCorrupt b : toCorrupt) {
|
|
|
|
+ markBlockAsCorrupt(b.blockInfo, node, b.reason);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|