HDFS-7716. Erasure Coding: extend BlockInfo to handle EC info. Contributed by Jing Zhao.

This commit is contained in:
Jing Zhao 2015-02-10 17:54:10 -08:00 committed by Zhe Zhang
parent b29f3bde4d
commit ba93714920
20 changed files with 1122 additions and 503 deletions

View File

@ -39,12 +39,12 @@ public interface BlockCollection {
public ContentSummary computeContentSummary(BlockStoragePolicySuite bsps); public ContentSummary computeContentSummary(BlockStoragePolicySuite bsps);
/** /**
* @return the number of blocks * @return the number of blocks or block groups
*/ */
public int numBlocks(); public int numBlocks();
/** /**
* Get the blocks. * Get the blocks or block groups.
*/ */
public BlockInfoContiguous[] getBlocks(); public BlockInfoContiguous[] getBlocks();
@ -55,8 +55,8 @@ public interface BlockCollection {
public long getPreferredBlockSize(); public long getPreferredBlockSize();
/** /**
* Get block replication for the collection * Get block replication for the collection.
* @return block replication value * @return block replication value. Return 0 if the file is erasure coded.
*/ */
public short getPreferredBlockReplication(); public short getPreferredBlockReplication();
@ -71,7 +71,7 @@ public interface BlockCollection {
public String getName(); public String getName();
/** /**
* Set the block at the given index. * Set the block/block-group at the given index.
*/ */
public void setBlock(int index, BlockInfoContiguous blk); public void setBlock(int index, BlockInfoContiguous blk);
@ -79,7 +79,8 @@ public interface BlockCollection {
* Convert the last block of the collection to an under-construction block * Convert the last block of the collection to an under-construction block
* and set the locations. * and set the locations.
*/ */
public BlockInfoContiguousUnderConstruction setLastBlock(BlockInfoContiguous lastBlock, public BlockInfoContiguousUnderConstruction setLastBlock(
BlockInfoContiguous lastBlock,
DatanodeStorageInfo[] targets) throws IOException; DatanodeStorageInfo[] targets) throws IOException;
/** /**

View File

@ -218,6 +218,11 @@ public static boolean isStripedBlockID(long id) {
} }
public static long convertToGroupID(long id) { public static long convertToGroupID(long id) {
return id & (~(HdfsConstants.MAX_BLOCKS_IN_GROUP - 1)); return id & (~HdfsConstants.BLOCK_GROUP_INDEX_MASK);
}
public static int getBlockIndex(Block reportedBlock) {
return (int) (reportedBlock.getBlockId() &
HdfsConstants.BLOCK_GROUP_INDEX_MASK);
} }
} }

View File

@ -0,0 +1,343 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.blockmanagement;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
import org.apache.hadoop.util.LightWeightGSet;
import java.util.LinkedList;
/**
* For a given block (or an erasure coding block group), BlockInfo class
* maintains 1) the {@link BlockCollection} it is part of, and 2) datanodes
* where the replicas of the block, or blocks belonging to the erasure coding
* block group, are stored.
*/
public abstract class BlockInfo extends Block
implements LightWeightGSet.LinkedElement {
private BlockCollection bc;
/** For implementing {@link LightWeightGSet.LinkedElement} interface */
private LightWeightGSet.LinkedElement nextLinkedElement;
/**
* This array contains triplets of references. For each i-th storage, the
* block belongs to triplets[3*i] is the reference to the
* {@link DatanodeStorageInfo} and triplets[3*i+1] and triplets[3*i+2] are
* references to the previous and the next blocks, respectively, in the list
* of blocks belonging to this storage.
*
* Using previous and next in Object triplets is done instead of a
* {@link LinkedList} list to efficiently use memory. With LinkedList the cost
* per replica is 42 bytes (LinkedList#Entry object per replica) versus 16
* bytes using the triplets.
*/
protected Object[] triplets;
/**
* Construct an entry for blocksmap
* @param size the block's replication factor, or the total number of blocks
* in the block group
*/
public BlockInfo(short size) {
this.triplets = new Object[3 * size];
this.bc = null;
}
public BlockInfo(Block blk, short size) {
super(blk);
this.triplets = new Object[3 * size];
this.bc = null;
}
public BlockCollection getBlockCollection() {
return bc;
}
public void setBlockCollection(BlockCollection bc) {
this.bc = bc;
}
public DatanodeDescriptor getDatanode(int index) {
DatanodeStorageInfo storage = getStorageInfo(index);
return storage == null ? null : storage.getDatanodeDescriptor();
}
DatanodeStorageInfo getStorageInfo(int index) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3 < triplets.length : "Index is out of bound";
return (DatanodeStorageInfo)triplets[index*3];
}
BlockInfo getPrevious(int index) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3+1 < triplets.length : "Index is out of bound";
return (BlockInfo) triplets[index*3+1];
}
BlockInfo getNext(int index) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3+2 < triplets.length : "Index is out of bound";
return (BlockInfo) triplets[index*3+2];
}
void setStorageInfo(int index, DatanodeStorageInfo storage) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3 < triplets.length : "Index is out of bound";
triplets[index*3] = storage;
}
/**
* Return the previous block on the block list for the datanode at
* position index. Set the previous block on the list to "to".
*
* @param index - the datanode index
* @param to - block to be set to previous on the list of blocks
* @return current previous block on the list of blocks
*/
BlockInfo setPrevious(int index, BlockInfo to) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3+1 < triplets.length : "Index is out of bound";
BlockInfo info = (BlockInfo) triplets[index*3+1];
triplets[index*3+1] = to;
return info;
}
/**
* Return the next block on the block list for the datanode at
* position index. Set the next block on the list to "to".
*
* @param index - the datanode index
* @param to - block to be set to next on the list of blocks
* @return current next block on the list of blocks
*/
BlockInfo setNext(int index, BlockInfo to) {
assert this.triplets != null : "BlockInfo is not initialized";
assert index >= 0 && index*3+2 < triplets.length : "Index is out of bound";
BlockInfo info = (BlockInfo) triplets[index*3+2];
triplets[index*3+2] = to;
return info;
}
public int getCapacity() {
assert this.triplets != null : "BlockInfo is not initialized";
assert triplets.length % 3 == 0 : "Malformed BlockInfo";
return triplets.length / 3;
}
/**
* Count the number of data-nodes the block currently belongs to (i.e., NN
* has received block reports from the DN).
*/
public abstract int numNodes();
/**
* Add a {@link DatanodeStorageInfo} location for a block
* @param storage The storage to add
* @param reportedBlock The block reported from the datanode. This is only
* used by erasure coded blocks, this block's id contains
* information indicating the index of the block in the
* corresponding block group.
*/
abstract boolean addStorage(DatanodeStorageInfo storage, Block reportedBlock);
/**
* Remove {@link DatanodeStorageInfo} location for a block
*/
abstract boolean removeStorage(DatanodeStorageInfo storage);
/**
* Replace the current BlockInfo with the new one in corresponding
* DatanodeStorageInfo's linked list
*/
abstract void replaceBlock(BlockInfo newBlock);
/**
* Find specified DatanodeDescriptor.
* @return index or -1 if not found.
*/
boolean findDatanode(DatanodeDescriptor dn) {
int len = getCapacity();
for (int idx = 0; idx < len; idx++) {
DatanodeDescriptor cur = getDatanode(idx);
if(cur == dn) {
return true;
}
}
return false;
}
/**
* Find specified DatanodeStorageInfo.
* @return DatanodeStorageInfo or null if not found.
*/
DatanodeStorageInfo findStorageInfo(DatanodeDescriptor dn) {
int len = getCapacity();
for(int idx = 0; idx < len; idx++) {
DatanodeStorageInfo cur = getStorageInfo(idx);
if(cur != null && cur.getDatanodeDescriptor() == dn) {
return cur;
}
}
return null;
}
/**
* Find specified DatanodeStorageInfo.
* @return index or -1 if not found.
*/
int findStorageInfo(DatanodeStorageInfo storageInfo) {
int len = getCapacity();
for(int idx = 0; idx < len; idx++) {
DatanodeStorageInfo cur = getStorageInfo(idx);
if (cur == storageInfo) {
return idx;
}
}
return -1;
}
/**
* Insert this block into the head of the list of blocks
* related to the specified DatanodeStorageInfo.
* If the head is null then form a new list.
* @return current block as the new head of the list.
*/
BlockInfo listInsert(BlockInfo head, DatanodeStorageInfo storage) {
int dnIndex = this.findStorageInfo(storage);
assert dnIndex >= 0 : "Data node is not found: current";
assert getPrevious(dnIndex) == null && getNext(dnIndex) == null :
"Block is already in the list and cannot be inserted.";
this.setPrevious(dnIndex, null);
this.setNext(dnIndex, head);
if (head != null) {
head.setPrevious(head.findStorageInfo(storage), this);
}
return this;
}
/**
* Remove this block from the list of blocks
* related to the specified DatanodeStorageInfo.
* If this block is the head of the list then return the next block as
* the new head.
* @return the new head of the list or null if the list becomes
* empy after deletion.
*/
BlockInfo listRemove(BlockInfo head, DatanodeStorageInfo storage) {
if (head == null) {
return null;
}
int dnIndex = this.findStorageInfo(storage);
if (dnIndex < 0) { // this block is not on the data-node list
return head;
}
BlockInfo next = this.getNext(dnIndex);
BlockInfo prev = this.getPrevious(dnIndex);
this.setNext(dnIndex, null);
this.setPrevious(dnIndex, null);
if (prev != null) {
prev.setNext(prev.findStorageInfo(storage), next);
}
if (next != null) {
next.setPrevious(next.findStorageInfo(storage), prev);
}
if (this == head) { // removing the head
head = next;
}
return head;
}
/**
* Remove this block from the list of blocks related to the specified
* DatanodeDescriptor. Insert it into the head of the list of blocks.
*
* @return the new head of the list.
*/
public BlockInfo moveBlockToHead(BlockInfo head, DatanodeStorageInfo storage,
int curIndex, int headIndex) {
if (head == this) {
return this;
}
BlockInfo next = this.setNext(curIndex, head);
BlockInfo prev = this.setPrevious(curIndex, null);
head.setPrevious(headIndex, this);
prev.setNext(prev.findStorageInfo(storage), next);
if (next != null) {
next.setPrevious(next.findStorageInfo(storage), prev);
}
return this;
}
/**
* BlockInfo represents a block that is not being constructed.
* In order to start modifying the block, the BlockInfo should be converted
* to {@link BlockInfoContiguousUnderConstruction}.
* @return {@link HdfsServerConstants.BlockUCState#COMPLETE}
*/
public HdfsServerConstants.BlockUCState getBlockUCState() {
return HdfsServerConstants.BlockUCState.COMPLETE;
}
/**
* Is this block complete?
*
* @return true if the state of the block is
* {@link HdfsServerConstants.BlockUCState#COMPLETE}
*/
public boolean isComplete() {
return getBlockUCState().equals(HdfsServerConstants.BlockUCState.COMPLETE);
}
public boolean isDeleted() {
return (bc == null);
}
@Override
public int hashCode() {
// Super implementation is sufficient
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
// Sufficient to rely on super's implementation
return (this == obj) || super.equals(obj);
}
@Override
public LightWeightGSet.LinkedElement getNext() {
return nextLinkedElement;
}
@Override
public void setNext(LightWeightGSet.LinkedElement next) {
this.nextLinkedElement = next;
}
static BlockInfo copyOf(BlockInfo b) {
if (b instanceof BlockInfoContiguous) {
return new BlockInfoContiguous((BlockInfoContiguous) b);
} else {
return new BlockInfoStriped((BlockInfoStriped) b);
}
}
}

View File

