文档章节

HDFS的create函数解析及如何选择存储Block的DataNode

强子1985
 强子1985
发布于 2014/12/18 17:52
字数 1288
阅读 156
收藏 8

话说client通过exists()函数得知目前的namenode那边不存在此文件后,

则通过namenode.create函数创建一个文件。具体细节如下:

 这里意味着:clientMachine的clientName创建了src文件。

clientMachine只用来选择目标DataNode.

public LocatedBlock create(String src, String clientName, String clientMachine, boolean overwrite) throws IOException {

        Object results[] = namesystem.startFile(new UTF8(src), new UTF8(clientName), new UTF8(clientMachine), overwrite);//调用文件系统的startFile函数,返回值为block信息和目标datanode信息

        if (results == null) {

            throw new IOException("Cannot create file " + src + " on client " + clientName);

        } else {

            Block b = (Block) results[0];//取回block

            DatanodeInfo targets[] = (DatanodeInfo[]) results[1];//获取DatanodeInfo数组信息

            return new LocatedBlock(b, targets);//组合返回最终信息 

        }

    }

====================================

下面开始学习

public synchronized Object[] startFile(UTF8 src, UTF8 holder, UTF8 clientMachine, boolean overwrite) {

 对此函数的分析如下:

public synchronized Object[] startFile(UTF8 src, UTF8 holder, UTF8 clientMachine, boolean overwrite) {

//背景知识:参数有holderclientMachine.比如一个例子如下:

Holder:DFS_CLIENT_xxxx

clientMachine:Machine66.

也就是说一个clientMachine上面可以有多个Holder.

一个clientMachine上的Holder发出了一个上传的请求。

下面的代码中哪里用到了holder和哪里用到了clientMachine,

还请读者自己注意思考。

        Object results[] = null;

        if (pendingCreates.get(src) == null) {//说明pendingCreates记录了正在创建的文件

            boolean fileValid = dir.isValidToCreate(src);//文件路径也确实不存在,需要这一句吗?

            if (overwrite && ! fileValid) {//如果可以覆盖的话,目前都是不可以覆盖

                delete(src);

                fileValid = true;

            }

            if (fileValid) {//确实可以的话,继续执行

                results = new Object[2];//创建返回结果的数组

                // Get the array of replication targets 

                DatanodeInfo targets[] = chooseTargets(this.desiredReplicationnull, clientMachine);

//根据clientMachine和备份数目选择多个目标datanode

                if (targets.length < this.minReplication) {

                    LOG.warning("Target-length is " + targets.length +

                        ", below MIN_REPLICATION (" + this.minReplication")");

                    return null;

                }//如果长度达不到备份数,则返回失败

                // Reserve space for this pending file

                pendingCreates.put(src, new Vector());//表明这个文件正在create!!!

                synchronized (leases) {//开始处理租约系统

                    Lease lease = (Lease) leases.get(holder);//查找租约系统

                    if (lease == null) {//如果不存在

                        lease = new Lease(holder);//创建

                        leases.put(holder, lease);//存储到leases

                        sortedLeases.add(lease);//存储到sortedLeases

                    } else {//如果存在的话,则lease本身刷新时间且重新加入到sortedLeases.

//注意,这里有一个sort过程。

                        sortedLeases.remove(lease);

                        lease.renew();

                        sortedLeases.add(lease);

                    }

                    lease.startedCreate(src);//lease的本身creates保存了文件名

                }

                // Create next block

                results[0] = allocateBlock(src);//主要是记录文件对应的Block信息

                results[1] = targets;//分配的datanode信息

            } else { // ! fileValid

              LOG.warning("Cannot start file because it is invalid. src=" + src);

            }

        } else {

            LOG.warning("Cannot start file because pendingCreates is non-null. src=" + src);

        }

        return results;//返回结果!

    }

 -------------------------------------------------------------

 

DatanodeInfo[] chooseTargets(int desiredReplicates, TreeSet forbiddenNodes, UTF8 clientMachine) {

        TreeSet alreadyChosen = new TreeSet();//初始化空的已经选择的机器

        Vector targets = new Vector();//真的无语。这里为啥还要再创建一个targets,浪费内存,直接传到chooseTarget一样的好吧!崩溃!

        for (int i = 0; i < desiredReplicates; i++) {//根据备份数来选择执行次数

            DatanodeInfo target = chooseTarget(forbiddenNodes, alreadyChosen, clientMachine);//选择单个机器

            if (target != null) {//选择好了一个,就加到targetsalreadyChosen.崩溃,加2次有啥意思!!!

                targets.add(target);

                alreadyChosen.add(target);

            } else {

                break// calling chooseTarget again won't help

            }

        }

        return (DatanodeInfo[]) targets.toArray(new DatanodeInfo[targets.size()]);//返回执行的结果

    }

---------------

=======================

 

DatanodeInfo chooseTarget(TreeSet forbidden1, TreeSet forbidden2, UTF8 clientMachine) {

        //

        // Check if there are any available targets at all

        //

        int totalMachines = datanodeMap.size();//获取当前已知的所有数据节点个数

        if (totalMachines == 0) {//0就不用说了,返回null

            LOG.warning("While choosing target, totalMachines is " + totalMachines);

            return null;

        }

        //

        // Build a map of forbidden hostnames from the two forbidden sets.

        //

        TreeSet forbiddenMachines = new TreeSet();

        if (forbidden1 != null) {//这里forbidden1是初始化禁止的节点,此处为null

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

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

                forbiddenMachines.add(cur.getHost());

            }

        }

        if (forbidden2 != null) {//是已经选择的节点,因为已经选择的就不会再返回了,你懂的

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

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

                forbiddenMachines.add(cur.getHost());

            }

        }

        //

        // Build list of machines we can actually choose from

        //

        Vector targetList = new Vector();//从总的节点中去掉不可以选择的节点,得到剩下的可选的节点

        for (Iterator it = datanodeMap.values().iterator(); it.hasNext(); ) {

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

            if (! forbiddenMachines.contains(node.getHost())) {

                targetList.add(node);

            }

        }

        Collections.shuffle(targetList);//本来不知道干嘛的,百度了一下,用来洗牌的

       //为啥?因为DFSShell采用计算机组成原理的菊花链的方式来上传数据。剩下的我就不用解释了

        

        //

        // Now pick one

        //

        if (targetList.size() > 0) {//如果还剩下确实可以选择的节点,并且clientMachine也在里面

            //并且容量大于5块,就直接返回clientMachine.我猜是为了本地加速

            //毕竟上传到本地和上传到远程主机是不一样的。

            // If the requester's machine is in the targetList, 

            // and it's got the capacity, pick it.

            //

            if (clientMachine != null && clientMachine.getLength() > 0) {

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

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

                    if (clientMachine.equals(node.getHost())) {

                        if (node.getRemaining() > BLOCK_SIZE * MIN_BLOCKS_FOR_WRITE) {

                            return node;

                        }

                    }

                }

            }

            //

            // Otherwise, choose node according to target capacity

            //否则,就从中选择一个容量大于5块的节点

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

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

                if (node.getRemaining() > BLOCK_SIZE * MIN_BLOCKS_FOR_WRITE) {

                    return node;

                }

            }

            //

            // That should do the trick.  But we might not be able

            // to pick any node if the target was out of bytes.  As

            // a last resort, pick the first valid one we can find.

            //否则,就选择一个至少大于1块的节点

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

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

                if (node.getRemaining() > BLOCK_SIZE) {

                    return node;

                }

            }

            LOG.warning("Could not find any nodes with sufficient capacity");

            return null;//否则返回null

        } else {

            LOG.warning("Zero targets found, forbidden1.size=" +

                ( forbidden1 != null ? forbidden1.size() : 0 ) +

                " forbidden2.size()=" +

                ( forbidden2 != null ? forbidden2.size() : 0 ));

            return null;//一个可用来查找的节点都没有!

        }

    }

