diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index c8e0c65cdbf..b5c14c1485d 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -439,6 +439,9 @@ Release 2.8.0 - UNRELEASED HADOOP-12186. ActiveStandbyElector shouldn't call monitorLockNodeAsync multiple times (zhihai xu via vinayakumarb) + HADOOP-12185. NetworkTopology is not efficient adding/getting/removing + nodes. (Inigo Goiri via cdouglas) + Release 2.7.2 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetworkTopology.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetworkTopology.java index 91410c70816..970ad404f95 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetworkTopology.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetworkTopology.java @@ -18,10 +18,11 @@ package org.apache.hadoop.net; import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.TreeMap; import java.util.concurrent.locks.ReadWriteLock; @@ -81,6 +82,7 @@ public static NetworkTopology getInstance(Configuration conf){ */ static class InnerNode extends NodeBase { protected List children=new ArrayList(); + private Map childrenMap = new HashMap(); private int numOfLeaves; /** Construct an InnerNode from a path-like string */ @@ -172,10 +174,13 @@ boolean add(Node n) { // this node is the parent of n; add n directly n.setParent(this); n.setLevel(this.level+1); - for(int i=0; i= 0) { - // excluded node is one of the children so adjust the leaf index - leafIndex = leafIndex>=excludedIndex ? leafIndex+1 : leafIndex; + if (excludedNode != null && + childrenMap.containsKey(excludedNode.getName())) { + int excludedIndex = children.indexOf(excludedNode); + if (excludedIndex != -1 && leafIndex >= 0) { + // excluded node is one of the children so adjust the leaf index + leafIndex = leafIndex>=excludedIndex ? leafIndex+1 : leafIndex; + } } } // range check diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestClusterTopology.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestClusterTopology.java index 3ab663f3dfa..72fc5cb7037 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestClusterTopology.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestClusterTopology.java @@ -18,8 +18,10 @@ package org.apache.hadoop.net; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import org.apache.commons.math3.stat.inference.ChiSquareTest; import org.junit.Assert; import org.junit.Test; @@ -79,12 +81,14 @@ public void setLevel(int i) { public void testCountNumNodes() throws Exception { // create the topology NetworkTopology cluster = new NetworkTopology(); - cluster.add(getNewNode("node1", "/d1/r1")); + NodeElement node1 = getNewNode("node1", "/d1/r1"); + cluster.add(node1); NodeElement node2 = getNewNode("node2", "/d1/r2"); cluster.add(node2); - cluster.add(getNewNode("node3", "/d1/r3")); - NodeElement node3 = getNewNode("node4", "/d1/r4"); + NodeElement node3 = getNewNode("node3", "/d1/r3"); cluster.add(node3); + NodeElement node4 = getNewNode("node4", "/d1/r4"); + cluster.add(node4); // create exclude list List excludedNodes = new ArrayList(); @@ -95,7 +99,7 @@ public void testCountNumNodes() throws Exception { assertEquals("4 nodes should be available with extra excluded Node", 4, cluster.countNumOfAvailableNodes(NodeBase.ROOT, excludedNodes)); // add one existing node to exclude list - excludedNodes.add(node3); + excludedNodes.add(node4); assertEquals("excluded nodes with ROOT scope should be considered", 3, cluster.countNumOfAvailableNodes(NodeBase.ROOT, excludedNodes)); assertEquals("excluded nodes without ~ scope should be considered", 2, @@ -112,6 +116,69 @@ public void testCountNumNodes() throws Exception { // getting count with non-exist scope. assertEquals("No nodes should be considered for non-exist scope", 0, cluster.countNumOfAvailableNodes("/non-exist", excludedNodes)); + // remove a node from the cluster + cluster.remove(node1); + assertEquals("1 node should be available", 1, + cluster.countNumOfAvailableNodes(NodeBase.ROOT, excludedNodes)); + } + + /** + * Test how well we pick random nodes. + */ + @Test + public void testChooseRandom() { + // create the topology + NetworkTopology cluster = new NetworkTopology(); + NodeElement node1 = getNewNode("node1", "/d1/r1"); + cluster.add(node1); + NodeElement node2 = getNewNode("node2", "/d1/r2"); + cluster.add(node2); + NodeElement node3 = getNewNode("node3", "/d1/r3"); + cluster.add(node3); + NodeElement node4 = getNewNode("node4", "/d1/r3"); + cluster.add(node4); + + // Number of iterations to do the test + int numIterations = 100; + + // Pick random nodes + HashMap histogram = new HashMap(); + for (int i=0; i(); + for (int i=0; i