blob: 4019b1305f6a88fccb88499d6557c5846e4bb53a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdds.scm.net;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Utility class to facilitate network topology functions.
*/
public final class NetUtils {
public static final Logger LOG = LoggerFactory.getLogger(NetUtils.class);
private NetUtils() {
// Prevent instantiation
}
/**
* Normalize a path by stripping off any trailing.
* {@link NetConstants#PATH_SEPARATOR}
* @param path path to normalize.
* @return the normalised path
* If <i>path</i>is empty or null, then {@link NetConstants#ROOT} is returned
*/
public static String normalize(String path) {
if (path == null || path.length() == 0) {
return NetConstants.ROOT;
}
if (path.charAt(0) != NetConstants.PATH_SEPARATOR) {
throw new IllegalArgumentException(
"Network Location path does not start with "
+ NetConstants.PATH_SEPARATOR_STR + ": " + path);
}
// Remove any trailing NetConstants.PATH_SEPARATOR
return path.length() == 1 ? path :
path.replaceAll(NetConstants.PATH_SEPARATOR_STR + "+$", "");
}
/**
* Given a network topology location string, return its network topology
* depth, E.g. the depth of /dc1/rack1/ng1/node1 is 5.
*/
public static int locationToDepth(String location) {
String newLocation = normalize(location);
return newLocation.equals(NetConstants.PATH_SEPARATOR_STR) ? 1 :
newLocation.split(NetConstants.PATH_SEPARATOR_STR).length;
}
/**
* Remove node from mutableExcludedNodes if it's covered by excludedScope.
* Please noted that mutableExcludedNodes content might be changed after the
* function call.
*/
public static void removeDuplicate(NetworkTopology topology,
Collection<Node> mutableExcludedNodes, List<String> mutableExcludedScopes,
int ancestorGen) {
if (CollectionUtils.isEmpty(mutableExcludedNodes) ||
CollectionUtils.isEmpty(mutableExcludedScopes) || topology == null) {
return;
}
Iterator<Node> iterator = mutableExcludedNodes.iterator();
while (iterator.hasNext() && (!mutableExcludedScopes.isEmpty())) {
Node node = iterator.next();
Node ancestor = topology.getAncestor(node, ancestorGen);
if (ancestor == null) {
LOG.warn("Fail to get ancestor generation " + ancestorGen +
" of node :" + node);
continue;
}
// excludedScope is child of ancestor
List<String> duplicateList = mutableExcludedScopes.stream()
.filter(scope -> scope.startsWith(ancestor.getNetworkFullPath()))
.collect(Collectors.toList());
mutableExcludedScopes.removeAll(duplicateList);
// ancestor is covered by excludedScope
mutableExcludedScopes.stream().forEach(scope -> {
if (ancestor.getNetworkFullPath().startsWith(scope)) {
// remove exclude node if it's covered by excludedScope
iterator.remove();
}
});
}
}
/**
* Remove node from mutableExcludedNodes if it's not part of scope
* Please noted that mutableExcludedNodes content might be changed after the
* function call.
*/
public static void removeOutscope(Collection<Node> mutableExcludedNodes,
String scope) {
if (CollectionUtils.isEmpty(mutableExcludedNodes) || scope == null) {
return;
}
synchronized (mutableExcludedNodes) {
Iterator<Node> iterator = mutableExcludedNodes.iterator();
while (iterator.hasNext()) {
Node next = iterator.next();
if (!next.getNetworkFullPath().startsWith(scope)) {
iterator.remove();
}
}
}
}
/**
* Get a ancestor list for nodes on generation <i>generation</i>.
*
* @param nodes a collection of leaf nodes
* @param generation the ancestor generation
* @return the ancestor list. If no ancestor is found, then a empty list is
* returned.
*/
public static List<Node> getAncestorList(NetworkTopology topology,
Collection<Node> nodes, int generation) {
List<Node> ancestorList = new ArrayList<>();
if (topology == null || CollectionUtils.isEmpty(nodes) ||
generation == 0) {
return ancestorList;
}
Iterator<Node> iterator = nodes.iterator();
while (iterator.hasNext()) {
Node node = iterator.next();
Node ancestor = topology.getAncestor(node, generation);
if (ancestor == null) {
LOG.warn("Fail to get ancestor generation " + generation +
" of node :" + node);
continue;
}
if (!ancestorList.contains(ancestor)) {
ancestorList.add(ancestor);
}
}
return ancestorList;
}
}