DatanodeDescriptor类记录了Datanode的使用情况,如capacity,used等统计信息,DatanodeDescriptor是Namenode内部的数据结构,并不是通过RPC通信从Datanode向Namenode通信时候使用。Namenode从DatanodeDescriptor中读取Datanode统计信息,并显示在jsp页面上,这就是在网页上面显示的统计信息的来源。 public class DatanodeDescriptor extends DatanodeInfo 首先来看一下DatanodeInfo 1. public class DatanodeInfo extends DatanodeID implements Node 1) 看一下DatanodeID类 public String name; public String storageID; protected int infoPort; public int ipcPort; 有如上四个变量,name表示了名称,storageID是ID号唯一,infoPort是infoServer运行的端口,ipcPort是ipc运行的端口,剩下的就是getter和setter方法。 2) DatanodeInfo中的变量有 protected long capacity; protected long dfsUsed; protected long remaining; protected long lastUpdate; protected int xceiverCount; protected String hostName = null; 这些变量是Datanode统计信息,要通过RPC通信在Namenode启动时将这些状态传递从Datanode传递给Namenode,剩下的方法也比较简单,基本上是getter和setter public String getDatanodeReport() 方法,按照一定的格式输出Datanode统计信息。 同时,DatanodeInfo类中还有一个Node parent变量,这个变量是为了计算拓扑结构使用。 2. 解决了DatanodeInfo继续看DatanodeDescriptor,下面一个结构为BlockTargetPair BlockTargetPair维护了一个Block和DatanodeDescriptor数组变量。为下面的变量提供了数据结构。 3. private static class BlockQueue 变量有 1) private final Queue<BlockTargetPair> blockq = new LinkedList<BlockTargetPair>(); 2) synchronized boolean offer(Block block, DatanodeDescriptor[] targets) 入链表 3) synchronized List<BlockTargetPair> poll(int numBlocks) 出链表 4. private volatile BlockInfo blockList = null; DatanodeDescriptor中维护了一个BlockInfo对象,是该Datanode对应的block的头结点,通过头结点可以遍历该Datanode上面的所有block。可以配合blocksMap理解这个结构。 5. 下面是三个重要变量 /** A queue of blocks to be replicated by this datanode */ private BlockQueue replicateBlocks = new BlockQueue(); /** A queue of blocks to be recovered by this datanode */ private BlockQueue recoverBlocks = new BlockQueue(); /** A set of blocks to be invalidated by this datanode */ private Set<Block> invalidateBlocks = new TreeSet<Block>(); 这三个变量分别代表了需要复制的 block链表,需要recovery的block链表,以及无效的block表。 6. boolean addBlock(BlockInfo b) 向该Datanode添加block,具体方法是: blockList = b.listInsert(blockList, this); 其中参数中的blockList是头结点,返回值是新的头结点,指向的是新添加的block对应的BlockInfo变量。 7. boolean removeBlock(BlockInfo b) 向该Datanode删除block,具体方法是: blockList = b.listRemove(blockList, this); 从blockMap链表结构中删除该block,返回头结点,blockList仍然维护的是一个头结点。 8. void moveBlockToHead(BlockInfo b) 将某个BlockInfo对应的对象放在blocksMap结构的头结点,方法是先删除,在插入。 blockList = b.listRemove(blockList, this); blockList = b.listInsert(blockList, this); 9. public int numBlocks() 根据头结点遍历所有block,获得该datanode上面所有block数量。 10. static private class BlockIterator implements Iterator<Block> 迭代器模式。 11. void addBlockToBeReplicated(Block block, DatanodeDescriptor[] targets) void addBlockToBeRecovered(Block block, DatanodeDescriptor[] targets) void addBlocksToBeInvalidated(List<Block> blocklist) 往相应的结构里面放,见5。 12. BlockCommand getReplicationCommand(int maxTransfers) BlockCommand getLeaseRecoveryCommand(int maxTransfers) BlockCommand getInvalidateBlocks(int maxblocks) 这些函数是要通过RPC传递给Datanode,datanode根据传递的信息进行相应操作,放到后面再说。 13. void reportDiff(BlocksMap blocksMap, BlockListAsLongs newReport, Collection<Block> toAdd, Collection<Block> toRemove, Collection<Block> toInvalidate) 这是DatanodeDescriptor中最重要的一个方法,从Datanode心跳汇报得到的块信 信息经过分类后传递给DatanodeDescriptor,进行统计分类。在想Namenode反馈 需要添加,需要移除以及无效的块集合。newReport是从datanode中通过RPC获 得的块信息。