好,创建文件及选择Block的过程全部分析完毕! 

© 著作权归作者所有

共有 人打赏支持
强子1985

强子1985

粉丝 862
博文 940
码字总数 648235
作品 8
南京
架构师
HDFS的reportWrittenBlock函数解析

可先看下网友的解析:http://fire-balrog.iteye.com/blog/812281 以下为我的解析: 当一个Block经由所有的DataNode写完后,就需要告诉namenode可以执行reportWrittenBlock函数了。 下面就来解...

强子哥哥
2014/12/19
0
0
Hbase写入hdfs源码分析

版权声明:本文由熊训德原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/258 来源:腾云阁 https://www.qcloud.com/community 本文档从源码角度分析了,...

偶素浅小浅
2016/12/12
5
0
HDFS原理分析(一)—— 基本概念

HDFS是Hadoop Distribute File System 的简称,也就是Hadoop的一个分布式文件系统。 一、HDFS的主要设计理念 1、存储超大文件 这里的“超大文件”是指几百MB、GB甚至TB级别的文件。 2、最高效...

shiw019
2012/11/28
0
0
一文详解大规模数据计算处理原理及操作重点

作者介绍 李智慧,《大型网站技术架构:核心原理与案例分析》作者。曾供职于阿里巴巴与英特尔亚太研发中心,从事大型网站与大数据方面的研发工作,目前在做企业级区块链方面的开发工作。 大数...

DBAplus社群
08/07
0
0
Hadoop HDFS概念学习系列之初步掌握HDFS的架构及原理2(二)

HDFS 如何读取文件? HDFS的文件读取原理,主要包括以下几个步骤: 1、首先调用FileSystem对象的open方法,其实获取的是一个DistributedFileSystem的实例。 2、DistributedFileSystem通过RPC...

技术小哥哥
2017/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java Lock接口分析之ReentantReadWriteLock

ReentantReadWriteLock读写锁,在读线程多余写线程的并发环境中能体现出优异的性能,相比于synchronized与ReentrantLock这种独占式锁的模型,ReentantReadWriteLock采用独占式写锁与共享式读...

我爱春天的毛毛雨
12分钟前
0
0
EFK (Fluentd ElasticSearch Kibana) 采集nginx日志

本文描述如何通过FEK组合集中化nginx的访问日志。本人更喜欢按顺序来命名,所以使用FEK而不是EFK. 首先在nginx服务器上执行以下操作. 安装ruby http://blog.csdn.net/chenhaifeng2016/artic...

xiaomin0322
13分钟前
0
0
一键下载:将知乎专栏导出成电子书

老是有同学问,学了 Python 基础后不知道可以做点什么来提高。今天就再用个小例子,给大家讲讲,通过 Python 和爬虫,可以完成怎样的小工具。 在知乎上,你一定关注了一些不错的专栏(比如 ...

crossin
22分钟前
1
0
synchronized 之 对象锁 和 类锁

一、synchronized(object) 如果object没有被加锁,则获取object的锁;如果object已经被加锁则等待object的锁被释放。 二、需要加锁的情景 多线程共享同一资源会引起线程安全的情况下,才需要...

MyOldTime
24分钟前
6
0
tomcat 单机/多机 部署多应用

一.单机部署多应用: 1.在 linux 下解压安装两个 tomcat:tomcat1, tomcat2; 2.修改 /etc/profile, 增加 tomcat 环境变量: path 中加上 重新加载配置文件 source /etc/profile 3.修改 tomc...

imbiao
35分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部