@ -17,66 +17,34 @@
*/ */
package org.apache.hadoop.hdfs.server.blockmanagement; package org.apache.hadoop.hdfs.server.blockmanagement;
import java.util.LinkedList;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hdfs.protocol.Block; import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState; import org.apache.hadoop.hdfs.server.common.HdfsServerConstants.BlockUCState;
import org.apache.hadoop.util.LightWeightGSet;
/** /**
* BlockInfo class maintains for a given block * Subclass of {@link BlockInfo}, used for a block with replication scheme.
* the {@link BlockCollection} it is part of and datanodes where the replicas of
* the block are stored.
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
public class BlockInfoContiguous extends Block public class BlockInfoContiguous extends BlockInfo {
implements LightWeightGSet.LinkedElement {
public static final BlockInfoContiguous[] EMPTY_ARRAY = {}; public static final BlockInfoContiguous[] EMPTY_ARRAY = {};
private BlockCollection bc; public BlockInfoContiguous(short size) {
super(size);
/** For implementing {@link LightWeightGSet.LinkedElement} interface */
private LightWeightGSet.LinkedElement nextLinkedElement;
/**
* This array contains triplets of references. For each i-th storage, the
* block belongs to triplets[3*i] is the reference to the
* {@link DatanodeStorageInfo} and triplets[3*i+1] and triplets[3*i+2] are
* references to the previous and the next blocks, respectively, in the list
* of blocks belonging to this storage.
*
* Using previous and next in Object triplets is done instead of a
* {@link LinkedList} list to efficiently use memory. With LinkedList the cost
* per replica is 42 bytes (LinkedList#Entry object per replica) versus 16
* bytes using the triplets.
*/
private Object[] triplets;
/**
* Construct an entry for blocksmap
* @param replication the block's replication factor
*/
public BlockInfoContiguous(short replication) {
this.triplets = new Object[3*replication];
this.bc = null;
} }
public BlockInfoContiguous(Block blk, short replication) { public BlockInfoContiguous(Block blk, short size) {
super(blk); super(blk, size);
this.triplets = new Object[3*replication];
this.bc = null;
} }
/** /**
* Copy construction. * Copy construction.
* This is used to convert BlockInfoUnderConstruction * This is used to convert BlockReplicationInfoUnderConstruction
* @param from BlockInfo to copy from. * @param from BlockReplicationInfo to copy from.
*/ */
protected BlockInfoContiguous(BlockInfoContiguous from) { protected BlockInfoContiguous(BlockInfoContiguous from) {
super(from); this(from, from.getBlockCollection().getBlockReplication());
this.triplets = new Object[from.triplets.length]; this.triplets = new Object[from.triplets.length];
this.bc = from.bc; this.setBlockCollection(from.getBlockCollection());
} }
public BlockCollection getBlockCollection() { public BlockCollection getBlockCollection() {
@ -173,8 +141,9 @@ public int getCapacity() {
private int ensureCapacity(int num) { private int ensureCapacity(int num) {
assert this.triplets != null : "BlockInfo is not initialized"; assert this.triplets != null : "BlockInfo is not initialized";
int last = numNodes(); int last = numNodes();
if(triplets.length >= (last+num)*3) if (triplets.length >= (last+num)*3) {
return last; return last;
}
/* Not enough space left. Create a new array. Should normally /* Not enough space left. Create a new array. Should normally
* happen only when replication is manually increased by the user. */ * happen only when replication is manually increased by the user. */
Object[] old = triplets; Object[] old = triplets;
@ -183,23 +152,8 @@ private int ensureCapacity(int num) {
return last; return last;
} }
/** @Override
* Count the number of data-nodes the block belongs to. boolean addStorage(DatanodeStorageInfo storage, Block reportedBlock) {
*/
public int numNodes() {
assert this.triplets != null : "BlockInfo is not initialized";
assert triplets.length % 3 == 0 : "Malformed BlockInfo";
for(int idx = getCapacity()-1; idx >= 0; idx--) {
if(getDatanode(idx) != null)
return idx+1;
}
return 0;
}
/**
* Add a {@link DatanodeStorageInfo} location for a block
*/
boolean addStorage(DatanodeStorageInfo storage) {
// find the last null node // find the last null node
int lastNode = ensureCapacity(1); int lastNode = ensureCapacity(1);
setStorageInfo(lastNode, storage); setStorageInfo(lastNode, storage);
@ -208,15 +162,14 @@ boolean addStorage(DatanodeStorageInfo storage) {
return true; return true;
} }
/** @Override
* Remove {@link DatanodeStorageInfo} location for a block
*/
boolean removeStorage(DatanodeStorageInfo storage) { boolean removeStorage(DatanodeStorageInfo storage) {
int dnIndex = findStorageInfo(storage); int dnIndex = findStorageInfo(storage);
if(dnIndex < 0) // the node is not found if (dnIndex < 0) { // the node is not found
return false; return false;
}
assert getPrevious(dnIndex) == null && getNext(dnIndex) == null : assert getPrevious(dnIndex) == null && getNext(dnIndex) == null :
"Block is still in the list and must be removed first."; "Block is still in the list and must be removed first.";
// find the last not null node // find the last not null node
int lastNode = numNodes()-1; int lastNode = numNodes()-1;
// replace current node triplet by the lastNode one // replace current node triplet by the lastNode one
@ -230,127 +183,32 @@ assert getPrevious(dnIndex) == null && getNext(dnIndex) == null :
return true; return true;
} }
/** @Override
* Find specified DatanodeStorageInfo. public int numNodes() {
* @return DatanodeStorageInfo or null if not found. assert this.triplets != null : "BlockInfo is not initialized";
*/ assert triplets.length % 3 == 0 : "Malformed BlockInfo";
DatanodeStorageInfo findStorageInfo(DatanodeDescriptor dn) {
int len = getCapacity();
for(int idx = 0; idx < len; idx++) {
DatanodeStorageInfo cur = getStorageInfo(idx);
if(cur == null)
break;
if(cur.getDatanodeDescriptor() == dn)
return cur;
}
return null;
}
/** for (int idx = getCapacity()-1; idx >= 0; idx--) {
* Find specified DatanodeStorageInfo. if (getDatanode(idx) != null) {
* @return index or -1 if not found. return idx + 1;
*/
int findStorageInfo(DatanodeStorageInfo storageInfo) {
int len = getCapacity();
for(int idx = 0; idx < len; idx++) {
DatanodeStorageInfo cur = getStorageInfo(idx);
if (cur == storageInfo) {
return idx;
}
if (cur == null) {
break;
} }
} }
return -1; return 0;
} }
/** @Override
* Insert this block into the head of the list of blocks void replaceBlock(BlockInfo newBlock) {
* related to the specified DatanodeStorageInfo. assert newBlock instanceof BlockInfoContiguous;
* If the head is null then form a new list. for (int i = this.numNodes() - 1; i >= 0; i--) {
* @return current block as the new head of the list. final DatanodeStorageInfo storage = this.getStorageInfo(i);
*/ final boolean removed = storage.removeBlock(this);
BlockInfoContiguous listInsert(BlockInfoContiguous head, assert removed : "currentBlock not found.";
DatanodeStorageInfo storage) {
int dnIndex = this.findStorageInfo(storage);
assert dnIndex >= 0 : "Data node is not found: current";
assert getPrevious(dnIndex) == null && getNext(dnIndex) == null :
"Block is already in the list and cannot be inserted.";
this.setPrevious(dnIndex, null);
this.setNext(dnIndex, head);
if(head != null)
head.setPrevious(head.findStorageInfo(storage), this);
return this;
}
/** final DatanodeStorageInfo.AddBlockResult result = storage.addBlock(
* Remove this block from the list of blocks newBlock, newBlock);
* related to the specified DatanodeStorageInfo. assert result == DatanodeStorageInfo.AddBlockResult.ADDED :
* If this block is the head of the list then return the next block as "newBlock already exists.";
* the new head.
* @return the new head of the list or null if the list becomes
* empy after deletion.
*/
BlockInfoContiguous listRemove(BlockInfoContiguous head,
DatanodeStorageInfo storage) {
if(head == null)
return null;
int dnIndex = this.findStorageInfo(storage);
if(dnIndex < 0) // this block is not on the data-node list
return head;
BlockInfoContiguous next = this.getNext(dnIndex);
BlockInfoContiguous prev = this.getPrevious(dnIndex);
this.setNext(dnIndex, null);
this.setPrevious(dnIndex, null);
if(prev != null)
prev.setNext(prev.findStorageInfo(storage), next);
if(next != null)
next.setPrevious(next.findStorageInfo(storage), prev);
if(this == head) // removing the head
head = next;
return head;
}
/**
* Remove this block from the list of blocks related to the specified
* DatanodeDescriptor. Insert it into the head of the list of blocks.
*
* @return the new head of the list.
*/
public BlockInfoContiguous moveBlockToHead(BlockInfoContiguous head,
DatanodeStorageInfo storage, int curIndex, int headIndex) {
if (head == this) {
return this;
} }
BlockInfoContiguous next = this.setNext(curIndex, head);
BlockInfoContiguous prev = this.setPrevious(curIndex, null);
head.setPrevious(headIndex, this);
prev.setNext(prev.findStorageInfo(storage), next);
if (next != null) {
next.setPrevious(next.findStorageInfo(storage), prev);
}
return this;
}
/**
* BlockInfo represents a block that is not being constructed.
* In order to start modifying the block, the BlockInfo should be converted
* to {@link BlockInfoContiguousUnderConstruction}.
* @return {@link BlockUCState#COMPLETE}
*/
public BlockUCState getBlockUCState() {
return BlockUCState.COMPLETE;
}
/**
* Is this block complete?
*
* @return true if the state of the block is {@link BlockUCState#COMPLETE}
*/
public boolean isComplete() {
return getBlockUCState().equals(BlockUCState.COMPLETE);
} }
/** /**
@ -368,32 +226,10 @@ public BlockInfoContiguousUnderConstruction convertToBlockUnderConstruction(
} }
// the block is already under construction // the block is already under construction
BlockInfoContiguousUnderConstruction ucBlock = BlockInfoContiguousUnderConstruction ucBlock =
(BlockInfoContiguousUnderConstruction)this; (BlockInfoContiguousUnderConstruction) this;
ucBlock.setBlockUCState(s); ucBlock.setBlockUCState(s);
ucBlock.setExpectedLocations(targets); ucBlock.setExpectedLocations(targets);
ucBlock.setBlockCollection(getBlockCollection()); ucBlock.setBlockCollection(getBlockCollection());
return ucBlock; return ucBlock;
} }
@Override
public int hashCode() {
// Super implementation is sufficient
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
// Sufficient to rely on super's implementation
return (this == obj) || super.equals(obj);
}
@Override
public LightWeightGSet.LinkedElement getNext() {
return nextLinkedElement;
}
@Override
public void setNext(LightWeightGSet.LinkedElement next) {
this.nextLinkedElement = next;
}
} }

View File

@ -59,101 +59,6 @@ public class BlockInfoContiguousUnderConstruction extends BlockInfoContiguous {
*/ */
private Block truncateBlock; private Block truncateBlock;
/**
* ReplicaUnderConstruction contains information about replicas while
* they are under construction.
* The GS, the length and the state of the replica is as reported by
* the data-node.
* It is not guaranteed, but expected, that data-nodes actually have
* corresponding replicas.
*/
static class ReplicaUnderConstruction extends Block {
private final DatanodeStorageInfo expectedLocation;
private ReplicaState state;
private boolean chosenAsPrimary;
ReplicaUnderConstruction(Block block,
DatanodeStorageInfo target,
ReplicaState state) {
super(block);
this.expectedLocation = target;
this.state = state;
this.chosenAsPrimary = false;
}
/**
* Expected block replica location as assigned when the block was allocated.
* This defines the pipeline order.
* It is not guaranteed, but expected, that the data-node actually has
* the replica.
*/
private DatanodeStorageInfo getExpectedStorageLocation() {
return expectedLocation;
}
/**
* Get replica state as reported by the data-node.
*/
ReplicaState getState() {
return state;
}
/**
* Whether the replica was chosen for recovery.
*/
boolean getChosenAsPrimary() {
return chosenAsPrimary;
}
/**
* Set replica state.
*/
void setState(ReplicaState s) {
state = s;
}
/**
* Set whether this replica was chosen for recovery.
*/
void setChosenAsPrimary(boolean chosenAsPrimary) {
this.chosenAsPrimary = chosenAsPrimary;
}
/**
* Is data-node the replica belongs to alive.
*/
boolean isAlive() {
return expectedLocation.getDatanodeDescriptor().isAlive;
}
@Override // Block
public int hashCode() {
return super.hashCode();
}
@Override // Block
public boolean equals(Object obj) {
// Sufficient to rely on super's implementation
return (this == obj) || super.equals(obj);
}
@Override
public String toString() {
final StringBuilder b = new StringBuilder(50);
appendStringTo(b);
return b.toString();
}
@Override
public void appendStringTo(StringBuilder sb) {
sb.append("ReplicaUC[")
.append(expectedLocation)
.append("|")
.append(state)
.append("]");
}
}
/** /**
* Create block and set its state to * Create block and set its state to
* {@link BlockUCState#UNDER_CONSTRUCTION}. * {@link BlockUCState#UNDER_CONSTRUCTION}.
@ -165,7 +70,8 @@ public BlockInfoContiguousUnderConstruction(Block blk, short replication) {
/** /**
* Create a block that is currently being constructed. * Create a block that is currently being constructed.
*/ */
public BlockInfoContiguousUnderConstruction(Block blk, short replication, BlockUCState state, DatanodeStorageInfo[] targets) { public BlockInfoContiguousUnderConstruction(Block blk, short replication,
BlockUCState state, DatanodeStorageInfo[] targets) {
super(blk, replication); super(blk, replication);
assert getBlockUCState() != BlockUCState.COMPLETE : assert getBlockUCState() != BlockUCState.COMPLETE :
"BlockInfoUnderConstruction cannot be in COMPLETE state"; "BlockInfoUnderConstruction cannot be in COMPLETE state";
@ -191,10 +97,11 @@ assert getBlockUCState() != BlockUCState.COMPLETE :
/** Set expected locations */ /** Set expected locations */
public void setExpectedLocations(DatanodeStorageInfo[] targets) { public void setExpectedLocations(DatanodeStorageInfo[] targets) {
int numLocations = targets == null ? 0 : targets.length; int numLocations = targets == null ? 0 : targets.length;
this.replicas = new ArrayList<ReplicaUnderConstruction>(numLocations); this.replicas = new ArrayList<>(numLocations);
for(int i = 0; i < numLocations; i++) for(int i = 0; i < numLocations; i++) {
replicas.add( replicas.add(new ReplicaUnderConstruction(this, targets[i],
new ReplicaUnderConstruction(this, targets[i], ReplicaState.RBW)); ReplicaState.RBW));
}
} }
/** /**
@ -204,8 +111,9 @@ public void setExpectedLocations(DatanodeStorageInfo[] targets) {
public DatanodeStorageInfo[] getExpectedStorageLocations() { public DatanodeStorageInfo[] getExpectedStorageLocations() {
int numLocations = replicas == null ? 0 : replicas.size(); int numLocations = replicas == null ? 0 : replicas.size();
DatanodeStorageInfo[] storages = new DatanodeStorageInfo[numLocations]; DatanodeStorageInfo[] storages = new DatanodeStorageInfo[numLocations];
for(int i = 0; i < numLocations; i++) for (int i = 0; i < numLocations; i++) {
storages[i] = replicas.get(i).getExpectedStorageLocation(); storages[i] = replicas.get(i).getExpectedStorageLocation();
}
return storages; return storages;
} }
@ -293,17 +201,17 @@ public void initializeBlockRecovery(long recoveryId) {
+ " No blocks found, lease removed."); + " No blocks found, lease removed.");
} }
boolean allLiveReplicasTriedAsPrimary = true; boolean allLiveReplicasTriedAsPrimary = true;
for (int i = 0; i < replicas.size(); i++) { for (ReplicaUnderConstruction replica : replicas) {
// Check if all replicas have been tried or not. // Check if all replicas have been tried or not.
if (replicas.get(i).isAlive()) { if (replica.isAlive()) {
allLiveReplicasTriedAsPrimary = allLiveReplicasTriedAsPrimary = (allLiveReplicasTriedAsPrimary &&
(allLiveReplicasTriedAsPrimary && replicas.get(i).getChosenAsPrimary()); replica.getChosenAsPrimary());
} }
} }
if (allLiveReplicasTriedAsPrimary) { if (allLiveReplicasTriedAsPrimary) {
// Just set all the replicas to be chosen whether they are alive or not. // Just set all the replicas to be chosen whether they are alive or not.
for (int i = 0; i < replicas.size(); i++) { for (ReplicaUnderConstruction replica : replicas) {
replicas.get(i).setChosenAsPrimary(false); replica.setChosenAsPrimary(false);
} }
} }
long mostRecentLastUpdate = 0; long mostRecentLastUpdate = 0;
@ -324,7 +232,8 @@ public void initializeBlockRecovery(long recoveryId) {
} }
} }
if (primary != null) { if (primary != null) {
primary.getExpectedStorageLocation().getDatanodeDescriptor().addBlockToBeRecovered(this); primary.getExpectedStorageLocation().getDatanodeDescriptor()
.addBlockToBeRecovered(this);
primary.setChosenAsPrimary(true); primary.setChosenAsPrimary(true);
NameNode.blockStateChangeLog.info( NameNode.blockStateChangeLog.info(
"BLOCK* {} recovery started, primary={}", this, primary); "BLOCK* {} recovery started, primary={}", this, primary);
@ -357,18 +266,6 @@ void addReplicaIfNotPresent(DatanodeStorageInfo storage,
replicas.add(new ReplicaUnderConstruction(block, storage, rState)); replicas.add(new ReplicaUnderConstruction(block, storage, rState));
} }
@Override // BlockInfo
// BlockInfoUnderConstruction participates in maps the same way as BlockInfo
public int hashCode() {
return super.hashCode();
}
@Override // BlockInfo
public boolean equals(Object obj) {
// Sufficient to rely on super's implementation
return (this == obj) || super.equals(obj);
}
@Override @Override
public String toString() { public String toString() {
final StringBuilder b = new StringBuilder(100); final StringBuilder b = new StringBuilder(100);

View File

@ -0,0 +1,179 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.blockmanagement;
import org.apache.hadoop.hdfs.protocol.Block;
/**
* Subclass of {@link BlockInfo}, presenting a block group in erasure coding.
*
* We still use triplets to store DatanodeStorageInfo for each block in the
* block group, as well as the previous/next block in the corresponding
* DatanodeStorageInfo. For a (m+k) block group, the first (m+k) triplet units
* are sorted and strictly mapped to the corresponding block.
*
* Normally each block belonging to group is stored in only one DataNode.
* However, it is possible that some block is over-replicated. Thus the triplet
* array's size can be larger than (m+k). Thus currently we use an extra byte
* array to record the block index for each triplet.
*/
public class BlockInfoStriped extends BlockInfo {
private final short dataBlockNum;
private final short parityBlockNum;
/**
* Always the same size with triplets. Record the block index for each triplet
* TODO: actually this is only necessary for over-replicated block. Thus can
* be further optimized to save memory usage.
*/
private byte[] indices;
public BlockInfoStriped(Block blk, short dataBlockNum, short parityBlockNum) {
super(blk, (short) (dataBlockNum + parityBlockNum));
indices = new byte[dataBlockNum + parityBlockNum];
initIndices();
this.dataBlockNum = dataBlockNum;
this.parityBlockNum = parityBlockNum;
}
BlockInfoStriped(BlockInfoStriped b) {
this(b, b.dataBlockNum, b.parityBlockNum);
this.setBlockCollection(b.getBlockCollection());
}
private short getTotalBlockNum() {
return (short) (dataBlockNum + parityBlockNum);
}
private void initIndices() {
for (int i = 0; i < indices.length; i++) {
indices[i] = -1;
}
}
private int findSlot() {
int i = getTotalBlockNum();
for (; i < getCapacity(); i++) {
if (getStorageInfo(i) == null) {
return i;
}
}
// need to expand the triplet size
ensureCapacity(i + 1, true);
return i;
}
@Override
boolean addStorage(DatanodeStorageInfo storage, Block reportedBlock) {
int blockIndex = BlockIdManager.getBlockIndex(reportedBlock);
int index = blockIndex;
DatanodeStorageInfo old = getStorageInfo(index);
if (old != null && !old.equals(storage)) { // over replicated
// check if the storage has been stored
int i = findStorageInfo(storage);
if (i == -1) {
index = findSlot();
} else {
return true;
}
}
addStorage(storage, index, blockIndex);
return true;
}
private void addStorage(DatanodeStorageInfo storage, int index,
int blockIndex) {
setStorageInfo(index, storage);
setNext(index, null);
setPrevious(index, null);
indices[index] = (byte) blockIndex;
}
private int findStorageInfoFromEnd(DatanodeStorageInfo storage) {
final int len = getCapacity();
for(int idx = len - 1; idx >= 0; idx--) {
DatanodeStorageInfo cur = getStorageInfo(idx);
if (storage.equals(cur)) {
return idx;
}
}
return -1;
}
@Override
boolean removeStorage(DatanodeStorageInfo storage) {
int dnIndex = findStorageInfoFromEnd(storage);
if (dnIndex < 0) { // the node is not found
return false;
}
assert getPrevious(dnIndex) == null && getNext(dnIndex) == null :
"Block is still in the list and must be removed first.";
// set the triplet to null
setStorageInfo(dnIndex, null);
setNext(dnIndex, null);
setPrevious(dnIndex, null);
indices[dnIndex] = -1;
return true;
}
private void ensureCapacity(int totalSize, boolean keepOld) {
if (getCapacity() < totalSize) {
Object[] old = triplets;
byte[] oldIndices = indices;
triplets = new Object[totalSize * 3];
indices = new byte[totalSize];
initIndices();
if (keepOld) {
System.arraycopy(old, 0, triplets, 0, old.length);
System.arraycopy(oldIndices, 0, indices, 0, oldIndices.length);
}
}
}
@Override
void replaceBlock(BlockInfo newBlock) {
assert newBlock instanceof BlockInfoStriped;
BlockInfoStriped newBlockGroup = (BlockInfoStriped) newBlock;
final int size = getCapacity();
newBlockGroup.ensureCapacity(size, false);
for (int i = 0; i < size; i++) {
final DatanodeStorageInfo storage = this.getStorageInfo(i);
if (storage != null) {
final int blockIndex = indices[i];
final boolean removed = storage.removeBlock(this);
assert removed : "currentBlock not found.";
newBlockGroup.addStorage(storage, i, blockIndex);
storage.insertToList(newBlockGroup);
}
}
}
@Override
public int numNodes() {
assert this.triplets != null : "BlockInfo is not initialized";
assert triplets.length % 3 == 0 : "Malformed BlockInfo";
int num = 0;
for (int idx = getCapacity()-1; idx >= 0; idx--) {
if (getStorageInfo(idx) != null) {
num++;
}
}
return num;
}
}

View File

@ -599,8 +599,8 @@ public boolean checkMinReplication(Block block) {
* of replicas reported from data-nodes. * of replicas reported from data-nodes.
*/ */
private static boolean commitBlock( private static boolean commitBlock(
final BlockInfoContiguousUnderConstruction block, final Block commitBlock) final BlockInfoContiguousUnderConstruction block,
throws IOException { final Block commitBlock) throws IOException {
if (block.getBlockUCState() == BlockUCState.COMMITTED) if (block.getBlockUCState() == BlockUCState.COMMITTED)
return false; return false;
assert block.getNumBytes() <= commitBlock.getNumBytes() : assert block.getNumBytes() <= commitBlock.getNumBytes() :
@ -631,7 +631,7 @@ public boolean commitOrCompleteLastBlock(BlockCollection bc,
return false; // already completed (e.g. by syncBlock) return false; // already completed (e.g. by syncBlock)
final boolean b = commitBlock( final boolean b = commitBlock(
(BlockInfoContiguousUnderConstruction) lastBlock, commitBlock); (BlockInfoContiguousUnderConstruction)lastBlock, commitBlock);
if(countNodes(lastBlock).liveReplicas() >= minReplication) if(countNodes(lastBlock).liveReplicas() >= minReplication)
completeBlock(bc, bc.numBlocks()-1, false); completeBlock(bc, bc.numBlocks()-1, false);
return b; return b;
@ -644,15 +644,16 @@ public boolean commitOrCompleteLastBlock(BlockCollection bc,
* @throws IOException if the block does not have at least a minimal number * @throws IOException if the block does not have at least a minimal number
* of replicas reported from data-nodes. * of replicas reported from data-nodes.
*/ */
private BlockInfoContiguous completeBlock(final BlockCollection bc, private BlockInfo completeBlock(final BlockCollection bc,
final int blkIndex, boolean force) throws IOException { final int blkIndex, boolean force) throws IOException {
if(blkIndex < 0) if(blkIndex < 0)
return null; return null;
BlockInfoContiguous curBlock = bc.getBlocks()[blkIndex]; BlockInfoContiguous curBlock = bc.getBlocks()[blkIndex];
if(curBlock.isComplete()) if (curBlock.isComplete())
return curBlock; return curBlock;
// TODO: support BlockInfoStripedUC
BlockInfoContiguousUnderConstruction ucBlock = BlockInfoContiguousUnderConstruction ucBlock =
(BlockInfoContiguousUnderConstruction) curBlock; (BlockInfoContiguousUnderConstruction)curBlock;
int numNodes = ucBlock.numNodes(); int numNodes = ucBlock.numNodes();
if (!force && numNodes < minReplication) if (!force && numNodes < minReplication)
throw new IOException("Cannot complete block: " + throw new IOException("Cannot complete block: " +
@ -678,13 +679,15 @@ private BlockInfoContiguous completeBlock(final BlockCollection bc,
return blocksMap.replaceBlock(completeBlock); return blocksMap.replaceBlock(completeBlock);
} }
private BlockInfoContiguous completeBlock(final BlockCollection bc, // TODO: support BlockInfoStrippedUC
final BlockInfoContiguous block, boolean force) throws IOException { private BlockInfo completeBlock(final BlockCollection bc,
final BlockInfo block, boolean force) throws IOException {
BlockInfoContiguous[] fileBlocks = bc.getBlocks(); BlockInfoContiguous[] fileBlocks = bc.getBlocks();
for(int idx = 0; idx < fileBlocks.length; idx++) for (int idx = 0; idx < fileBlocks.length; idx++) {
if(fileBlocks[idx] == block) { if (fileBlocks[idx] == block) {
return completeBlock(bc, idx, force); return completeBlock(bc, idx, force);
} }
}
return block; return block;
} }
@ -693,7 +696,7 @@ private BlockInfoContiguous completeBlock(final BlockCollection bc,
* regardless of whether enough replicas are present. This is necessary * regardless of whether enough replicas are present. This is necessary
* when tailing edit logs as a Standby. * when tailing edit logs as a Standby.
*/ */
public BlockInfoContiguous forceCompleteBlock(final BlockCollection bc, public BlockInfo forceCompleteBlock(final BlockCollection bc,
final BlockInfoContiguousUnderConstruction block) throws IOException { final BlockInfoContiguousUnderConstruction block) throws IOException {
block.commitBlock(block); block.commitBlock(block);
return completeBlock(bc, block, true); return completeBlock(bc, block, true);
@ -725,8 +728,8 @@ public LocatedBlock convertLastBlockToUnderConstruction(
DatanodeStorageInfo[] targets = getStorages(oldBlock); DatanodeStorageInfo[] targets = getStorages(oldBlock);
BlockInfoContiguousUnderConstruction ucBlock = BlockInfoContiguousUnderConstruction ucBlock = bc.setLastBlock(oldBlock,
bc.setLastBlock(oldBlock, targets); targets);
blocksMap.replaceBlock(ucBlock); blocksMap.replaceBlock(ucBlock);
// Remove block from replication queue. // Remove block from replication queue.
@ -1027,7 +1030,7 @@ private BlocksWithLocations getBlocksWithLocations(final DatanodeID datanode,
if(numBlocks == 0) { if(numBlocks == 0) {
return new BlocksWithLocations(new BlockWithLocations[0]); return new BlocksWithLocations(new BlockWithLocations[0]);
} }
Iterator<BlockInfoContiguous> iter = node.getBlockIterator(); Iterator<BlockInfo> iter = node.getBlockIterator();
// starting from a random block // starting from a random block
int startBlock = ThreadLocalRandom.current().nextInt(numBlocks); int startBlock = ThreadLocalRandom.current().nextInt(numBlocks);
// skip blocks // skip blocks
@ -1036,7 +1039,7 @@ private BlocksWithLocations getBlocksWithLocations(final DatanodeID datanode,
} }
List<BlockWithLocations> results = new ArrayList<BlockWithLocations>(); List<BlockWithLocations> results = new ArrayList<BlockWithLocations>();
long totalSize = 0; long totalSize = 0;
BlockInfoContiguous curBlock; BlockInfo curBlock;
while(totalSize<size && iter.hasNext()) { while(totalSize<size && iter.hasNext()) {
curBlock = iter.next(); curBlock = iter.next();
if(!curBlock.isComplete()) continue; if(!curBlock.isComplete()) continue;
@ -1135,7 +1138,8 @@ void removeFromInvalidates(final DatanodeInfo datanode) {
public void findAndMarkBlockAsCorrupt(final ExtendedBlock blk, public void findAndMarkBlockAsCorrupt(final ExtendedBlock blk,
final DatanodeInfo dn, String storageID, String reason) throws IOException { final DatanodeInfo dn, String storageID, String reason) throws IOException {
assert namesystem.hasWriteLock(); assert namesystem.hasWriteLock();
final BlockInfoContiguous storedBlock = getStoredBlock(blk.getLocalBlock()); final Block reportedBlock = blk.getLocalBlock();
final BlockInfo storedBlock = getStoredBlock(reportedBlock);
if (storedBlock == null) { if (storedBlock == null) {
// Check if the replica is in the blockMap, if not // Check if the replica is in the blockMap, if not
// ignore the request for now. This could happen when BlockScanner // ignore the request for now. This could happen when BlockScanner
@ -1152,7 +1156,7 @@ public void findAndMarkBlockAsCorrupt(final ExtendedBlock blk,
+ ") does not exist"); + ") does not exist");
} }
markBlockAsCorrupt(new BlockToMarkCorrupt(storedBlock, markBlockAsCorrupt(new BlockToMarkCorrupt(reportedBlock, storedBlock,
blk.getGenerationStamp(), reason, Reason.CORRUPTION_REPORTED), blk.getGenerationStamp(), reason, Reason.CORRUPTION_REPORTED),
storageID == null ? null : node.getStorageInfo(storageID), storageID == null ? null : node.getStorageInfo(storageID),
node); node);
@ -1179,7 +1183,7 @@ private void markBlockAsCorrupt(BlockToMarkCorrupt b,
// Add replica to the data-node if it is not already there // Add replica to the data-node if it is not already there
if (storageInfo != null) { if (storageInfo != null) {
storageInfo.addBlock(b.stored); storageInfo.addBlock(b.stored, b.reportedBlock);
} }
// Add this replica to corruptReplicas Map // Add this replica to corruptReplicas Map
@ -1732,40 +1736,54 @@ static class StatefulBlockInfo {
} }
} }
private static class BlockInfoToAdd {
final BlockInfo stored;
final Block reported;
BlockInfoToAdd(BlockInfo stored, Block reported) {
this.stored = stored;
this.reported = reported;
}
}
/** /**
* BlockToMarkCorrupt is used to build the "toCorrupt" list, which is a * BlockToMarkCorrupt is used to build the "toCorrupt" list, which is a
* list of blocks that should be considered corrupt due to a block report. * list of blocks that should be considered corrupt due to a block report.
*/ */
private static class BlockToMarkCorrupt { private static class BlockToMarkCorrupt {
/** The corrupted block in a datanode. */ /** The corrupted block in a datanode. */
final BlockInfoContiguous corrupted; final BlockInfo corrupted;
/** The corresponding block stored in the BlockManager. */ /** The corresponding block stored in the BlockManager. */
final BlockInfoContiguous stored; final BlockInfo stored;
/** The block reported from a datanode */
final Block reportedBlock;
/** The reason to mark corrupt. */ /** The reason to mark corrupt. */
final String reason; final String reason;
/** The reason code to be stored */ /** The reason code to be stored */
final Reason reasonCode; final Reason reasonCode;
BlockToMarkCorrupt(BlockInfoContiguous corrupted, BlockToMarkCorrupt(Block reported, BlockInfo corrupted,
BlockInfoContiguous stored, String reason, BlockInfo stored, String reason, Reason reasonCode) {
Reason reasonCode) { Preconditions.checkNotNull(reported, "reported is null");
Preconditions.checkNotNull(corrupted, "corrupted is null"); Preconditions.checkNotNull(corrupted, "corrupted is null");
Preconditions.checkNotNull(stored, "stored is null"); Preconditions.checkNotNull(stored, "stored is null");
this.reportedBlock = reported;
this.corrupted = corrupted; this.corrupted = corrupted;
this.stored = stored; this.stored = stored;
this.reason = reason; this.reason = reason;
this.reasonCode = reasonCode; this.reasonCode = reasonCode;
} }
BlockToMarkCorrupt(BlockInfoContiguous stored, String reason, BlockToMarkCorrupt(Block reported, BlockInfo stored, String reason,
Reason reasonCode) { Reason reasonCode) {
this(stored, stored, reason, reasonCode); this(reported, stored, stored, reason, reasonCode);
} }
BlockToMarkCorrupt(BlockInfoContiguous stored, long gs, String reason, BlockToMarkCorrupt(Block reported, BlockInfo stored, long gs,
Reason reasonCode) { String reason, Reason reasonCode) {
this(new BlockInfoContiguous(stored), stored, reason, reasonCode); this(reported, BlockInfo.copyOf(stored), stored, reason,
reasonCode);
//the corrupted block in datanode has a different generation stamp //the corrupted block in datanode has a different generation stamp
corrupted.setGenerationStamp(gs); corrupted.setGenerationStamp(gs);
} }
@ -1943,7 +1961,7 @@ void rescanPostponedMisreplicatedBlocks() {
break; break;
} }
BlockInfoContiguous bi = getStoredBlock(b); BlockInfo bi = getStoredBlock(b);
if (bi == null) { if (bi == null) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("BLOCK* rescanPostponedMisreplicatedBlocks: " + LOG.debug("BLOCK* rescanPostponedMisreplicatedBlocks: " +
@ -1983,7 +2001,7 @@ private Collection<Block> processReport(
// Modify the (block-->datanode) map, according to the difference // Modify the (block-->datanode) map, according to the difference
// between the old and new block report. // between the old and new block report.
// //
Collection<BlockInfoContiguous> toAdd = new LinkedList<BlockInfoContiguous>(); Collection<BlockInfoToAdd> toAdd = new LinkedList<>();
Collection<Block> toRemove = new TreeSet<Block>(); Collection<Block> toRemove = new TreeSet<Block>();
Collection<Block> toInvalidate = new LinkedList<Block>(); Collection<Block> toInvalidate = new LinkedList<Block>();
Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>(); Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>();
@ -2000,8 +2018,9 @@ private Collection<Block> processReport(
removeStoredBlock(b, node); removeStoredBlock(b, node);
} }
int numBlocksLogged = 0; int numBlocksLogged = 0;
for (BlockInfoContiguous b : toAdd) { for (BlockInfoToAdd b : toAdd) {
addStoredBlock(b, storageInfo, null, numBlocksLogged < maxNumBlocksToLog); addStoredBlock(b.stored, b.reported, storageInfo, null,
numBlocksLogged < maxNumBlocksToLog);
numBlocksLogged++; numBlocksLogged++;
} }
if (numBlocksLogged > maxNumBlocksToLog) { if (numBlocksLogged > maxNumBlocksToLog) {
@ -2091,7 +2110,7 @@ private void processFirstBlockReport(
continue; continue;
} }
BlockInfoContiguous storedBlock = getStoredBlock(iblk); BlockInfo storedBlock = getStoredBlock(iblk);
// If block does not belong to any file, we are done. // If block does not belong to any file, we are done.
if (storedBlock == null) continue; if (storedBlock == null) continue;
@ -2114,7 +2133,7 @@ private void processFirstBlockReport(
// If block is under construction, add this replica to its list // If block is under construction, add this replica to its list
if (isBlockUnderConstruction(storedBlock, ucState, reportedState)) { if (isBlockUnderConstruction(storedBlock, ucState, reportedState)) {
((BlockInfoContiguousUnderConstruction)storedBlock) ((BlockInfoContiguousUnderConstruction) storedBlock)
.addReplicaIfNotPresent(storageInfo, iblk, reportedState); .addReplicaIfNotPresent(storageInfo, iblk, reportedState);
// OpenFileBlocks only inside snapshots also will be added to safemode // OpenFileBlocks only inside snapshots also will be added to safemode
// threshold. So we need to update such blocks to safemode // threshold. So we need to update such blocks to safemode
@ -2129,14 +2148,14 @@ private void processFirstBlockReport(
} }
//add replica if appropriate //add replica if appropriate
if (reportedState == ReplicaState.FINALIZED) { if (reportedState == ReplicaState.FINALIZED) {
addStoredBlockImmediate(storedBlock, storageInfo); addStoredBlockImmediate(storedBlock, iblk, storageInfo);
} }
} }
} }
private void reportDiff(DatanodeStorageInfo storageInfo, private void reportDiff(DatanodeStorageInfo storageInfo,
BlockListAsLongs newReport, BlockListAsLongs newReport,
Collection<BlockInfoContiguous> toAdd, // add to DatanodeDescriptor Collection<BlockInfoToAdd> 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<BlockToMarkCorrupt> toCorrupt, // add to corrupt replicas list Collection<BlockToMarkCorrupt> toCorrupt, // add to corrupt replicas list
@ -2144,8 +2163,10 @@ private void reportDiff(DatanodeStorageInfo storageInfo,
// 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
BlockInfoContiguous delimiter = new BlockInfoContiguous(new Block(), (short) 1); Block delimiterBlock = new Block();
AddBlockResult result = storageInfo.addBlock(delimiter); BlockInfoContiguous delimiter = new BlockInfoContiguous(delimiterBlock,
(short) 1);
AddBlockResult result = storageInfo.addBlock(delimiter, delimiterBlock);
assert result == AddBlockResult.ADDED assert result == AddBlockResult.ADDED
: "Delimiting block cannot be present in the node"; : "Delimiting block cannot be present in the node";
int headIndex = 0; //currently the delimiter is in the head of the list int headIndex = 0; //currently the delimiter is in the head of the list
@ -2157,7 +2178,7 @@ private void reportDiff(DatanodeStorageInfo storageInfo,
// scan the report and process newly reported blocks // scan the report and process newly reported blocks
for (BlockReportReplica iblk : newReport) { for (BlockReportReplica iblk : newReport) {
ReplicaState iState = iblk.getState(); ReplicaState iState = iblk.getState();
BlockInfoContiguous storedBlock = processReportedBlock(storageInfo, BlockInfo storedBlock = processReportedBlock(storageInfo,
iblk, iState, toAdd, toInvalidate, toCorrupt, toUC); iblk, iState, toAdd, toInvalidate, toCorrupt, toUC);
// move block to the head of the list // move block to the head of the list
@ -2169,8 +2190,7 @@ private void reportDiff(DatanodeStorageInfo storageInfo,
// collect blocks that have not been reported // collect blocks that have not been reported
// all of them are next to the delimiter // all of them are next to the delimiter
Iterator<BlockInfoContiguous> it = Iterator<BlockInfo> it = storageInfo.new BlockIterator(delimiter.getNext(0));
storageInfo.new BlockIterator(delimiter.getNext(0));
while(it.hasNext()) while(it.hasNext())
toRemove.add(it.next()); toRemove.add(it.next());
storageInfo.removeBlock(delimiter); storageInfo.removeBlock(delimiter);
@ -2207,10 +2227,10 @@ private void reportDiff(DatanodeStorageInfo storageInfo,
* @return the up-to-date stored block, if it should be kept. * @return the up-to-date stored block, if it should be kept.
* Otherwise, null. * Otherwise, null.
*/ */
private BlockInfoContiguous processReportedBlock( private BlockInfo processReportedBlock(
final DatanodeStorageInfo storageInfo, final DatanodeStorageInfo storageInfo,
final Block block, final ReplicaState reportedState, final Block block, final ReplicaState reportedState,
final Collection<BlockInfoContiguous> toAdd, final Collection<BlockInfoToAdd> toAdd,
final Collection<Block> toInvalidate, final Collection<Block> toInvalidate,
final Collection<BlockToMarkCorrupt> toCorrupt, final Collection<BlockToMarkCorrupt> toCorrupt,
final Collection<StatefulBlockInfo> toUC) { final Collection<StatefulBlockInfo> toUC) {
@ -2231,7 +2251,7 @@ private BlockInfoContiguous processReportedBlock(
} }
// find block by blockId // find block by blockId
BlockInfoContiguous storedBlock = getStoredBlock(block); BlockInfo storedBlock = getStoredBlock(block);
if(storedBlock == null) { if(storedBlock == null) {
// If blocksMap does not contain reported block id, // If blocksMap does not contain reported block id,
// the replica should be removed from the data-node. // the replica should be removed from the data-node.
@ -2285,7 +2305,7 @@ private BlockInfoContiguous processReportedBlock(
if (reportedState == ReplicaState.FINALIZED if (reportedState == ReplicaState.FINALIZED
&& (storedBlock.findStorageInfo(storageInfo) == -1 || && (storedBlock.findStorageInfo(storageInfo) == -1 ||
corruptReplicas.isReplicaCorrupt(storedBlock, dn))) { corruptReplicas.isReplicaCorrupt(storedBlock, dn))) {
toAdd.add(storedBlock); toAdd.add(new BlockInfoToAdd(storedBlock, block));
} }
return storedBlock; return storedBlock;
} }
@ -2370,7 +2390,7 @@ public void processAllPendingDNMessages() throws IOException {
*/ */
private BlockToMarkCorrupt checkReplicaCorrupt( private BlockToMarkCorrupt checkReplicaCorrupt(
Block reported, ReplicaState reportedState, Block reported, ReplicaState reportedState,
BlockInfoContiguous storedBlock, BlockUCState ucState, BlockInfo storedBlock, BlockUCState ucState,
DatanodeDescriptor dn) { DatanodeDescriptor dn) {
switch(reportedState) { switch(reportedState) {
case FINALIZED: case FINALIZED:
@ -2379,12 +2399,12 @@ private BlockToMarkCorrupt checkReplicaCorrupt(
case COMMITTED: case COMMITTED:
if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) { if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) {
final long reportedGS = reported.getGenerationStamp(); final long reportedGS = reported.getGenerationStamp();
return new BlockToMarkCorrupt(storedBlock, reportedGS, return new BlockToMarkCorrupt(reported, storedBlock, reportedGS,
"block is " + ucState + " and reported genstamp " + reportedGS "block is " + ucState + " and reported genstamp " + reportedGS
+ " does not match genstamp in block map " + " does not match genstamp in block map "
+ storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH); + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
} else if (storedBlock.getNumBytes() != reported.getNumBytes()) { } else if (storedBlock.getNumBytes() != reported.getNumBytes()) {
return new BlockToMarkCorrupt(storedBlock, return new BlockToMarkCorrupt(reported, storedBlock,
"block is " + ucState + " and reported length " + "block is " + ucState + " and reported length " +
reported.getNumBytes() + " does not match " + reported.getNumBytes() + " does not match " +
"length in block map " + storedBlock.getNumBytes(), "length in block map " + storedBlock.getNumBytes(),
@ -2395,8 +2415,8 @@ private BlockToMarkCorrupt checkReplicaCorrupt(
case UNDER_CONSTRUCTION: case UNDER_CONSTRUCTION:
if (storedBlock.getGenerationStamp() > reported.getGenerationStamp()) { if (storedBlock.getGenerationStamp() > reported.getGenerationStamp()) {
final long reportedGS = reported.getGenerationStamp(); final long reportedGS = reported.getGenerationStamp();
return new BlockToMarkCorrupt(storedBlock, reportedGS, "block is " return new BlockToMarkCorrupt(reported, storedBlock, reportedGS,
+ ucState + " and reported state " + reportedState "block is " + ucState + " and reported state " + reportedState
+ ", But reported genstamp " + reportedGS + ", But reported genstamp " + reportedGS
+ " does not match genstamp in block map " + " does not match genstamp in block map "
+ storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH); + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
@ -2411,7 +2431,7 @@ private BlockToMarkCorrupt checkReplicaCorrupt(
return null; // not corrupt return null; // not corrupt
} else if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) { } else if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) {
final long reportedGS = reported.getGenerationStamp(); final long reportedGS = reported.getGenerationStamp();
return new BlockToMarkCorrupt(storedBlock, reportedGS, return new BlockToMarkCorrupt(reported, storedBlock, reportedGS,
"reported " + reportedState + " replica with genstamp " + reportedGS "reported " + reportedState + " replica with genstamp " + reportedGS
+ " does not match COMPLETE block's genstamp in block map " + " does not match COMPLETE block's genstamp in block map "
+ storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH); + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
@ -2426,7 +2446,7 @@ private BlockToMarkCorrupt checkReplicaCorrupt(
"complete with the same genstamp"); "complete with the same genstamp");
return null; return null;
} else { } else {
return new BlockToMarkCorrupt(storedBlock, return new BlockToMarkCorrupt(reported, storedBlock,
"reported replica has invalid state " + reportedState, "reported replica has invalid state " + reportedState,
Reason.INVALID_STATE); Reason.INVALID_STATE);
} }
@ -2439,11 +2459,12 @@ private BlockToMarkCorrupt checkReplicaCorrupt(
" on " + dn + " size " + storedBlock.getNumBytes(); " on " + dn + " size " + storedBlock.getNumBytes();
// log here at WARN level since this is really a broken HDFS invariant // log here at WARN level since this is really a broken HDFS invariant
LOG.warn(msg); LOG.warn(msg);
return new BlockToMarkCorrupt(storedBlock, msg, Reason.INVALID_STATE); return new BlockToMarkCorrupt(reported, storedBlock, msg,
Reason.INVALID_STATE);
} }
} }
private boolean isBlockUnderConstruction(BlockInfoContiguous storedBlock, private boolean isBlockUnderConstruction(BlockInfo storedBlock,
BlockUCState ucState, ReplicaState reportedState) { BlockUCState ucState, ReplicaState reportedState) {
switch(reportedState) { switch(reportedState) {
case FINALIZED: case FINALIZED:
@ -2472,7 +2493,7 @@ void addStoredBlockUnderConstruction(StatefulBlockInfo ucBlock,
if (ucBlock.reportedState == ReplicaState.FINALIZED && if (ucBlock.reportedState == ReplicaState.FINALIZED &&
(block.findStorageInfo(storageInfo) < 0)) { (block.findStorageInfo(storageInfo) < 0)) {
addStoredBlock(block, storageInfo, null, true); addStoredBlock(block, ucBlock.reportedBlock, storageInfo, null, true);
} }
} }
@ -2487,18 +2508,18 @@ void addStoredBlockUnderConstruction(StatefulBlockInfo ucBlock,
* *
* @throws IOException * @throws IOException
*/ */
private void addStoredBlockImmediate(BlockInfoContiguous storedBlock, private void addStoredBlockImmediate(BlockInfo storedBlock, Block reported,
DatanodeStorageInfo storageInfo) DatanodeStorageInfo storageInfo)
throws IOException { throws IOException {
assert (storedBlock != null && namesystem.hasWriteLock()); assert (storedBlock != null && namesystem.hasWriteLock());
if (!namesystem.isInStartupSafeMode() if (!namesystem.isInStartupSafeMode()
|| namesystem.isPopulatingReplQueues()) { || namesystem.isPopulatingReplQueues()) {
addStoredBlock(storedBlock, storageInfo, null, false); addStoredBlock(storedBlock, reported, storageInfo, null, false);
return; return;
} }
// just add it // just add it
AddBlockResult result = storageInfo.addBlock(storedBlock); AddBlockResult result = storageInfo.addBlock(storedBlock, reported);
// Now check for completion of blocks and safe block count // Now check for completion of blocks and safe block count
int numCurrentReplica = countLiveNodes(storedBlock); int numCurrentReplica = countLiveNodes(storedBlock);
@ -2519,13 +2540,14 @@ private void addStoredBlockImmediate(BlockInfoContiguous storedBlock,
* needed replications if this takes care of the problem. * needed replications if this takes care of the problem.
* @return the block that is stored in blockMap. * @return the block that is stored in blockMap.
*/ */
private Block addStoredBlock(final BlockInfoContiguous block, private Block addStoredBlock(final BlockInfo block,
final Block reportedBlock,
DatanodeStorageInfo storageInfo, DatanodeStorageInfo storageInfo,
DatanodeDescriptor delNodeHint, DatanodeDescriptor delNodeHint,
boolean logEveryBlock) boolean logEveryBlock)
throws IOException { throws IOException {
assert block != null && namesystem.hasWriteLock(); assert block != null && namesystem.hasWriteLock();
BlockInfoContiguous storedBlock; BlockInfo storedBlock;
DatanodeDescriptor node = storageInfo.getDatanodeDescriptor(); DatanodeDescriptor node = storageInfo.getDatanodeDescriptor();
if (block instanceof BlockInfoContiguousUnderConstruction) { if (block instanceof BlockInfoContiguousUnderConstruction) {
//refresh our copy in case the block got completed in another thread //refresh our copy in case the block got completed in another thread
@ -2546,7 +2568,7 @@ private Block addStoredBlock(final BlockInfoContiguous block,
assert bc != null : "Block must belong to a file"; assert bc != null : "Block must belong to a file";
// add block to the datanode // add block to the datanode
AddBlockResult result = storageInfo.addBlock(storedBlock); AddBlockResult result = storageInfo.addBlock(storedBlock, reportedBlock);
int curReplicaDelta; int curReplicaDelta;
if (result == AddBlockResult.ADDED) { if (result == AddBlockResult.ADDED) {
@ -2618,13 +2640,13 @@ private Block addStoredBlock(final BlockInfoContiguous block,
storedBlock + "blockMap has " + numCorruptNodes + storedBlock + "blockMap has " + numCorruptNodes +
" but corrupt replicas map has " + corruptReplicasCount); " but corrupt replicas map has " + corruptReplicasCount);
} }
if ((corruptReplicasCount > 0) && (numLiveReplicas >= fileReplication)) if ((corruptReplicasCount > 0) && (numLiveReplicas >= fileReplication)) {
invalidateCorruptReplicas(storedBlock); invalidateCorruptReplicas(storedBlock, reportedBlock);
}
return storedBlock; return storedBlock;
} }
private void logAddStoredBlock(BlockInfoContiguous storedBlock, private void logAddStoredBlock(BlockInfo storedBlock, DatanodeDescriptor node) {
DatanodeDescriptor node) {
if (!blockLog.isInfoEnabled()) { if (!blockLog.isInfoEnabled()) {
return; return;
} }
@ -2651,7 +2673,7 @@ private void logAddStoredBlock(BlockInfoContiguous storedBlock,
* *
* @param blk Block whose corrupt replicas need to be invalidated * @param blk Block whose corrupt replicas need to be invalidated
*/ */
private void invalidateCorruptReplicas(BlockInfoContiguous blk) { private void invalidateCorruptReplicas(BlockInfo blk, Block reported) {
Collection<DatanodeDescriptor> nodes = corruptReplicas.getNodes(blk); Collection<DatanodeDescriptor> nodes = corruptReplicas.getNodes(blk);
boolean removedFromBlocksMap = true; boolean removedFromBlocksMap = true;
if (nodes == null) if (nodes == null)
@ -2661,7 +2683,7 @@ private void invalidateCorruptReplicas(BlockInfoContiguous blk) {
DatanodeDescriptor[] nodesCopy = nodes.toArray(new DatanodeDescriptor[0]); DatanodeDescriptor[] nodesCopy = nodes.toArray(new DatanodeDescriptor[0]);
for (DatanodeDescriptor node : nodesCopy) { for (DatanodeDescriptor node : nodesCopy) {
try { try {
if (!invalidateBlock(new BlockToMarkCorrupt(blk, null, if (!invalidateBlock(new BlockToMarkCorrupt(reported, blk, null,
Reason.ANY), node)) { Reason.ANY), node)) {
removedFromBlocksMap = false; removedFromBlocksMap = false;
} }
@ -2730,7 +2752,7 @@ private void processMisReplicatesAsync() throws InterruptedException {
long nrInvalid = 0, nrOverReplicated = 0; long nrInvalid = 0, nrOverReplicated = 0;
long nrUnderReplicated = 0, nrPostponed = 0, nrUnderConstruction = 0; long nrUnderReplicated = 0, nrPostponed = 0, nrUnderConstruction = 0;
long startTimeMisReplicatedScan = Time.monotonicNow(); long startTimeMisReplicatedScan = Time.monotonicNow();
Iterator<BlockInfoContiguous> blocksItr = blocksMap.getBlocks().iterator(); Iterator<BlockInfo> blocksItr = blocksMap.getBlocks().iterator();
long totalBlocks = blocksMap.size(); long totalBlocks = blocksMap.size();
replicationQueuesInitProgress = 0; replicationQueuesInitProgress = 0;
long totalProcessed = 0; long totalProcessed = 0;
@ -2742,7 +2764,7 @@ private void processMisReplicatesAsync() throws InterruptedException {
namesystem.writeLockInterruptibly(); namesystem.writeLockInterruptibly();
try { try {
while (processed < numBlocksPerIteration && blocksItr.hasNext()) { while (processed < numBlocksPerIteration && blocksItr.hasNext()) {
BlockInfoContiguous block = blocksItr.next(); BlockInfo block = blocksItr.next();
MisReplicationResult res = processMisReplicatedBlock(block); MisReplicationResult res = processMisReplicatedBlock(block);
if (LOG.isTraceEnabled()) { if (LOG.isTraceEnabled()) {
LOG.trace("block " + block + ": " + res); LOG.trace("block " + block + ": " + res);
@ -2817,7 +2839,7 @@ public double getReplicationQueuesInitProgress() {
* appropriate queues if necessary, and returns a result code indicating * appropriate queues if necessary, and returns a result code indicating
* what happened with it. * what happened with it.
*/ */
private MisReplicationResult processMisReplicatedBlock(BlockInfoContiguous block) { private MisReplicationResult processMisReplicatedBlock(BlockInfo block) {
if (block.isDeleted()) { if (block.isDeleted()) {
// block does not belong to any file // block does not belong to any file
addToInvalidates(block); addToInvalidates(block);
@ -3157,14 +3179,14 @@ private void processAndHandleReportedBlock(
ReplicaState reportedState, DatanodeDescriptor delHintNode) ReplicaState reportedState, DatanodeDescriptor delHintNode)
throws IOException { throws IOException {
// blockReceived reports a finalized block // blockReceived reports a finalized block
Collection<BlockInfoContiguous> toAdd = new LinkedList<BlockInfoContiguous>(); Collection<BlockInfoToAdd> toAdd = new LinkedList<>();
Collection<Block> toInvalidate = new LinkedList<Block>(); Collection<Block> toInvalidate = new LinkedList<Block>();
Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>(); Collection<BlockToMarkCorrupt> toCorrupt = new LinkedList<BlockToMarkCorrupt>();
Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>(); Collection<StatefulBlockInfo> toUC = new LinkedList<StatefulBlockInfo>();
final DatanodeDescriptor node = storageInfo.getDatanodeDescriptor(); final DatanodeDescriptor node = storageInfo.getDatanodeDescriptor();
processReportedBlock(storageInfo, block, reportedState, processReportedBlock(storageInfo, block, reportedState, toAdd, toInvalidate,
toAdd, toInvalidate, toCorrupt, toUC); toCorrupt, toUC);
// the block is only in one of the to-do lists // the block is only in one of the to-do lists
// if it is in none then data-node already has it // if it is in none then data-node already has it
assert toUC.size() + toAdd.size() + toInvalidate.size() + toCorrupt.size() <= 1 assert toUC.size() + toAdd.size() + toInvalidate.size() + toCorrupt.size() <= 1
@ -3174,8 +3196,9 @@ private void processAndHandleReportedBlock(
addStoredBlockUnderConstruction(b, storageInfo); addStoredBlockUnderConstruction(b, storageInfo);
} }
long numBlocksLogged = 0; long numBlocksLogged = 0;
for (BlockInfoContiguous b : toAdd) { for (BlockInfoToAdd b : toAdd) {
addStoredBlock(b, storageInfo, delHintNode, numBlocksLogged < maxNumBlocksToLog); addStoredBlock(b.stored, b.reported, storageInfo, delHintNode,
numBlocksLogged < maxNumBlocksToLog);
numBlocksLogged++; numBlocksLogged++;
} }
if (numBlocksLogged > maxNumBlocksToLog) { if (numBlocksLogged > maxNumBlocksToLog) {
@ -3301,7 +3324,7 @@ public NumberReplicas countNodes(Block b) {
* @param b - the block being tested * @param b - the block being tested
* @return count of live nodes for this block * @return count of live nodes for this block
*/ */
int countLiveNodes(BlockInfoContiguous b) { int countLiveNodes(BlockInfo b) {
if (!namesystem.isInStartupSafeMode()) { if (!namesystem.isInStartupSafeMode()) {
return countNodes(b).liveReplicas(); return countNodes(b).liveReplicas();
} }
@ -3380,7 +3403,7 @@ public int getActiveBlockCount() {
return blocksMap.size(); return blocksMap.size();
} }
public DatanodeStorageInfo[] getStorages(BlockInfoContiguous block) { public DatanodeStorageInfo[] getStorages(BlockInfo block) {
final DatanodeStorageInfo[] storages = new DatanodeStorageInfo[block.numNodes()]; final DatanodeStorageInfo[] storages = new DatanodeStorageInfo[block.numNodes()];
int i = 0; int i = 0;
for(DatanodeStorageInfo s : blocksMap.getStorages(block)) { for(DatanodeStorageInfo s : blocksMap.getStorages(block)) {
@ -3409,8 +3432,8 @@ public void removeBlock(Block block) {
} }
} }
public BlockInfoContiguous getStoredBlock(Block block) { public BlockInfo getStoredBlock(Block block) {
BlockInfoContiguous info = null; BlockInfo info = null;
if (BlockIdManager.isStripedBlockID(block.getBlockId())) { if (BlockIdManager.isStripedBlockID(block.getBlockId())) {
info = blocksMap.getStoredBlock( info = blocksMap.getStoredBlock(
new Block(BlockIdManager.convertToGroupID(block.getBlockId()))); new Block(BlockIdManager.convertToGroupID(block.getBlockId())));
@ -3588,7 +3611,8 @@ public long getMissingReplOneBlocksCount() {
public BlockInfoContiguous addBlockCollection(BlockInfoContiguous block, public BlockInfoContiguous addBlockCollection(BlockInfoContiguous block,
BlockCollection bc) { BlockCollection bc) {
return blocksMap.addBlockCollection(block, bc); // TODO
return (BlockInfoContiguous) blocksMap.addBlockCollection(block, bc);
} }
public BlockCollection getBlockCollection(Block b) { public BlockCollection getBlockCollection(Block b) {
@ -3826,7 +3850,7 @@ private void chooseTargets(BlockPlacementPolicy blockplacement,
/** /**
* A simple result enum for the result of * A simple result enum for the result of
* {@link BlockManager#processMisReplicatedBlock(BlockInfoContiguous)}. * {@link BlockManager#processMisReplicatedBlock}.
*/ */
enum MisReplicationResult { enum MisReplicationResult {
/** The block should be invalidated since it belongs to a deleted file. */ /** The block should be invalidated since it belongs to a deleted file. */

View File

@ -20,12 +20,10 @@
import java.util.Iterator; import java.util.Iterator;
import org.apache.hadoop.hdfs.protocol.Block; import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo.AddBlockResult;
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage; import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage;
import org.apache.hadoop.util.GSet; import org.apache.hadoop.util.GSet;
import org.apache.hadoop.util.LightWeightGSet; import org.apache.hadoop.util.LightWeightGSet;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@ -36,10 +34,10 @@
*/ */
class BlocksMap { class BlocksMap {
private static class StorageIterator implements Iterator<DatanodeStorageInfo> { private static class StorageIterator implements Iterator<DatanodeStorageInfo> {
private final BlockInfoContiguous blockInfo; private final BlockInfo blockInfo;
private int nextIdx = 0; private int nextIdx = 0;
StorageIterator(BlockInfoContiguous blkInfo) { StorageIterator(BlockInfo blkInfo) {
this.blockInfo = blkInfo; this.blockInfo = blkInfo;
} }
@ -63,14 +61,14 @@ public void remove() {
/** Constant {@link LightWeightGSet} capacity. */ /** Constant {@link LightWeightGSet} capacity. */
private final int capacity; private final int capacity;
private GSet<Block, BlockInfoContiguous> blocks; private GSet<Block, BlockInfo> blocks;
BlocksMap(int capacity) { BlocksMap(int capacity) {
// Use 2% of total memory to size the GSet capacity // Use 2% of total memory to size the GSet capacity
this.capacity = capacity; this.capacity = capacity;
this.blocks = new LightWeightGSet<Block, BlockInfoContiguous>(capacity) { this.blocks = new LightWeightGSet<Block, BlockInfo>(capacity) {
@Override @Override
public Iterator<BlockInfoContiguous> iterator() { public Iterator<BlockInfo> iterator() {
SetIterator iterator = new SetIterator(); SetIterator iterator = new SetIterator();
/* /*
* Not tracking any modifications to set. As this set will be used * Not tracking any modifications to set. As this set will be used
@ -97,15 +95,15 @@ void clear() {
} }
BlockCollection getBlockCollection(Block b) { BlockCollection getBlockCollection(Block b) {
BlockInfoContiguous info = blocks.get(b); BlockInfo info = blocks.get(b);
return (info != null) ? info.getBlockCollection() : null; return (info != null) ? info.getBlockCollection() : null;
} }
/** /**
* Add block b belonging to the specified block collection to the map. * Add block b belonging to the specified block collection to the map.
*/ */
BlockInfoContiguous addBlockCollection(BlockInfoContiguous b, BlockCollection bc) { BlockInfo addBlockCollection(BlockInfo b, BlockCollection bc) {
BlockInfoContiguous info = blocks.get(b); BlockInfo info = blocks.get(b);
if (info != b) { if (info != b) {
info = b; info = b;
blocks.put(info); blocks.put(info);
@ -120,11 +118,12 @@ BlockInfoContiguous addBlockCollection(BlockInfoContiguous b, BlockCollection bc
* and remove all data-node locations associated with the block. * and remove all data-node locations associated with the block.
*/ */
void removeBlock(Block block) { void removeBlock(Block block) {
BlockInfoContiguous blockInfo = blocks.remove(block); BlockInfo blockInfo = blocks.remove(block);
if (blockInfo == null) if (blockInfo == null)
return; return;
blockInfo.setBlockCollection(null); blockInfo.setBlockCollection(null);
// TODO: fix this logic for block group
for(int idx = blockInfo.numNodes()-1; idx >= 0; idx--) { for(int idx = blockInfo.numNodes()-1; idx >= 0; idx--) {
DatanodeDescriptor dn = blockInfo.getDatanode(idx); DatanodeDescriptor dn = blockInfo.getDatanode(idx);
dn.removeBlock(blockInfo); // remove from the list and wipe the location dn.removeBlock(blockInfo); // remove from the list and wipe the location
@ -132,7 +131,7 @@ void removeBlock(Block block) {
} }
/** Returns the block object it it exists in the map. */ /** Returns the block object it it exists in the map. */
BlockInfoContiguous getStoredBlock(Block b) { BlockInfo getStoredBlock(Block b) {
return blocks.get(b); return blocks.get(b);
} }
@ -164,7 +163,7 @@ public boolean apply(DatanodeStorageInfo storage) {
* For a block that has already been retrieved from the BlocksMap * For a block that has already been retrieved from the BlocksMap
* returns {@link Iterable} of the storages the block belongs to. * returns {@link Iterable} of the storages the block belongs to.
*/ */
Iterable<DatanodeStorageInfo> getStorages(final BlockInfoContiguous storedBlock) { Iterable<DatanodeStorageInfo> getStorages(final BlockInfo storedBlock) {
return new Iterable<DatanodeStorageInfo>() { return new Iterable<DatanodeStorageInfo>() {
@Override @Override
public Iterator<DatanodeStorageInfo> iterator() { public Iterator<DatanodeStorageInfo> iterator() {
@ -175,7 +174,7 @@ public Iterator<DatanodeStorageInfo> iterator() {
/** counts number of containing nodes. Better than using iterator. */ /** counts number of containing nodes. Better than using iterator. */
int numNodes(Block b) { int numNodes(Block b) {
BlockInfoContiguous info = blocks.get(b); BlockInfo info = blocks.get(b);
return info == null ? 0 : info.numNodes(); return info == null ? 0 : info.numNodes();
} }
@ -185,7 +184,7 @@ int numNodes(Block b) {
* only if it does not belong to any file and data-nodes. * only if it does not belong to any file and data-nodes.
*/ */
boolean removeNode(Block b, DatanodeDescriptor node) { boolean removeNode(Block b, DatanodeDescriptor node) {
BlockInfoContiguous info = blocks.get(b); BlockInfo info = blocks.get(b);
if (info == null) if (info == null)
return false; return false;
@ -203,7 +202,7 @@ int size() {
return blocks.size(); return blocks.size();
} }
Iterable<BlockInfoContiguous> getBlocks() { Iterable<BlockInfo> getBlocks() {
return blocks; return blocks;
} }
@ -218,20 +217,11 @@ int getCapacity() {
* @param newBlock - block for replacement * @param newBlock - block for replacement
* @return new block * @return new block
*/ */
BlockInfoContiguous replaceBlock(BlockInfoContiguous newBlock) { BlockInfo replaceBlock(BlockInfo newBlock) {
BlockInfoContiguous currentBlock = blocks.get(newBlock); BlockInfo currentBlock = blocks.get(newBlock);
assert currentBlock != null : "the block if not in blocksMap"; assert currentBlock != null : "the block if not in blocksMap";
// replace block in data-node lists // replace block in data-node lists
for (int i = currentBlock.numNodes() - 1; i >= 0; i--) { currentBlock.replaceBlock(newBlock);
final DatanodeDescriptor dn = currentBlock.getDatanode(i);
final DatanodeStorageInfo storage = currentBlock.findStorageInfo(dn);
final boolean removed = storage.removeBlock(currentBlock);
Preconditions.checkState(removed, "currentBlock not found.");
final AddBlockResult result = storage.addBlock(newBlock);
Preconditions.checkState(result == AddBlockResult.ADDED,
"newBlock already exists.");
}
// replace block in the map itself // replace block in the map itself
blocks.put(newBlock); blocks.put(newBlock);
return newBlock; return newBlock;

View File

@ -513,8 +513,7 @@ private void rescanCachedBlockMap() {
iter.remove(); iter.remove();
} }
} }
BlockInfoContiguous blockInfo = blockManager. BlockInfoContiguous blockInfo = namesystem.getStoredBlock(new Block(cblock.getBlockId()));
getStoredBlock(new Block(cblock.getBlockId()));
String reason = findReasonForNotCaching(cblock, blockInfo); String reason = findReasonForNotCaching(cblock, blockInfo);
int neededCached = 0; int neededCached = 0;
if (reason != null) { if (reason != null) {
@ -628,8 +627,7 @@ private void addNewPendingCached(final int neededCached,
List<DatanodeDescriptor> pendingCached) { List<DatanodeDescriptor> pendingCached) {
// To figure out which replicas can be cached, we consult the // To figure out which replicas can be cached, we consult the
// blocksMap. We don't want to try to cache a corrupt replica, though. // blocksMap. We don't want to try to cache a corrupt replica, though.
BlockInfoContiguous blockInfo = blockManager. BlockInfoContiguous blockInfo = namesystem.getStoredBlock(new Block(cachedBlock.getBlockId()));
getStoredBlock(new Block(cachedBlock.getBlockId()));
if (blockInfo == null) { if (blockInfo == null) {
LOG.debug("Block {}: can't add new cached replicas," + LOG.debug("Block {}: can't add new cached replicas," +
" because there is no record of this block " + " because there is no record of this block " +
@ -668,7 +666,7 @@ private void addNewPendingCached(final int neededCached,
while (it.hasNext()) { while (it.hasNext()) {
CachedBlock cBlock = it.next(); CachedBlock cBlock = it.next();
BlockInfoContiguous info = BlockInfoContiguous info =
blockManager.getStoredBlock(new Block(cBlock.getBlockId())); namesystem.getStoredBlock(new Block(cBlock.getBlockId()));
if (info != null) { if (info != null) {
pendingBytes -= info.getNumBytes(); pendingBytes -= info.getNumBytes();
} }
@ -678,7 +676,7 @@ private void addNewPendingCached(final int neededCached,
while (it.hasNext()) { while (it.hasNext()) {
CachedBlock cBlock = it.next(); CachedBlock cBlock = it.next();
BlockInfoContiguous info = BlockInfoContiguous info =
blockManager.getStoredBlock(new Block(cBlock.getBlockId())); namesystem.getStoredBlock(new Block(cBlock.getBlockId()));
if (info != null) { if (info != null) {
pendingBytes += info.getNumBytes(); pendingBytes += info.getNumBytes();
} }

View File

@ -335,7 +335,7 @@ List<DatanodeStorageInfo> removeZombieStorages() {
* Remove block from the list of blocks belonging to the data-node. Remove * Remove block from the list of blocks belonging to the data-node. Remove
* data-node from the block. * data-node from the block.
*/ */
boolean removeBlock(BlockInfoContiguous b) { boolean removeBlock(BlockInfo b) {
final DatanodeStorageInfo s = b.findStorageInfo(this); final DatanodeStorageInfo s = b.findStorageInfo(this);
// if block exists on this datanode // if block exists on this datanode
if (s != null) { if (s != null) {
@ -348,12 +348,9 @@ boolean removeBlock(BlockInfoContiguous b) {
* Remove block from the list of blocks belonging to the data-node. Remove * Remove block from the list of blocks belonging to the data-node. Remove
* data-node from the block. * data-node from the block.
*/ */
boolean removeBlock(String storageID, BlockInfoContiguous b) { boolean removeBlock(String storageID, BlockInfo b) {
DatanodeStorageInfo s = getStorageInfo(storageID); DatanodeStorageInfo s = getStorageInfo(storageID);
if (s != null) { return s != null && s.removeBlock(b);
return s.removeBlock(b);
}
return false;
} }
public void resetBlocks() { public void resetBlocks() {
@ -537,12 +534,12 @@ private void updateFailedStorage(
} }
} }
private static class BlockIterator implements Iterator<BlockInfoContiguous> { private static class BlockIterator implements Iterator<BlockInfo> {
private int index = 0; private int index = 0;
private final List<Iterator<BlockInfoContiguous>> iterators; private final List<Iterator<BlockInfo>> iterators;
private BlockIterator(final DatanodeStorageInfo... storages) { private BlockIterator(final DatanodeStorageInfo... storages) {
List<Iterator<BlockInfoContiguous>> iterators = new ArrayList<Iterator<BlockInfoContiguous>>(); List<Iterator<BlockInfo>> iterators = new ArrayList<>();
for (DatanodeStorageInfo e : storages) { for (DatanodeStorageInfo e : storages) {
iterators.add(e.getBlockIterator()); iterators.add(e.getBlockIterator());
} }
@ -556,7 +553,7 @@ public boolean hasNext() {
} }
@Override @Override
public BlockInfoContiguous next() { public BlockInfo next() {
update(); update();
return iterators.get(index).next(); return iterators.get(index).next();
} }
@ -573,10 +570,11 @@ private void update() {
} }
} }
Iterator<BlockInfoContiguous> getBlockIterator() { Iterator<BlockInfo> getBlockIterator() {
return new BlockIterator(getStorageInfos()); return new BlockIterator(getStorageInfos());
} }
Iterator<BlockInfoContiguous> getBlockIterator(final String storageID) {
Iterator<BlockInfo> getBlockIterator(final String storageID) {
return new BlockIterator(getStorageInfo(storageID)); return new BlockIterator(getStorageInfo(storageID));
} }

View File

@ -24,6 +24,7 @@
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.fs.StorageType; import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
import org.apache.hadoop.hdfs.protocol.DatanodeInfoWithStorage; import org.apache.hadoop.hdfs.protocol.DatanodeInfoWithStorage;
import org.apache.hadoop.hdfs.protocol.ExtendedBlock; import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
@ -83,10 +84,10 @@ public void updateFromStorage(DatanodeStorage storage) {
/** /**
* Iterates over the list of blocks belonging to the data-node. * Iterates over the list of blocks belonging to the data-node.
*/ */
class BlockIterator implements Iterator<BlockInfoContiguous> { class BlockIterator implements Iterator<BlockInfo> {
private BlockInfoContiguous current; private BlockInfo current;
BlockIterator(BlockInfoContiguous head) { BlockIterator(BlockInfo head) {
this.current = head; this.current = head;
} }
@ -94,8 +95,8 @@ public boolean hasNext() {
return current != null; return current != null;
} }
public BlockInfoContiguous next() { public BlockInfo next() {
BlockInfoContiguous res = current; BlockInfo res = current;
current = current.getNext(current.findStorageInfo(DatanodeStorageInfo.this)); current = current.getNext(current.findStorageInfo(DatanodeStorageInfo.this));
return res; return res;
} }
@ -115,7 +116,7 @@ public void remove() {
private volatile long remaining; private volatile long remaining;
private long blockPoolUsed; private long blockPoolUsed;
private volatile BlockInfoContiguous blockList = null; private volatile BlockInfo blockList = null;
private int numBlocks = 0; private int numBlocks = 0;
// The ID of the last full block report which updated this storage. // The ID of the last full block report which updated this storage.
@ -229,7 +230,7 @@ long getBlockPoolUsed() {
return blockPoolUsed; return blockPoolUsed;
} }
public AddBlockResult addBlock(BlockInfoContiguous b) { public AddBlockResult addBlock(BlockInfo b, Block reportedBlock) {
// First check whether the block belongs to a different storage // First check whether the block belongs to a different storage
// on the same DN. // on the same DN.
AddBlockResult result = AddBlockResult.ADDED; AddBlockResult result = AddBlockResult.ADDED;
@ -248,13 +249,21 @@ public AddBlockResult addBlock(BlockInfoContiguous b) {
} }
// add to the head of the data-node list // add to the head of the data-node list
b.addStorage(this); b.addStorage(this, reportedBlock);
blockList = b.listInsert(blockList, this); insertToList(b);
numBlocks++;
return result; return result;
} }
public boolean removeBlock(BlockInfoContiguous b) { AddBlockResult addBlock(BlockInfoContiguous b) {
return addBlock(b, b);
}
public void insertToList(BlockInfo b) {
blockList = b.listInsert(blockList, this);
numBlocks++;
}
public boolean removeBlock(BlockInfo b) {
blockList = b.listRemove(blockList, this); blockList = b.listRemove(blockList, this);
if (b.removeStorage(this)) { if (b.removeStorage(this)) {
numBlocks--; numBlocks--;
@ -268,16 +277,15 @@ int numBlocks() {
return numBlocks; return numBlocks;
} }
Iterator<BlockInfoContiguous> getBlockIterator() { Iterator<BlockInfo> getBlockIterator() {
return new BlockIterator(blockList); return new BlockIterator(blockList);
} }
/** /**
* Move block to the head of the list of blocks belonging to the data-node. * Move block to the head of the list of blocks belonging to the data-node.
* @return the index of the head of the blockList * @return the index of the head of the blockList
*/ */
int moveBlockToHead(BlockInfoContiguous b, int curIndex, int headIndex) { int moveBlockToHead(BlockInfo b, int curIndex, int headIndex) {
blockList = b.moveBlockToHead(blockList, this, curIndex, headIndex); blockList = b.moveBlockToHead(blockList, this, curIndex, headIndex);
return curIndex; return curIndex;
} }
@ -287,7 +295,7 @@ int moveBlockToHead(BlockInfoContiguous b, int curIndex, int headIndex) {
* @return the head of the blockList * @return the head of the blockList
*/ */
@VisibleForTesting @VisibleForTesting
BlockInfoContiguous getBlockListHeadForTesting(){ BlockInfo getBlockListHeadForTesting(){
return blockList; return blockList;
} }
@ -374,6 +382,6 @@ static DatanodeStorageInfo getDatanodeStorageInfo(
} }
static enum AddBlockResult { static enum AddBlockResult {
ADDED, REPLACED, ALREADY_EXIST; ADDED, REPLACED, ALREADY_EXIST
} }
} }

View File

@ -0,0 +1,119 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.blockmanagement;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
/**
* ReplicaUnderConstruction contains information about replicas (or blocks
* belonging to a block group) while they are under construction.
*
* The GS, the length and the state of the replica is as reported by the
* datanode.
*
* It is not guaranteed, but expected, that datanodes actually have
* corresponding replicas.
*/
class ReplicaUnderConstruction extends Block {
private final DatanodeStorageInfo expectedLocation;
private HdfsServerConstants.ReplicaState state;
private boolean chosenAsPrimary;
ReplicaUnderConstruction(Block block,
DatanodeStorageInfo target,
HdfsServerConstants.ReplicaState state) {
super(block);
this.expectedLocation = target;
this.state = state;
this.chosenAsPrimary = false;
}
/**
* Expected block replica location as assigned when the block was allocated.
* This defines the pipeline order.
* It is not guaranteed, but expected, that the data-node actually has
* the replica.
*/
DatanodeStorageInfo getExpectedStorageLocation() {
return expectedLocation;
}
/**
* Get replica state as reported by the data-node.
*/
HdfsServerConstants.ReplicaState getState() {
return state;
}
/**
* Whether the replica was chosen for recovery.
*/
boolean getChosenAsPrimary() {
return chosenAsPrimary;
}
/**
* Set replica state.
*/
void setState(HdfsServerConstants.ReplicaState s) {
state = s;
}
/**
* Set whether this replica was chosen for recovery.
*/
void setChosenAsPrimary(boolean chosenAsPrimary) {
this.chosenAsPrimary = chosenAsPrimary;
}
/**
* Is data-node the replica belongs to alive.
*/
boolean isAlive() {
return expectedLocation.getDatanodeDescriptor().isAlive;
}
@Override // Block
public int hashCode() {
return super.hashCode();
}
@Override // Block
public boolean equals(Object obj) {
// Sufficient to rely on super's implementation
return (this == obj) || super.equals(obj);
}
@Override
public String toString() {
final StringBuilder b = new StringBuilder(50);
appendStringTo(b);
return b.toString();
}
@Override
public void appendStringTo(StringBuilder sb) {
sb.append("ReplicaUC[")
.append(expectedLocation)
.append("|")
.append(state)
.append("]");
}
}

View File

@ -3540,7 +3540,8 @@ boolean internalReleaseLease(Lease lease, String src, INodesInPath iip,
throw new AlreadyBeingCreatedException(message); throw new AlreadyBeingCreatedException(message);
case UNDER_CONSTRUCTION: case UNDER_CONSTRUCTION:
case UNDER_RECOVERY: case UNDER_RECOVERY:
final BlockInfoContiguousUnderConstruction uc = (BlockInfoContiguousUnderConstruction)lastBlock; final BlockInfoContiguousUnderConstruction uc =
(BlockInfoContiguousUnderConstruction)lastBlock;
// determine if last block was intended to be truncated // determine if last block was intended to be truncated
Block recoveryBlock = uc.getTruncateBlock(); Block recoveryBlock = uc.getTruncateBlock();
boolean truncateRecovery = recoveryBlock != null; boolean truncateRecovery = recoveryBlock != null;
@ -3650,9 +3651,8 @@ void finalizeINodeFileUnderConstruction(
blockManager.checkReplication(pendingFile); blockManager.checkReplication(pendingFile);
} }
@VisibleForTesting public BlockInfoContiguous getStoredBlock(Block block) {
BlockInfoContiguous getStoredBlock(Block block) { return (BlockInfoContiguous) blockManager.getStoredBlock(block);
return blockManager.getStoredBlock(block);
} }
@Override @Override
@ -3811,9 +3811,9 @@ void commitBlockSynchronization(ExtendedBlock oldBlock,
trimmedTargets.get(i).getStorageInfo(trimmedStorages.get(i)); trimmedTargets.get(i).getStorageInfo(trimmedStorages.get(i));
if (storageInfo != null) { if (storageInfo != null) {
if(copyTruncate) { if(copyTruncate) {
storageInfo.addBlock(truncatedBlock); storageInfo.addBlock(truncatedBlock, truncatedBlock);
} else { } else {
storageInfo.addBlock(storedBlock); storageInfo.addBlock(storedBlock, storedBlock);
} }
} }
} }
@ -4163,9 +4163,8 @@ private void clearCorruptLazyPersistFiles()
while (it.hasNext()) { while (it.hasNext()) {
Block b = it.next(); Block b = it.next();
BlockInfoContiguous blockInfo = blockManager.getStoredBlock(b); BlockInfoContiguous blockInfo = getStoredBlock(b);
if (blockInfo.getBlockCollection().getStoragePolicyID() if (blockInfo.getBlockCollection().getStoragePolicyID() == lpPolicy.getId()) {
== lpPolicy.getId()) {
filesToDelete.add(blockInfo.getBlockCollection()); filesToDelete.add(blockInfo.getBlockCollection());
} }
} }

View File

@ -243,7 +243,8 @@ public void blockIdCK(String blockId) {
//get blockInfo //get blockInfo
Block block = new Block(Block.getBlockId(blockId)); Block block = new Block(Block.getBlockId(blockId));
//find which file this block belongs to //find which file this block belongs to
BlockInfoContiguous blockInfo = bm.getStoredBlock(block); BlockInfoContiguous blockInfo = namenode.getNamesystem()
.getStoredBlock(block);
if(blockInfo == null) { if(blockInfo == null) {
out.println("Block "+ blockId +" " + NONEXISTENT_STATUS); out.println("Block "+ blockId +" " + NONEXISTENT_STATUS);
LOG.warn("Block "+ blockId + " " + NONEXISTENT_STATUS); LOG.warn("Block "+ blockId + " " + NONEXISTENT_STATUS);

View File

@ -239,10 +239,12 @@ private void loadFileDiffList(InputStream in, INodeFile file, int size)
FileDiff diff = new FileDiff(pbf.getSnapshotId(), copy, null, FileDiff diff = new FileDiff(pbf.getSnapshotId(), copy, null,
pbf.getFileSize()); pbf.getFileSize());
List<BlockProto> bpl = pbf.getBlocksList(); List<BlockProto> bpl = pbf.getBlocksList();
// TODO: also persist striped blocks
BlockInfoContiguous[] blocks = new BlockInfoContiguous[bpl.size()]; BlockInfoContiguous[] blocks = new BlockInfoContiguous[bpl.size()];
for(int j = 0, e = bpl.size(); j < e; ++j) { for(int j = 0, e = bpl.size(); j < e; ++j) {
Block blk = PBHelper.convert(bpl.get(j)); Block blk = PBHelper.convert(bpl.get(j));
BlockInfoContiguous storedBlock = fsn.getBlockManager().getStoredBlock(blk); BlockInfoContiguous storedBlock =
(BlockInfoContiguous) fsn.getBlockManager().getStoredBlock(blk);
if(storedBlock == null) { if(storedBlock == null) {
storedBlock = fsn.getBlockManager().addBlockCollection( storedBlock = fsn.getBlockManager().addBlockCollection(
new BlockInfoContiguous(blk, copy.getFileReplication()), file); new BlockInfoContiguous(blk, copy.getFileReplication()), file);

View File

@ -1608,8 +1608,8 @@ public static void createKey(String keyName, MiniDFSCluster cluster,
*/ */
public static DatanodeDescriptor getExpectedPrimaryNode(NameNode nn, public static DatanodeDescriptor getExpectedPrimaryNode(NameNode nn,
ExtendedBlock blk) { ExtendedBlock blk) {
BlockManager bm0 = nn.getNamesystem().getBlockManager(); FSNamesystem fsn = nn.getNamesystem();
BlockInfoContiguous storedBlock = bm0.getStoredBlock(blk.getLocalBlock()); BlockInfoContiguous storedBlock = fsn.getStoredBlock(blk.getLocalBlock());
assertTrue("Block " + blk + " should be under construction, " + assertTrue("Block " + blk + " should be under construction, " +
"got: " + storedBlock, "got: " + storedBlock,
storedBlock instanceof BlockInfoContiguousUnderConstruction); storedBlock instanceof BlockInfoContiguousUnderConstruction);

View File

@ -63,7 +63,7 @@ public void testAddStorage() throws Exception {
final DatanodeStorageInfo storage = DFSTestUtil.createDatanodeStorageInfo("storageID", "127.0.0.1"); final DatanodeStorageInfo storage = DFSTestUtil.createDatanodeStorageInfo("storageID", "127.0.0.1");
boolean added = blockInfo.addStorage(storage); boolean added = blockInfo.addStorage(storage, blockInfo);
Assert.assertTrue(added); Assert.assertTrue(added);
Assert.assertEquals(storage, blockInfo.getStorageInfo(0)); Assert.assertEquals(storage, blockInfo.getStorageInfo(0));
@ -129,7 +129,7 @@ public void testBlockListMoveToHead() throws Exception {
// list length should be equal to the number of blocks we inserted // list length should be equal to the number of blocks we inserted
LOG.info("Checking list length..."); LOG.info("Checking list length...");
assertEquals("Length should be MAX_BLOCK", MAX_BLOCKS, dd.numBlocks()); assertEquals("Length should be MAX_BLOCK", MAX_BLOCKS, dd.numBlocks());
Iterator<BlockInfoContiguous> it = dd.getBlockIterator(); Iterator<BlockInfo> it = dd.getBlockIterator();
int len = 0; int len = 0;
while (it.hasNext()) { while (it.hasNext()) {
it.next(); it.next();
@ -151,7 +151,7 @@ public void testBlockListMoveToHead() throws Exception {
// move head of the list to the head - this should not change the list // move head of the list to the head - this should not change the list
LOG.info("Moving head to the head..."); LOG.info("Moving head to the head...");
BlockInfoContiguous temp = dd.getBlockListHeadForTesting(); BlockInfo temp = dd.getBlockListHeadForTesting();
curIndex = 0; curIndex = 0;
headIndex = 0; headIndex = 0;
dd.moveBlockToHead(temp, curIndex, headIndex); dd.moveBlockToHead(temp, curIndex, headIndex);

View File

@ -0,0 +1,219 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.blockmanagement;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.protocol.Block;
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo.AddBlockResult;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.internal.util.reflection.Whitebox;
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.NUM_DATA_BLOCKS;
import static org.apache.hadoop.hdfs.protocol.HdfsConstants.NUM_PARITY_BLOCKS;
/**
* Test {@link BlockInfoStriped}
*/
public class TestBlockInfoStriped {
private static final int TOTAL_NUM_BLOCKS = NUM_DATA_BLOCKS + NUM_PARITY_BLOCKS;
private static final long BASE_ID = -1600;
private static final Block baseBlock = new Block(BASE_ID);
private BlockInfoStriped info;
@Before
public void setup() {
info = new BlockInfoStriped(baseBlock, NUM_DATA_BLOCKS, NUM_PARITY_BLOCKS);
}
private Block[] createReportedBlocks(int num) {
Block[] blocks = new Block[num];
for (int i = 0; i < num; i++) {
blocks[i] = new Block(BASE_ID + i);
}
return blocks;
}
/**
* Test adding storage and reported block
*/
@Test
public void testAddStorage() {
// first add NUM_DATA_BLOCKS + NUM_PARITY_BLOCKS storages, i.e., a complete
// group of blocks/storages
DatanodeStorageInfo[] storageInfos = DFSTestUtil.createDatanodeStorageInfos(
TOTAL_NUM_BLOCKS);
Block[] blocks = createReportedBlocks(TOTAL_NUM_BLOCKS);
int i = 0;
for (; i < storageInfos.length; i += 2) {
info.addStorage(storageInfos[i], blocks[i]);
Assert.assertEquals(i/2 + 1, info.numNodes());
}
i /= 2;
for (int j = 1; j < storageInfos.length; j += 2) {
Assert.assertTrue(info.addStorage(storageInfos[j], blocks[j]));
Assert.assertEquals(i + (j+1)/2, info.numNodes());
}
// check
byte[] indices = (byte[]) Whitebox.getInternalState(info, "indices");
Assert.assertEquals(TOTAL_NUM_BLOCKS, info.getCapacity());
Assert.assertEquals(TOTAL_NUM_BLOCKS, indices.length);
i = 0;
for (DatanodeStorageInfo storage : storageInfos) {
int index = info.findStorageInfo(storage);
Assert.assertEquals(i++, index);
Assert.assertEquals(index, indices[index]);
}
// the same block is reported from the same storage twice
i = 0;
for (DatanodeStorageInfo storage : storageInfos) {
Assert.assertTrue(info.addStorage(storage, blocks[i++]));
}
Assert.assertEquals(TOTAL_NUM_BLOCKS, info.getCapacity());
Assert.assertEquals(TOTAL_NUM_BLOCKS, info.numNodes());
Assert.assertEquals(TOTAL_NUM_BLOCKS, indices.length);
i = 0;
for (DatanodeStorageInfo storage : storageInfos) {
int index = info.findStorageInfo(storage);
Assert.assertEquals(i++, index);
Assert.assertEquals(index, indices[index]);
}
// the same block is reported from another storage
DatanodeStorageInfo[] storageInfos2 = DFSTestUtil.createDatanodeStorageInfos(
TOTAL_NUM_BLOCKS * 2);
// only add the second half of info2
for (i = TOTAL_NUM_BLOCKS; i < storageInfos2.length; i++) {
info.addStorage(storageInfos2[i], blocks[i % TOTAL_NUM_BLOCKS]);
Assert.assertEquals(i + 1, info.getCapacity());
Assert.assertEquals(i + 1, info.numNodes());
indices = (byte[]) Whitebox.getInternalState(info, "indices");
Assert.assertEquals(i + 1, indices.length);
}
for (i = TOTAL_NUM_BLOCKS; i < storageInfos2.length; i++) {
int index = info.findStorageInfo(storageInfos2[i]);
Assert.assertEquals(i++, index);
Assert.assertEquals(index - TOTAL_NUM_BLOCKS, indices[index]);
}
}
@Test
public void testRemoveStorage() {
// first add TOTAL_NUM_BLOCKS into the BlockInfoStriped
DatanodeStorageInfo[] storages = DFSTestUtil.createDatanodeStorageInfos(
TOTAL_NUM_BLOCKS);
Block[] blocks = createReportedBlocks(TOTAL_NUM_BLOCKS);
for (int i = 0; i < storages.length; i++) {
info.addStorage(storages[i], blocks[i]);
}
// remove two storages
info.removeStorage(storages[0]);
info.removeStorage(storages[2]);
// check
Assert.assertEquals(TOTAL_NUM_BLOCKS, info.getCapacity());
Assert.assertEquals(TOTAL_NUM_BLOCKS - 2, info.numNodes());
byte[] indices = (byte[]) Whitebox.getInternalState(info, "indices");
for (int i = 0; i < storages.length; i++) {
int index = info.findStorageInfo(storages[i]);
if (i != 0 && i != 2) {
Assert.assertEquals(i, index);
Assert.assertEquals(index, indices[index]);
} else {
Assert.assertEquals(-1, index);
Assert.assertEquals(-1, indices[i]);
}
}
// the same block is reported from another storage
DatanodeStorageInfo[] storages2 = DFSTestUtil.createDatanodeStorageInfos(
TOTAL_NUM_BLOCKS * 2);
for (int i = TOTAL_NUM_BLOCKS; i < storages2.length; i++) {
info.addStorage(storages2[i], blocks[i % TOTAL_NUM_BLOCKS]);
}
// now we should have 8 storages
Assert.assertEquals(TOTAL_NUM_BLOCKS * 2 - 2, info.numNodes());
Assert.assertEquals(TOTAL_NUM_BLOCKS * 2 - 2, info.getCapacity());
indices = (byte[]) Whitebox.getInternalState(info, "indices");
Assert.assertEquals(TOTAL_NUM_BLOCKS * 2 - 2, indices.length);
int j = TOTAL_NUM_BLOCKS;
for (int i = TOTAL_NUM_BLOCKS; i < storages2.length; i++) {
int index = info.findStorageInfo(storages2[i]);
if (i == TOTAL_NUM_BLOCKS || i == TOTAL_NUM_BLOCKS + 2) {
Assert.assertEquals(i - TOTAL_NUM_BLOCKS, index);
} else {
Assert.assertEquals(j++, index);
}
}
// remove the storages from storages2
for (int i = 0; i < TOTAL_NUM_BLOCKS; i++) {
info.removeStorage(storages2[i + TOTAL_NUM_BLOCKS]);
}
// now we should have 3 storages
Assert.assertEquals(TOTAL_NUM_BLOCKS - 2, info.numNodes());
Assert.assertEquals(TOTAL_NUM_BLOCKS * 2 - 2, info.getCapacity());
indices = (byte[]) Whitebox.getInternalState(info, "indices");
Assert.assertEquals(TOTAL_NUM_BLOCKS * 2 - 2, indices.length);
for (int i = 0; i < TOTAL_NUM_BLOCKS; i++) {
if (i == 0 || i == 2) {
int index = info.findStorageInfo(storages2[i + TOTAL_NUM_BLOCKS]);
Assert.assertEquals(-1, index);
} else {
int index = info.findStorageInfo(storages[i]);
Assert.assertEquals(i, index);
}
}
for (int i = TOTAL_NUM_BLOCKS; i < TOTAL_NUM_BLOCKS * 2 - 2; i++) {
Assert.assertEquals(-1, indices[i]);
Assert.assertNull(info.getDatanode(i));
}
}
@Test
public void testReplaceBlock() {
DatanodeStorageInfo[] storages = DFSTestUtil.createDatanodeStorageInfos(
TOTAL_NUM_BLOCKS);
Block[] blocks = createReportedBlocks(TOTAL_NUM_BLOCKS);
// add block/storage 0, 2, 4 into the BlockInfoStriped
for (int i = 0; i < storages.length; i += 2) {
Assert.assertEquals(AddBlockResult.ADDED,
storages[i].addBlock(info, blocks[i]));
}
BlockInfoStriped newBlockInfo = new BlockInfoStriped(info);
info.replaceBlock(newBlockInfo);
// make sure the newBlockInfo is correct
byte[] indices = (byte[]) Whitebox.getInternalState(newBlockInfo, "indices");
for (int i = 0; i < storages.length; i += 2) {
int index = newBlockInfo.findStorageInfo(storages[i]);
Assert.assertEquals(i, index);
Assert.assertEquals(index, indices[i]);
// make sure the newBlockInfo is added to the linked list of the storage
Assert.assertSame(newBlockInfo, storages[i].getBlockListHeadForTesting());
Assert.assertEquals(1, storages[i].numBlocks());
Assert.assertNull(newBlockInfo.getNext());
}
}
}

View File

@ -383,7 +383,7 @@ private void fulfillPipeline(BlockInfoContiguous blockInfo,
for (int i = 1; i < pipeline.length; i++) { for (int i = 1; i < pipeline.length; i++) {
DatanodeStorageInfo storage = pipeline[i]; DatanodeStorageInfo storage = pipeline[i];
bm.addBlock(storage, blockInfo, null); bm.addBlock(storage, blockInfo, null);
blockInfo.addStorage(storage); blockInfo.addStorage(storage, blockInfo);
} }
} }
@ -393,7 +393,7 @@ private BlockInfoContiguous blockOnNodes(long blkId, List<DatanodeDescriptor> no
for (DatanodeDescriptor dn : nodes) { for (DatanodeDescriptor dn : nodes) {
for (DatanodeStorageInfo storage : dn.getStorageInfos()) { for (DatanodeStorageInfo storage : dn.getStorageInfos()) {
blockInfo.addStorage(storage); blockInfo.addStorage(storage, blockInfo);
} }
} }
return blockInfo; return blockInfo;

View File

@ -1244,7 +1244,7 @@ public void testAddStoredBlockDoesNotCauseSkippedReplication()
when(storage.removeBlock(any(BlockInfoContiguous.class))).thenReturn(true); when(storage.removeBlock(any(BlockInfoContiguous.class))).thenReturn(true);
when(storage.addBlock(any(BlockInfoContiguous.class))).thenReturn when(storage.addBlock(any(BlockInfoContiguous.class))).thenReturn
(DatanodeStorageInfo.AddBlockResult.ADDED); (DatanodeStorageInfo.AddBlockResult.ADDED);
ucBlock.addStorage(storage); ucBlock.addStorage(storage, ucBlock);
when(mbc.setLastBlock((BlockInfoContiguous) any(), (DatanodeStorageInfo[]) any())) when(mbc.setLastBlock((BlockInfoContiguous) any(), (DatanodeStorageInfo[]) any()))
.thenReturn(ucBlock); .thenReturn(ucBlock);