hadoop源代码分析——block管理(一)

更多请看http://www.kakuka.net

6.1 block allocation

6.1.1 block allocation概览

客户端使用DFSOutputStream调用namenode的addBlock()(RPC方法),之后namenode调用nameSystem的getAdditionalBlock函数,传递文件名和客户端。
public LocatedBlock getAdditionalBlock(String src, 
                                         String clientName
                                         ) throws IOException {
    //忽略了一部分检测

      INodeFileUnderConstruction pendingFile  = checkLease(src, clientName);

      //
      // If we fail this, bad things happen!
      //
      if (!checkFileProgress(pendingFile, false)) {
        throw new NotReplicatedYetException("Not replicated yet:" + src);
      }
      fileLength = pendingFile.computeContentSummary().getLength();
      blockSize = pendingFile.getPreferredBlockSize();
      clientNode = pendingFile.getClientNode();
      replication = (int)pendingFile.getReplication();
    }

    // choose targets for the new block tobe allocated.
    DatanodeDescriptor targets[] = replicator.chooseTarget(replication,
                                                           clientNode,
                                                           null,
                                                           blockSize);
    if (targets.length < this.minReplication) {
      throw new IOException("File " + src + " could only be replicated to " +
                            targets.length + " nodes, instead of " +
                            minReplication);
    }

    // Allocate a new block and record it in the INode. 
    synchronized (this) {
      INode[] pathINodes = dir.getExistingPathINodes(src);//返回路径上的所有节点,最后一个是叶子节点(如果src指向文件的话)
      int inodesLen = pathINodes.length;
      checkLease(src, clientName, pathINodes[inodesLen-1]);
      INodeFileUnderConstruction pendingFile  = (INodeFileUnderConstruction) 
                                                pathINodes[inodesLen - 1];
                                                           
      if (!checkFileProgress(pendingFile, false)) {
        throw new NotReplicatedYetException("Not replicated yet:" + src);
      }

      // allocate new block record block locations in INode.
      newBlock = allocateBlock(src, pathINodes);
      pendingFile.setTargets(targets);
      
      for (DatanodeDescriptor dn : targets) {
        dn.incBlocksScheduled();
      }//表示这个datanode中需要被处理的block多了一个。      
    }
        
    // Create next block
    return new LocatedBlock(newBlock, targets, fileLength);
  }

这个函数经过一系列检测之后,调用replicator.chooseTarget把block都分配好了(下面详说),之后进行封装返回。注意此时的block还未在硬盘上进行存储,即现在只是绑定了block和它所属的file。在函数调用路径中有这样一段:
      namesystem.blocksMap.addINode(block, fileNode);
      BlockInfo blockInfo = namesystem.blocksMap.getStoredBlock(block);
      fileNode.addBlock(blockInfo);
可以看出来,现在只是绑定了block和file(即INode)。然后在getAdditionalBlock函数中pendingFile.setTargets(targets),设置好了这个block需要复制到的目标。

6.1.2 block allocation算法

好了,看完了整体,接下来就看看block是如何分配的吧,确切的说是block的target(datanode)是如何分配的。从ReplicationTargetChooser的chooseTarget看起。这里不分析整个调用栈,只取出其关键的部分来讨论,考虑第一次分配调用的情况。
DatanodeDescriptor[] chooseTarget(int numOfReplicas,
                                    DatanodeDescriptor writer,
                                    List
  
  
   
    choosenNodes,
                                    List
   
   
    
     excludedNodes,
                                    long blocksize) {
    //忽略一些
    
    if (!clusterMap.contains(writer)) {
      writer=null;
    }//在一般情况下,客户端不是datanode,所以这个一般会成立。
      //关键的部分
    DatanodeDescriptor localNode = chooseTarget(numOfReplicas, writer, 
                                                excludedNodes, blocksize, maxNodesPerRack, results);
      
    results.removeAll(choosenNodes);
      
    // sorting nodes to form a pipeline 按照距离设置
    return getPipeline((writer==null)?localNode:writer,
                       results.toArray(new DatanodeDescriptor[results.size()]));
  }

   
   
  
  
关键部分拿下来:
private DatanodeDescriptor chooseTarget(int numOfReplicas,
                                          DatanodeDescriptor writer,
                                          List
  
  
   
    excludedNodes,
                                          long blocksize,
                                          int maxNodesPerRack,
                                          List
   
   
    
     results) {
      
    //忽略非第一次的判定部分
      
    int numOfResults = results.size();//第一次分配时,size 是0
    boolean newBlock = (numOfResults==0);
    if (writer == null && !newBlock) {
      writer = (DatanodeDescriptor)results.get(0);
    }
      
    try {
      switch(numOfResults) {
      case 0:
        writer = chooseLocalNode(writer, excludedNodes, 
                                 blocksize, maxNodesPerRack, results);
		//在一般的客户端不是datanode的情况下,这里仅仅随机选取了一个datanode作为本地node,也就是primary(待定)
        if (--numOfReplicas == 0) {
          break;
        }
      //……忽略达不到的部分
      default:
        chooseRandom(numOfReplicas, NodeBase.ROOT, excludedNodes, 
                     blocksize, maxNodesPerRack, results);//随机选取了其余的target
      }
    } catch (NotEnoughReplicasException e) {
      FSNamesystem.LOG.warn("Not able to place enough replicas, still in need of "
               + numOfReplicas);
    }
    return writer;
  }

   
   
  
  
这些函数综合起来,也就说在首次分配的时候,首先随机选取了一个datanode作为primary,之后随机选取了一些datanode作为target。这里并未体现复杂的分配算法,后续的调整部分可能会有。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值