图说Hadoop源码-NetworkTopology

NetworkTopology定义了InnerNode为根节点的成员变量clusterMap, 其中的方法都是通过clusterMap调用InnerNode中的相应方法并更新一些其他变量. 

比如NetworkTopology.add(Node)会通过clusterMap.add(node)来完成, 并更新NetworkTopology的变量numOfRacks和depthOfAllLeaves.  

下面的方法都会在try和finally中, 通过锁netLock执行. 为了篇幅, 下面的方法都省略了try和finally语句.  

  /** Check if the tree contains Node node*/
  public boolean contains(Node node) {
      Node parent = node.getParent();
      for(int level=node.getLevel(); parent!=null&&level>0; parent=parent.getParent(), level--) {
        if (parent == clusterMap)
          return true;
      }
    return false; 
  }
  /** Check if two nodes are on the same rack */
  public boolean isOnSameRack( Node node1,  Node node2) {
      return node1.getParent()==node2.getParent();
  }

contains: 从叶子节点开始, 一层一层往上寻找父节点. 最终的父节点如果是根节点即clusterMap. 那么节点就在拓扑图中.  

isOnSameRack: (叶子/DN)节点的父节点如果相同, 那么他们就是在同一个机架上. 


getDistance

  /** Return the distance between two nodes. It is assumed that the distance from one node to its parent is 1 节点到父节点的举例为1
   * The distance between two nodes is calculated by summing up their distances to their closest common ancestor. 寻找最近的共同祖先. */
  public int getDistance(Node node1, Node node2) {
    if (node1 == node2) return 0;
    Node n1=node1, n2=node2;
    int dis = 0;
      int level1=node1.getLevel(), level2=node2.getLevel();
      while(n1!=null && level1>level2) {
        n1 = n1.getParent();
        level1--;
        dis++;
      }
      while(n2!=null && level2>level1) {
        n2 = n2.getParent();
        level2--;
        dis++;
      }
      while(n1!=null && n2!=null && n1.getParent()!=n2.getParent()) {
        n1=n1.getParent();
        n2=n2.getParent();
        dis+=2;
      }
    return dis+2;
  } 

计算节点间的距离从一个节点到另一个节点在网络拓扑图中经过的边的数量.


下面的网络拓扑图中每个叶子节点的level都为3. 所以代码主要集中在第三个while循环的处理<h1, h3>为例分析距离的计算过程


pseudoSortByDistance

  /* swap two array items */
  static private void swap(Node[] nodes, int i, int j) {
    Node tempNode;
    tempNode = nodes[j];
    nodes[j] = nodes[i];
    nodes[i] = tempNode;
  }
  
  /** Sort nodes array by their distances to reader
   * It linearly scans the array, if a local node is found, swap it with the first element of the array.
   * If a local rack node is found, swap it with the first element following the local node.
   * If neither local node or local rack node is found, put a random replica location at postion 0. It leaves the rest nodes untouched. */
  public void pseudoSortByDistance( Node reader, Node[] nodes ) {
    int tempIndex = 0;							// 是否有本地节点的标记位. 如果有设置为1
    if (reader != null ) {
      int localRackNode = -1;					// nodes中和reader同一机架的节点的索引. -1为没有节点和reader同机架, 标志位
      for(int i=0; i<nodes.length; i++) {			// scan the array to find the local node & local rack node
        if(tempIndex == 0 && reader == nodes[i]){	// [01] local node 在数组中找到一个本地节点. 将数组中的此节点交换到数组的第一个位置
          if( i != 0 ) swap(nodes, 0, i);			// [02] swap the local node and the node at position 0 数组中有localnode,但不在第一个位置才需要交换
          tempIndex=1;						// [03] 数组中有本地节点, 标记tempIndex=1
          if(localRackNode != -1 ) {				// [04] 在本地节点之前的节点有和reader同机架的, 已经设置了localRackNode为其节点索引
            if(localRackNode == 0) {			// [05] 数组的第一个节点就在和reader同一机架.	
              localRackNode = i;				// [06] 因为本地节点其实也可以看做是和reader同机架的. 所以设置localRackNode=0.
            }
            break;							// [07] 只要本地节点前有和reader同机架的, 不管是不是数组的第一项. 都会跳出循环
          }
        } else if(localRackNode == -1 && isOnSameRack(reader, nodes[i])) { // [08] local rack 数组中有节点和read在同一机架
          localRackNode = i;					// [09] 在数组nodes中找到和reader同一机架的节点, 设置标记位localRackNode为此节点的索引
          if(tempIndex != 0 ) break;				// [10] 
        }
      }
      
      if(localRackNode != -1 && localRackNode != tempIndex ) {	// [11] swap the local rack node and the node at position tempIndex
        swap(nodes, tempIndex, localRackNode);				// [12]
        tempIndex++;
      }
    }
    
    if(tempIndex == 0 && nodes.length != 0) {					// [13] put a random node at position 0 if it is not a local/local-rack node
      swap(nodes, 0, r.nextInt(nodes.length));				// [14]	
    }
  }

