HDFS之blockreport更新操作解释

0.1版

---

在datanode的函数

  public void offerService() throws Exception {中,

有这么一段函数

if (now - lastBlockReport > blockReportInterval) {

                    //

                    // Send latest blockinfo report if timer has expired.

                    // Get back a list of local block(s) that are obsolete

                    // and can be safely GC'ed.

                    //

                    Block toDelete[] = namenode.blockReport(localNamedata.getBlockReport());

                    data.invalidate(toDelete);

                    lastBlockReport = now;

                    continue;

                }

也就是把本地的block全部发送到namenode,然后namenode返回失效的block,然后datanode再在本地将失效的block直接物理删除。

---下面就来看看namenode收到blockReport后究竟做了什么?

public Block[] blockReport(String sender, Block blocks[]) {

        LOG.info("Block report from "+sender+": "+blocks.length+" blocks.");

        return namesystem.processReport(blocks, new UTF8(sender));

    }

可见namenode直接调用了本地的 namesystem.processReport(blocks, new UTF8(sender));

所以我们就来分析namesystem.processReport(...) 函数。

---

 

 

 

public synchronized Block[] processReport(Block newReport[], UTF8 name) {

        DatanodeInfo node = (DatanodeInfo) datanodeMap.get(name);//从映射表中根据名字找到对应的节点信息

        if (node == null) {//找不到就报错

            throw new IllegalArgumentException("Unexpected exception.  Received block report from node " + name + ", but there is no info for " + name);

        }

 

        //

        // Modify the (block-->datanode) map, according to the difference

        // between the old and new block report.

        //

        int oldPos = 0, newPos = 0;//因为要对两个新旧数组开始遍历,可以理解为遍历我们以前在数据结构里学的有序链表:)

        要强调一点的就是Block对象本身实现了compare函数。所以产生的数组才是有序的。下面的代码才可以这么写。

        Block oldReport[] = node.getBlocks();

        while (oldReport != null && newReport != null && oldPos < oldReport.length && newPos < newReport.length) {

            int cmp = oldReport[oldPos].compareTo(newReport[newPos]);//开始比较二者的blkid

            

            if (cmp == 0) {//如果二者的ID一致,则说明二者是一样的一个block文件块,2个指示器都需要自增1

                // Do nothing, blocks are the same

                oldPos++;//不解释

                newPos++;//不解释

            } else if (cmp < 0) {//表明,老的有有一块新的没有,则老的这一块应该被删除,已经失效了。

                // The old report has a block the new one does not

                removeStoredBlock(oldReport[oldPos], node);//未完待续

                oldPos++;

            } else {//表明有一个新的块,则需要在本地namenode更新。

                // The new report has a block the old one does not

                addStoredBlock(newReport[newPos], node);//未完待续

                newPos++;

            }

        }

        while (oldReport != null && oldPos < oldReport.length) {//如果老的还有更多,则都是过时的。

            // The old report has a block the new one does not

            removeStoredBlock(oldReport[oldPos], node);

            oldPos++;

        }

        while (newReport != null && newPos < newReport.length) {//如果还有新的,则都需要新增到本地。

            // The new report has a block the old one does not

            addStoredBlock(newReport[newPos], node);

            newPos++;

        }

 

        //

        // Modify node so it has the new blockreport

        //

        node.updateBlocks(newReport); //依据最新的block来更新本地DataNode的信息。

 

        //

        // We've now completely updated the node's block report profile.

        // We now go through all its blocks and find which ones are invalid,

        // no longer pending, or over-replicated.

        //

        // (Note it's not enough to just invalidate blocks at lease expiry 

        // time; datanodes can go down before the client's lease on 

        // the failed file expires and miss the "expire" event.)

        //

        // This function considers every block on a datanode, and thus

        // should only be invoked infrequently.

        //

        Vector obsolete = new Vector();

        for (Iterator it = node.getBlockIterator(); it.hasNext(); ) {

            Block b = (Block) it.next();

 

            if (! dir.isValidBlock(b) && ! pendingCreateBlocks.contains(b)) {

                LOG.info("Obsoleting block " + b);

                obsolete.add(b);

            }

        }

        return (Block[]) obsolete.toArray(new Block[obsolete.size()]);

    }

 

上面有几个函数没有解释,先解释

synchronized void removeStoredBlock(Block block, DatanodeInfo node) {

源码如下:

 

 synchronized void removeStoredBlock(Block block, DatanodeInfo node) {

        TreeSet containingNodes = (TreeSet) blocksMap.get(block);//找到对应的节点集合

        if (containingNodes == null || ! containingNodes.contains(node)) {

            throw new IllegalArgumentException("No machine mapping found for block " + block + ", which should be at node " + node);

        }

        containingNodes.remove(node);//需要的话,删除这个节点

 

        //

        // It's possible that the block was removed because of a datanode

        // failure.  If the block is still valid, check if replication is

        // necessary.  In that case, put block on a possibly-will-

        // be-replicated list.

        //

        if (dir.isValidBlock(block) && (containingNodes.size() < this.desiredReplication)) {

            synchronized (neededReplications) {

                neededReplications.add(block);//如果备份数低于阀值,则需要进行复制任务。

            }

        }

 

        //

        // We've removed a block from a node, so it's definitely no longer

        // in "excess" there.

        //

        TreeSet excessBlocks = (TreeSet) excessReplicateMap.get(node.getName());//excessReplicateMap是记录某个节点的块冗余了。

        if (excessBlocks != null) {

            excessBlocks.remove(block);//删除这个节点的这个快

            if (excessBlocks.size() == 0) {//如果为0了,自然可以把这个节点从excessReplicateMap移除

                excessReplicateMap.remove(node.getName());

            }

        }

    }

接下来再分析 synchronized void addStoredBlock(Block block, DatanodeInfo node) {

 synchronized void addStoredBlock(Block block, DatanodeInfo node) {

        TreeSet containingNodes = (TreeSet) blocksMap.get(block);

        if (containingNodes == null) {

            containingNodes = new TreeSet();

            blocksMap.put(block, containingNodes);

        }

        if (! containingNodes.contains(node)) {

            containingNodes.add(node);

        } else {

            LOG.info("Redundant addStoredBlock request received for block " + block + " on node " + node);

        }//上面的代码主要是用来更新blocksMap这个数据结构

 

        synchronized (neededReplications) {

            if (dir.isValidBlock(block)) {

                if (containingNodes.size() >= this.desiredReplication) {

                    neededReplications.remove(block);//如果已经达到了阀值了,则不需要再复制了

                    pendingReplications.remove(block);//正在复制的也不需要了

                } else if (containingNodes.size() < this.desiredReplication) {

                    if (! neededReplications.contains(block)) {

                        neededReplications.add(block);//如果不够阀值,则需要进行备份复制。

                    }

                }

 

                //

                // Find how many of the containing nodes are "extra", if any.

                // If there are any extras, call chooseExcessReplicates() to

                // mark them in the excessReplicateMap.

                //

                Vector nonExcess = new Vector();

                for (Iterator it = containingNodes.iterator(); it.hasNext(); ) {

                    DatanodeInfo cur = (DatanodeInfo) it.next();

                    TreeSet excessBlocks = (TreeSet) excessReplicateMap.get(cur.getName());

                    if (excessBlocks == null || ! excessBlocks.contains(block)) {

                        nonExcess.add(cur);

                    }

                }

                if (nonExcess.size() > this.maxReplication) {

                    chooseExcessReplicates(nonExcess, block, this.maxReplication);    

                }

            }

        }

    }

 

 想了一会,其实没必要完全理解这段代码,自己写也是没问题的,每个人都有自己的逻辑思维,相信自己的实力。

好歹咱也看过不少源码了,就那么回事吧。

转载于:https://my.oschina.net/qiangzigege/blog/464427

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值