Skip to content

Commit 77435a0

Browse files
authored
HADOOP-17408. Optimize NetworkTopology sorting block locations. (#2601). Contributed by Ahmed Hussein and Daryn Sharp.
1 parent e306f59 commit 77435a0

File tree

2 files changed

+36
-44
lines changed

2 files changed

+36
-44
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/NetworkTopology.java

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import org.apache.hadoop.thirdparty.com.google.common.annotations.VisibleForTesting;
2121
import org.apache.hadoop.thirdparty.com.google.common.base.Preconditions;
22-
import org.apache.hadoop.thirdparty.com.google.common.collect.Lists;
2322
import org.apache.hadoop.classification.InterfaceAudience;
2423
import org.apache.hadoop.classification.InterfaceStability;
2524
import org.apache.hadoop.conf.Configuration;
@@ -29,6 +28,8 @@
2928
import org.slf4j.LoggerFactory;
3029

3130
import java.util.*;
31+
import java.util.concurrent.ThreadLocalRandom;
32+
import java.util.concurrent.atomic.AtomicReference;
3233
import java.util.concurrent.locks.ReadWriteLock;
3334
import java.util.concurrent.locks.ReentrantReadWriteLock;
3435
import java.util.function.Consumer;
@@ -52,6 +53,8 @@ public class NetworkTopology {
5253
private static final char PATH_SEPARATOR = '/';
5354
private static final String PATH_SEPARATOR_STR = "/";
5455
private static final String ROOT = "/";
56+
private static final AtomicReference<Random> RANDOM_REF =
57+
new AtomicReference<>();
5558

5659
public static class InvalidTopologyException extends RuntimeException {
5760
private static final long serialVersionUID = 1L;
@@ -394,17 +397,12 @@ static public int getDistanceByPath(Node node1, Node node2) {
394397
* @exception IllegalArgumentException when either node1 or node2 is null, or
395398
* node1 or node2 do not belong to the cluster
396399
*/
397-
public boolean isOnSameRack( Node node1, Node node2) {
400+
public boolean isOnSameRack(Node node1, Node node2) {
398401
if (node1 == null || node2 == null) {
399402
return false;
400403
}
401-
402-
netlock.readLock().lock();
403-
try {
404-
return isSameParents(node1, node2);
405-
} finally {
406-
netlock.readLock().unlock();
407-
}
404+
405+
return isSameParents(node1, node2);
408406
}
409407

410408
/**
@@ -438,11 +436,14 @@ protected boolean isSameParents(Node node1, Node node2) {
438436
return node1.getParent()==node2.getParent();
439437
}
440438

441-
private static final Random r = new Random();
442-
443439
@VisibleForTesting
444440
void setRandomSeed(long seed) {
445-
r.setSeed(seed);
441+
RANDOM_REF.set(new Random(seed));
442+
}
443+
444+
Random getRandom() {
445+
Random random = RANDOM_REF.get();
446+
return (random == null) ? ThreadLocalRandom.current() : random;
446447
}
447448

448449
/**
@@ -561,6 +562,7 @@ private Node chooseRandom(final InnerNode parentNode,
561562
totalInScopeNodes, availableNodes);
562563
return null;
563564
}
565+
Random r = getRandom();
564566
if (excludedNodes == null || excludedNodes.isEmpty()) {
565567
// if there are no excludedNodes, randomly choose a node
566568
final int index = r.nextInt(totalInScopeNodes);
@@ -876,7 +878,7 @@ public void sortByDistance(Node reader, Node[] nodes, int activeLen) {
876878
* This method is called if the reader is a datanode,
877879
* so nonDataNodeReader flag is set to false.
878880
*/
879-
sortByDistance(reader, nodes, activeLen, list -> Collections.shuffle(list));
881+
sortByDistance(reader, nodes, activeLen, null);
880882
}
881883

882884
/**
@@ -919,8 +921,7 @@ public void sortByDistanceUsingNetworkLocation(Node reader, Node[] nodes,
919921
* This method is called if the reader is not a datanode,
920922
* so nonDataNodeReader flag is set to true.
921923
*/
922-
sortByDistanceUsingNetworkLocation(reader, nodes, activeLen,
923-
list -> Collections.shuffle(list));
924+
sortByDistanceUsingNetworkLocation(reader, nodes, activeLen, null);
924925
}
925926

926927
/**
@@ -958,38 +959,28 @@ private <T extends Node> void sortByDistance(Node reader, T[] nodes,
958959
int activeLen, Consumer<List<T>> secondarySort,
959960
boolean nonDataNodeReader) {
960961
/** Sort weights for the nodes array */
961-
int[] weights = new int[activeLen];
962-
for (int i=0; i<activeLen; i++) {
963-
if(nonDataNodeReader) {
964-
weights[i] = getWeightUsingNetworkLocation(reader, nodes[i]);
962+
TreeMap<Integer, List<T>> weightedNodeTree =
963+
new TreeMap<>();
964+
int nWeight;
965+
for (int i = 0; i < activeLen; i++) {
966+
if (nonDataNodeReader) {
967+
nWeight = getWeightUsingNetworkLocation(reader, nodes[i]);
965968
} else {
966-
weights[i] = getWeight(reader, nodes[i]);
967-
}
968-
}
969-
// Add weight/node pairs to a TreeMap to sort
970-
TreeMap<Integer, List<T>> tree = new TreeMap<>();
971-
for (int i=0; i<activeLen; i++) {
972-
int weight = weights[i];
973-
T node = nodes[i];
974-
List<T> list = tree.get(weight);
975-
if (list == null) {
976-
list = Lists.newArrayListWithExpectedSize(1);
977-
tree.put(weight, list);
969+
nWeight = getWeight(reader, nodes[i]);
978970
}
979-
list.add(node);
971+
weightedNodeTree.computeIfAbsent(
972+
nWeight, k -> new ArrayList<>(1)).add(nodes[i]);
980973
}
981-
// Sort nodes which have the same weight using secondarySort.
982974
int idx = 0;
983-
for (List<T> list: tree.values()) {
984-
if (list != null) {
985-
Collections.shuffle(list, r);
986-
if (secondarySort != null) {
987-
secondarySort.accept(list);
988-
}
989-
for (T n: list) {
990-
nodes[idx] = n;
991-
idx++;
992-
}
975+
// Sort nodes which have the same weight using secondarySort.
976+
for (List<T> nodesList : weightedNodeTree.values()) {
977+
Collections.shuffle(nodesList, getRandom());
978+
if (secondarySort != null) {
979+
// a secondary sort breaks the tie between nodes.
980+
secondarySort.accept(nodesList);
981+
}
982+
for (T n : nodesList) {
983+
nodes[idx++] = n;
993984
}
994985
}
995986
Preconditions.checkState(idx == activeLen,

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/net/TestNetworkTopology.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Map;
3030
import java.util.Random;
3131
import java.util.Set;
32+
import java.util.concurrent.TimeUnit;
3233

3334
import org.apache.hadoop.conf.Configuration;
3435
import org.apache.hadoop.hdfs.DFSTestUtil;
@@ -56,7 +57,7 @@ public class TestNetworkTopology {
5657
private DatanodeDescriptor dataNodes[];
5758

5859
@Rule
59-
public Timeout testTimeout = new Timeout(30000);
60+
public Timeout testTimeout = new Timeout(30000, TimeUnit.MILLISECONDS);
6061

6162
@Before
6263
public void setupDatanodes() {

0 commit comments

Comments
 (0)