假设reader=h0(为了和索引从0开始相对应记第一个DNh0), 待排序的DN数组有h0, h1, h2. 其中数组的h0称作local node.

数组的排序有6(3!=3*2*1=6)种方式: [h0, h1, h2] [h0, h2, h1] [h1, h0, h2] [h1, h2, h0] [h2, h0, h1] [h2, h1, h0]


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

A. [h0, h1, h2]

[01] nodes[0]=h0=reader 数组中存在本地节点

[02] .. i=0, 本地节点不需要交换到数组前面因为已经在最前面了

[03] tempIndex=1

[04] localRackNode=-1 ... 继续处理数组的下一个节点h1

[08] h1reader在同一个机架上

[09] localRackNode=1, 表示和reader同一机架的节点的索引为1, nodes[1]reader同机架.

[10] tempIndex=1, break

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

nodes: [h0, h1, h2]

localRackNode = 1:  本机架节点nodes[1]=h1

tempIndex = 1:  存在本地节点

[..] 因为localRackNode = tempIndex = 1. 所以后面都不执行了 h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

B. [h0, h2, h1]

[01] nodes[0]=h0=reader 数组中存在本地节点

[02] .. i=0, 本地节点不需要交换到数组前面因为已经在最前面了

[03] tempIndex=1

[04] localRackNode=-1 ... 继续处理数组的下一个节点h1

[..] h2都不满足本地节点和本地机架继续处理数组的下一个节点h1

[08] h1reader在同一个机架上

[09] localRackNode=2, 表示和reader同一机架的节点的索引为2, nodes[2]reader同机架.

[10] tempIndex=1, break

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

nodes: [h0, h2, h1]

localRackNode = 2:  本机架节点nodes[2]=h1

tempIndex = 1:  存在本地节点

[11] localRackNode != tempIndex

[12] 交换localRackNodetempIndex. 即交换数组中2(localRackNode的值)1(tempIndex的值)的节点h2h1交换: [h0, h1, h2]

PS: 交换节点时, localRackNodetempIndex的值会不会互换不会互换这两个方法内的变量只起到标志位的作用我们的目的是排序数组.

[..] tempIndex++, [13]就不会执行了 h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

C. [h1, h0, h2]

[08] h1reader在同一个机架上

[09] localRackNode=0, 表示和reader同一机架的节点的索引为0, nodes[0]reader同机架.

[10] tempIndex=0

[01] nodes[1]=h0=reader 数组中存在本地节点

[02] .. i=1, 交换第一个节点(h1)和本地节点(h0)的位置 [h0, h1, h2]

[03] tempIndex=1

[04][05] localRackNode=0, 即数组第一个节点和reader同机架(本地节点不在数组第一个). 

[06] 设置localRackNode=i=1. 因为本机架节点(第一个)和本地节点交换交换后本机架节点的索引就是交换前的本地节点的位置

[07] break 只要本地节点前有和reader同机架的不管是不是数组的第一项都会跳出循环

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

nodes: [h1, h0, h2]  -> [h0, h1, h2]

localRackNode = 1:  本机架节点nodes[1]=h1

tempIndex = 1:  存在本地节点

localRackNode = tempIndex. A. [h0, h1, h2] h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

D. [h1, h2, h0]

[08] h1reader在同一个机架上

[09] localRackNode=0, 表示和reader同一机架的节点的索引为0, nodes[0]reader同机架.

[10] tempIndex=0

[..] h2都不满足本地节点和本地机架继续处理数组的下一个节点h1

[01] nodes[2]=h0=reader 数组中存在本地节点

[02] .. i=2, 交换第一个节点(h1)和本地节点(h0)的位置 [h0, h2, h1]

[03] tempIndex=1

[04][05] localRackNode=0, 即数组第一个节点和reader同机架(本地节点不在数组第一个). 

[06] 设置localRackNode=i=2. 因为本机架节点(第一个)和本地节点交换交换后本机架节点的索引就是交换前的本地节点的位置

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

nodes: [h1, h2, h0]  -> [h0, h2, h1]

localRackNode = 2:  本机架节点nodes[2]=h1

tempIndex = 1:  存在本地节点

localRackNode != tempIndex, B. [h0, h2, h1] -> [h0, h1 , h2] h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

E. [h2, h0, h1]

[..] h2都不满足本地节点和本地机架继续处理数组的下一个节点h1

[01] nodes[1]=h0=reader 数组中存在本地节点

[02] .. i=1!=0, 交换第一个节点(h2)和本地节点(h0)的位置 [h0, h2, h1]

[03] tempIndex=1

[04] localRackNode=-1 ... 继续处理数组的下一个节点h1

[08] h1reader在同一个机架上

[09] localRackNode=2, 表示和reader同一机架的节点的索引为2, nodes[2]reader同机架.

[10] tempIndex=1, break

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

nodes: [h2, h0, h1]  -> [h0, h2, h1]

localRackNode = 2:  本机架节点nodes[2]=h1

tempIndex = 1:  存在本地节点

localRackNode != tempIndex, B. [h0, h2, h1] -> [h0, h1, h2] h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

F. [h2, h1, h0]

