`
xitong
  • 浏览: 6197313 次
文章分类
社区版块
存档分类
最新评论

hadoop 0.1.0版本namenode代码分析

 
阅读更多

在对hbase有了一点了解后最近开始学习hadoop的相关源码,首先看了下某高人的hadoop源码分析系列http://caibinbupt.iteye.com/blog/monthblog/2008-11,看了三十几篇停了,有些看不懂,虽然代码解释的比较细但类实在太多,想一下子理清思路比较难。果断使用学习hbase时的方法,把hadoop最原始的化石版本0.1.0搞来看看,本文将介绍namenode的重要逻辑实现。

namenode初始化流程:

1.初始化FSNamespace(处理hadoop中虚拟文件系统的大多逻辑)
2.初始化配置

FSNamespace初始化
1。初始化FSDirectory
2.初始化HeartbeatMonitor,管理datanode的心跳,超时则删除此节点
3.初始化LeaseMonitor,管理hadoop的契约,会定期处理超时的操作


FSDirectory初始化:
1.loadFSImage 从image load 文件名=》blockid的map
2.saveFSImage 把1的map持久化到文件
3.this.editlog = new DataOutputStream 打开editlog的输出流,准备随时写入

0.1.0版本果然是非常的简单,namenode在启动后啥也不干,只是接受RPC请求,所以后面会以重要函数为切入介绍namenode。

FSDirectory.LoadFsImage:

作用:我们知道namenode需要维护filename-》blocksequence的map,LoadFsImage就是从image文件中load 该map

 DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(curFile)));
            try {
                int numFiles = in.readInt();
                for (int i = 0; i < numFiles; i++) {
                    UTF8 name = new UTF8();
                    name.readFields(in);
                    int numBlocks = in.readInt();
                    if (numBlocks == 0) {
                        unprotectedAddFile(name, null);
                    } else {
                        Block blocks[] = new Block[numBlocks];
                        for (int j = 0; j < numBlocks; j++) {
                            blocks[j] = new Block();
                            blocks[j].readFields(in);
                        }
                        unprotectedAddFile(name, blocks);
                    }
                }

解读:

1.很有意思,image的读写中全是直接的readField和writeField来做持久化,没有任何读写object

2.numBlocks为零即为目录

3.Block对象包括blockId,length

synchronized (rootDir) {
        if (blocks != null) {
            // Add file->block mapping
            for (int i = 0; i < blocks.length; i++) {
                    activeBlocks.add(blocks[i]);
                }
        }
        return (rootDir.addNode(name.toString(), blocks) != null);
   }

执行rootDir.addNode添加该node,包括文件名和对应的blocks。

解释下INode类:

类似Linux中INode的概念,看下INode的成员变量

class INode :
        public String name;
        public INode parent;
        public TreeMap children = new TreeMap();
        public Block blocks[];

包含了文件名,父亲节点,孩子节点,和文件实际的blocks

再来看addNode方法:

INode addNode(String target, Block blks[]) {
            if (getNode(target) != null) {
                return null;
            } else {
                String parentName = DFSFile.getDFSParent(target);
                if (parentName == null) {
                    return null;
                }

                INode parentNode = getNode(parentName);
                if (parentNode == null) {
                    return null;
                } else {
                    String targetName = new File(target).getName();
                    INode newItem = new INode(targetName, parentNode, blks);
                    parentNode.children.put(targetName, newItem);
                    return newItem;
                }
            }
        }

1.首先尝试getNode,如果取到INode对象表示已经有该节点,返回失败

2.DFSFile.getDFSParent拿到parent文件夹的名字,方法是简单的字符串操作

3.拿到parent INode

4.创新新INode,并添加到parent中。这边调用了 new File().getName,没太明白,应该不会真的创建文件的,只是调用下getName方法。

再看下getNode方法:

  Vector components = new Vector();
                int start = 0;
                int slashid = 0;
                while (start < target.length() && (slashid = target.indexOf('/', start)) >= 0) {
                    components.add(target.substring(start, slashid));
                    start = slashid + 1;
                }
                if (start < target.length()) {
                    components.add(target.substring(start));
                }
                return getNode(components, 0);

根据'/'符把文件路径分割成一个个component,然后调用getNode(components,0)递归获取INode。

INode getNode(Vector components, int index) {
            if (! name.equals((String) components.elementAt(index))) {
                return null;
            }
            if (index == components.size()-1) {
                return this;
            }

            // Check with children
            INode child = (INode) children.get(components.elementAt(index+1));
            if (child == null) {
                return null;
            } else {
                return child.getNode(components, index+1);
            }
        }

这样,通过调用LoadFsImage方法就成功将Image中的数据转换为Inode对象挂到rootNode上了。

Namenode.open:

方法申明:public LocatedBlock[] open(String src)

作用:client从namenode打开一个文件

LocatedBlock包括了该文件需要的blocks和每个block对应的datanode的集合,在实际读取过程中每个block会随即从拥有该block的datanode中读出block。

public LocatedBlock[] open(String src) throws IOException {
        Object openResults[] = namesystem.open(new UTF8(src));
        if (openResults == null) {
            throw new IOException("Cannot open filename " + src);
        } else {
            Block blocks[] = (Block[]) openResults[0];
            DatanodeInfo sets[][] = (DatanodeInfo[][]) openResults[1];
            LocatedBlock results[] = new LocatedBlock[blocks.length];
            for (int i = 0; i < blocks.length; i++) {
                results[i] = new LocatedBlock(blocks[i], sets[i]);
            }
            return results;
        }
    }

namesystem.open

public Object[] open(UTF8 src) {
        Object results[] = null;
        Block blocks[] = dir.getFile(src);
        if (blocks != null) {
            results = new Object[2];
            DatanodeInfo machineSets[][] = new DatanodeInfo[blocks.length][];

            for (int i = 0; i < blocks.length; i++) {
                TreeSet containingNodes = (TreeSet) blocksMap.get(blocks[i]);
                if (containingNodes == null) {
                    machineSets[i] = new DatanodeInfo[0];
                } else {
                    machineSets[i] = new DatanodeInfo[containingNodes.size()];
                    int j = 0;
                    for (Iterator it = containingNodes.iterator(); it.hasNext(); j++) {
                        machineSets[i][j] = (DatanodeInfo) it.next();
                    }
                }
            }

            results[0] = blocks;
            results[1] = machineSets;
        }
        return results;
    }

首先通过dir.getFile拿到该文件对应的blocks列表,然后从block->datanode的map中取出相应的machineSets。

namenode的主要逻辑我个人感觉搞清楚file->blockseqid和blockid->machineSet这2个map就差不多了。后面有空会分析下最新的hadoop2.0的代码。

是时候看点真正的代码了!。。。





分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics