blob: 53b05ea294166a17bf9444b4748ca9b5de0792b2 [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 com.google.common.base.Preconditions;
import static org.apache.hadoop.hdds.scm.net.NetConstants.ROOT;
import static org.apache.hadoop.hdds.scm.net.NetConstants.PATH_SEPARATOR_STR;
/**
* A thread safe class that implements interface Node.
*/
public class NodeImpl implements Node {
// host:port#
private String name;
// string representation of this node's location, such as /dc1/rack1
private String location;
// location + "/" + name
private String path;
// which level of the tree the node resides, start from 1 for root
private int level;
// node's parent
private InnerNode parent;
// the cost to go through this node
private final int cost;
/**
* Construct a node from its name and its location.
* @param name this node's name (can be null, must not contain
* {@link NetConstants#PATH_SEPARATOR})
* @param location this node's location
*/
public NodeImpl(String name, String location, int cost) {
if (name != null && name.contains(PATH_SEPARATOR_STR)) {
throw new IllegalArgumentException(
"Network location name:" + name + " should not contain " +
PATH_SEPARATOR_STR);
}
this.name = (name == null) ? ROOT : name;
this.location = NetUtils.normalize(location);
this.path = getPath();
this.cost = cost;
}
/**
* Construct a node from its name and its location.
*
* @param name this node's name (can be null, must not contain
* {@link NetConstants#PATH_SEPARATOR})
* @param location this node's location
* @param parent this node's parent node
* @param level this node's level in the tree
* @param cost this node's cost if traffic goes through it
*/
public NodeImpl(String name, String location, InnerNode parent, int level,
int cost) {
this(name, location, cost);
this.parent = parent;
this.level = level;
}
/**
* @return this node's name
*/
public String getNetworkName() {
return name;
}
/**
* Set this node's name, can be hostname or Ipaddress.
* @param networkName it's network name
*/
public void setNetworkName(String networkName) {
this.name = networkName;
this.path = getPath();
}
/**
* @return this node's network location
*/
public String getNetworkLocation() {
return location;
}
/**
* Set this node's network location.
* @param networkLocation it's network location
*/
@Override
public void setNetworkLocation(String networkLocation) {
this.location = networkLocation;
this.path = getPath();
}
/**
* @return this node's full path in network topology. It's the concatenation
* of location and name.
*/
public String getNetworkFullPath() {
return path;
}
/**
* @return this node's parent
*/
public InnerNode getParent() {
return parent;
}
/**
* @return this node's ancestor, generation 0 is itself, generation 1 is
* node's parent, and so on.
*/
public Node getAncestor(int generation) {
Preconditions.checkArgument(generation >= 0);
Node current = this;
while (generation > 0 && current != null) {
current = current.getParent();
generation--;
}
return current;
}
/**
* Set this node's parent.
*
* @param parent the parent
*/
public void setParent(InnerNode parent) {
this.parent = parent;
}
/**
* @return this node's level in the tree.
* E.g. the root of a tree returns 0 and its children return 1
*/
public int getLevel() {
return this.level;
}
/**
* Set this node's level in the tree.
*
* @param level the level
*/
public void setLevel(int level) {
this.level = level;
}
/**
* @return this node's cost when network traffic go through it.
* E.g. the cost of going cross a switch is 1, and cost of going through a
* datacenter is 5.
* Be default the cost of leaf datanode is 0, all other inner node is 1.
*/
public int getCost() {
return this.cost;
}
/** @return the leaf nodes number under this node. */
public int getNumOfLeaves() {
return 1;
}
/**
* Check if this node is an ancestor of node <i>node</i>. Ancestor includes
* itself and parents case;
* @param node a node
* @return true if this node is an ancestor of <i>node</i>
*/
public boolean isAncestor(Node node) {
return this.getNetworkFullPath().equals(PATH_SEPARATOR_STR) ||
node.getNetworkLocation().startsWith(this.getNetworkFullPath()) ||
node.getNetworkFullPath().equalsIgnoreCase(
this.getNetworkFullPath());
}
@Override
public boolean equals(Object to) {
if (to == null) {
return false;
}
if (this == to) {
return true;
}
return this.toString().equals(to.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
/**
* @return this node's path as its string representation
*/
@Override
public String toString() {
return getNetworkFullPath();
}
private String getPath() {
return this.location.equals(PATH_SEPARATOR_STR) ?
this.location + this.name :
this.location + PATH_SEPARATOR_STR + this.name;
}
}