[..] h2都不满足本地节点和本地机架继续处理数组的下一个节点h1

[08] h1reader在同一个机架上

[09] localRackNode=1, 表示和reader同一机架的节点的索引为1, nodes[1]reader同机架.

[10] tempIndex=0

[01] nodes[2]=h0=reader 数组中存在本地节点

[02] .. i=2!=0, 交换第一个节点(h2)和本地节点(h0)的位置 [h0, h1, h2]

[03] tempIndex=1

[04] localRackNode=1  

[07] break

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

nodes: [h2, h1, h0]  -> [h0, h1, h2]

localRackNode = 1:  本机架节点nodes[1]=h1

tempIndex = 1:  存在本地节点

localRackNode = tempIndex. A. [h0, h1, h2] h0, h1, h2

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

**[*, *, *] -> [h0, h1, h2]**  

存在本地节点和本机架节点的情况下最后数组都会排列成[h0, h1, h2]


**循环次数:**  

A. [h0, h1, h2]

C. [h1, h0, h2]  -> [h0, h1, h2]

如果数组的前两个节点分别是本地节点和本机架节点则后面的节点不会再执行了说明只排序了两次所以也叫做伪排序.

**tempIndex == localRackNode**  

tempIndex取值要么为0表示不存在本地节点要么为1表示存在本地节点.

localRackNode表示数组中和reader同一机架的节点的位置取值可以为数组的任意一项

localRackNode如果等于tempIndex=0/1. 即本机架节点在数组的第一项nodes[0]或者第二项nodes[1]. 

localRackNode = tempIndex = 0时表示不存在本地节点本机架节点为nodes[0]. 

不存在本地节点但存在本机架节点那么本机架节点应该排列在数组的第一个位置


localRackNode = tempIndex = 1时表示本机架节点为nodes[1], 本地节点为nodes[0]

存在本地节点本地节点优于本机架节点所以本地节点应该排在数组的第一个位置


**localRackNode !=-1, tempIndex != localRackNode**

tempIndex=0, localRackNode=1,2....  不存在本地节点本机架节点应该在数组的第一项进行交换操作交换本地节点到nodes[0]

tempIndex=1,  localRackNode=2,... 存在本地节点因为本地节点优于本机架节点所以本地节点已经在第一项了

localRackNode应该从数组第三项即nodes[2]开始(不能为0, 因为已经被本地节点占了不能为1, 因为!=的约束). 

那么本机架节点要交换到数组的第二项nodes[1]紧跟着本地节点后面

也就是说如果本地节点和本机架几点都存在的情况下排列顺序依次是本地节点本机架节点...


测试用例3 - pseudoSort
  public void printLocalNodeAndLocalRack(DatanodeDescriptor[] testNodes){
	  cluster.pseudoSortByDistance(dataNodes[0], testNodes );
	  assertTrue(testNodes[0] == dataNodes[0]);
	  assertTrue(testNodes[1] == dataNodes[1]);
	  assertTrue(testNodes[2] == dataNodes[2]);
  }
  public void nodeIndex(DatanodeDescriptor[] testNodes, int[] nodeIndex){
	  for(int i=0;i<3;i++){
		  testNodes[i] = dataNodes[nodeIndex[i]];
	  }
  }
  
  public void testPseudoSortByDistance() throws Exception {
    DatanodeDescriptor[] testNodes = new DatanodeDescriptor[3];
    int[][] index = new int[][]{
    	{0,1,2}, {0,2,1}, {1,0,2}, {1,2,0}, {2,0,1}, {2,1,0},
    };
    for(int i=0; i<index.length;i++){
    	nodeIndex(testNodes, index[i]);
    	printLocalNodeAndLocalRack(testNodes);
  }
  }

  public void testPseudoSortByDistance() throws Exception {
    DatanodeDescriptor[] testNodes = new DatanodeDescriptor[3];
    
    // array contains both local node & local rack node
    testNodes[0] = dataNodes[1];
    testNodes[1] = dataNodes[2];
    testNodes[2] = dataNodes[0];
    cluster.pseudoSortByDistance(dataNodes[0], testNodes );
    assertTrue(testNodes[0] == dataNodes[0]);
    assertTrue(testNodes[1] == dataNodes[1]);
    assertTrue(testNodes[2] == dataNodes[2]);

    // array contains local node
    testNodes[0] = dataNodes[1];
    testNodes[1] = dataNodes[3];
    testNodes[2] = dataNodes[0];
    cluster.pseudoSortByDistance(dataNodes[0], testNodes );
    assertTrue(testNodes[0] == dataNodes[0]);
    assertTrue(testNodes[1] == dataNodes[1]);
    assertTrue(testNodes[2] == dataNodes[3]);

    // array contains local rack node
    testNodes[0] = dataNodes[5];
    testNodes[1] = dataNodes[3];
    testNodes[2] = dataNodes[1];
    cluster.pseudoSortByDistance(dataNodes[0], testNodes );
    assertTrue(testNodes[0] == dataNodes[1]);
    assertTrue(testNodes[1] == dataNodes[3]);
    assertTrue(testNodes[2] == dataNodes[5]);
  }




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值