001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.hadoop.hdfs.protocol; 019 020 import static org.apache.hadoop.hdfs.DFSUtil.percent2String; 021 022 import java.util.Date; 023 024 import org.apache.hadoop.classification.InterfaceAudience; 025 import org.apache.hadoop.classification.InterfaceStability; 026 import org.apache.hadoop.hdfs.DFSConfigKeys; 027 import org.apache.hadoop.hdfs.DFSUtil; 028 import org.apache.hadoop.net.NetUtils; 029 import org.apache.hadoop.net.NetworkTopology; 030 import org.apache.hadoop.net.Node; 031 import org.apache.hadoop.net.NodeBase; 032 import org.apache.hadoop.util.StringUtils; 033 import org.apache.hadoop.util.Time; 034 035 /** 036 * This class extends the primary identifier of a Datanode with ephemeral 037 * state, eg usage information, current administrative state, and the 038 * network location that is communicated to clients. 039 */ 040 @InterfaceAudience.Private 041 @InterfaceStability.Evolving 042 public class DatanodeInfo extends DatanodeID implements Node { 043 private long capacity; 044 private long dfsUsed; 045 private long remaining; 046 private long blockPoolUsed; 047 private long lastUpdate; 048 private int xceiverCount; 049 private String location = NetworkTopology.DEFAULT_RACK; 050 051 // Datanode administrative states 052 public enum AdminStates { 053 NORMAL("In Service"), 054 DECOMMISSION_INPROGRESS("Decommission In Progress"), 055 DECOMMISSIONED("Decommissioned"); 056 057 final String value; 058 059 AdminStates(final String v) { 060 this.value = v; 061 } 062 063 @Override 064 public String toString() { 065 return value; 066 } 067 068 public static AdminStates fromValue(final String value) { 069 for (AdminStates as : AdminStates.values()) { 070 if (as.value.equals(value)) return as; 071 } 072 return NORMAL; 073 } 074 } 075 076 protected AdminStates adminState; 077 078 public DatanodeInfo(DatanodeInfo from) { 079 super(from); 080 this.capacity = from.getCapacity(); 081 this.dfsUsed = from.getDfsUsed(); 082 this.remaining = from.getRemaining(); 083 this.blockPoolUsed = from.getBlockPoolUsed(); 084 this.lastUpdate = from.getLastUpdate(); 085 this.xceiverCount = from.getXceiverCount(); 086 this.location = from.getNetworkLocation(); 087 this.adminState = from.getAdminState(); 088 } 089 090 public DatanodeInfo(DatanodeID nodeID) { 091 super(nodeID); 092 this.capacity = 0L; 093 this.dfsUsed = 0L; 094 this.remaining = 0L; 095 this.blockPoolUsed = 0L; 096 this.lastUpdate = 0L; 097 this.xceiverCount = 0; 098 this.adminState = null; 099 } 100 101 public DatanodeInfo(DatanodeID nodeID, String location) { 102 this(nodeID); 103 this.location = location; 104 } 105 106 public DatanodeInfo(DatanodeID nodeID, String location, 107 final long capacity, final long dfsUsed, final long remaining, 108 final long blockPoolUsed, final long lastUpdate, final int xceiverCount, 109 final AdminStates adminState) { 110 this(nodeID.getIpAddr(), nodeID.getHostName(), nodeID.getStorageID(), nodeID.getXferPort(), 111 nodeID.getInfoPort(), nodeID.getIpcPort(), capacity, dfsUsed, remaining, 112 blockPoolUsed, lastUpdate, xceiverCount, location, adminState); 113 } 114 115 /** Constructor */ 116 public DatanodeInfo(final String ipAddr, final String hostName, 117 final String storageID, final int xferPort, final int infoPort, final int ipcPort, 118 final long capacity, final long dfsUsed, final long remaining, 119 final long blockPoolUsed, final long lastUpdate, final int xceiverCount, 120 final String networkLocation, final AdminStates adminState) { 121 super(ipAddr, hostName, storageID, xferPort, infoPort, ipcPort); 122 this.capacity = capacity; 123 this.dfsUsed = dfsUsed; 124 this.remaining = remaining; 125 this.blockPoolUsed = blockPoolUsed; 126 this.lastUpdate = lastUpdate; 127 this.xceiverCount = xceiverCount; 128 this.location = networkLocation; 129 this.adminState = adminState; 130 } 131 132 /** Network location name */ 133 @Override 134 public String getName() { 135 return getXferAddr(); 136 } 137 138 /** The raw capacity. */ 139 public long getCapacity() { return capacity; } 140 141 /** The used space by the data node. */ 142 public long getDfsUsed() { return dfsUsed; } 143 144 /** The used space by the block pool on data node. */ 145 public long getBlockPoolUsed() { return blockPoolUsed; } 146 147 /** The used space by the data node. */ 148 public long getNonDfsUsed() { 149 long nonDFSUsed = capacity - dfsUsed - remaining; 150 return nonDFSUsed < 0 ? 0 : nonDFSUsed; 151 } 152 153 /** The used space by the data node as percentage of present capacity */ 154 public float getDfsUsedPercent() { 155 return DFSUtil.getPercentUsed(dfsUsed, capacity); 156 } 157 158 /** The raw free space. */ 159 public long getRemaining() { return remaining; } 160 161 /** Used space by the block pool as percentage of present capacity */ 162 public float getBlockPoolUsedPercent() { 163 return DFSUtil.getPercentUsed(blockPoolUsed, capacity); 164 } 165 166 /** The remaining space as percentage of configured capacity. */ 167 public float getRemainingPercent() { 168 return DFSUtil.getPercentRemaining(remaining, capacity); 169 } 170 171 /** The time when this information was accurate. */ 172 public long getLastUpdate() { return lastUpdate; } 173 174 /** number of active connections */ 175 public int getXceiverCount() { return xceiverCount; } 176 177 /** Sets raw capacity. */ 178 public void setCapacity(long capacity) { 179 this.capacity = capacity; 180 } 181 182 /** Sets the used space for the datanode. */ 183 public void setDfsUsed(long dfsUsed) { 184 this.dfsUsed = dfsUsed; 185 } 186 187 /** Sets raw free space. */ 188 public void setRemaining(long remaining) { 189 this.remaining = remaining; 190 } 191 192 /** Sets block pool used space */ 193 public void setBlockPoolUsed(long bpUsed) { 194 this.blockPoolUsed = bpUsed; 195 } 196 197 /** Sets time when this information was accurate. */ 198 public void setLastUpdate(long lastUpdate) { 199 this.lastUpdate = lastUpdate; 200 } 201 202 /** Sets number of active connections */ 203 public void setXceiverCount(int xceiverCount) { 204 this.xceiverCount = xceiverCount; 205 } 206 207 /** network location */ 208 public synchronized String getNetworkLocation() {return location;} 209 210 /** Sets the network location */ 211 public synchronized void setNetworkLocation(String location) { 212 this.location = NodeBase.normalize(location); 213 } 214 215 /** A formatted string for reporting the status of the DataNode. */ 216 public String getDatanodeReport() { 217 StringBuilder buffer = new StringBuilder(); 218 long c = getCapacity(); 219 long r = getRemaining(); 220 long u = getDfsUsed(); 221 long nonDFSUsed = getNonDfsUsed(); 222 float usedPercent = getDfsUsedPercent(); 223 float remainingPercent = getRemainingPercent(); 224 String lookupName = NetUtils.getHostNameOfIP(getName()); 225 226 buffer.append("Name: "+ getName()); 227 if (lookupName != null) { 228 buffer.append(" (" + lookupName + ")"); 229 } 230 buffer.append("\n"); 231 buffer.append("Hostname: " + getHostName() + "\n"); 232 233 if (!NetworkTopology.DEFAULT_RACK.equals(location)) { 234 buffer.append("Rack: "+location+"\n"); 235 } 236 buffer.append("Decommission Status : "); 237 if (isDecommissioned()) { 238 buffer.append("Decommissioned\n"); 239 } else if (isDecommissionInProgress()) { 240 buffer.append("Decommission in progress\n"); 241 } else { 242 buffer.append("Normal\n"); 243 } 244 buffer.append("Configured Capacity: "+c+" ("+StringUtils.byteDesc(c)+")"+"\n"); 245 buffer.append("DFS Used: "+u+" ("+StringUtils.byteDesc(u)+")"+"\n"); 246 buffer.append("Non DFS Used: "+nonDFSUsed+" ("+StringUtils.byteDesc(nonDFSUsed)+")"+"\n"); 247 buffer.append("DFS Remaining: " +r+ " ("+StringUtils.byteDesc(r)+")"+"\n"); 248 buffer.append("DFS Used%: "+percent2String(usedPercent) + "\n"); 249 buffer.append("DFS Remaining%: "+percent2String(remainingPercent) + "\n"); 250 buffer.append("Last contact: "+new Date(lastUpdate)+"\n"); 251 return buffer.toString(); 252 } 253 254 /** A formatted string for printing the status of the DataNode. */ 255 public String dumpDatanode() { 256 StringBuilder buffer = new StringBuilder(); 257 long c = getCapacity(); 258 long r = getRemaining(); 259 long u = getDfsUsed(); 260 buffer.append(getName()); 261 if (!NetworkTopology.DEFAULT_RACK.equals(location)) { 262 buffer.append(" "+location); 263 } 264 if (isDecommissioned()) { 265 buffer.append(" DD"); 266 } else if (isDecommissionInProgress()) { 267 buffer.append(" DP"); 268 } else { 269 buffer.append(" IN"); 270 } 271 buffer.append(" " + c + "(" + StringUtils.byteDesc(c)+")"); 272 buffer.append(" " + u + "(" + StringUtils.byteDesc(u)+")"); 273 buffer.append(" " + percent2String(u/(double)c)); 274 buffer.append(" " + r + "(" + StringUtils.byteDesc(r)+")"); 275 buffer.append(" " + new Date(lastUpdate)); 276 return buffer.toString(); 277 } 278 279 /** 280 * Start decommissioning a node. 281 * old state. 282 */ 283 public void startDecommission() { 284 adminState = AdminStates.DECOMMISSION_INPROGRESS; 285 } 286 287 /** 288 * Stop decommissioning a node. 289 * old state. 290 */ 291 public void stopDecommission() { 292 adminState = null; 293 } 294 295 /** 296 * Returns true if the node is in the process of being decommissioned 297 */ 298 public boolean isDecommissionInProgress() { 299 return adminState == AdminStates.DECOMMISSION_INPROGRESS; 300 } 301 302 /** 303 * Returns true if the node has been decommissioned. 304 */ 305 public boolean isDecommissioned() { 306 return adminState == AdminStates.DECOMMISSIONED; 307 } 308 309 /** 310 * Sets the admin state to indicate that decommission is complete. 311 */ 312 public void setDecommissioned() { 313 adminState = AdminStates.DECOMMISSIONED; 314 } 315 316 /** 317 * Retrieves the admin state of this node. 318 */ 319 public AdminStates getAdminState() { 320 if (adminState == null) { 321 return AdminStates.NORMAL; 322 } 323 return adminState; 324 } 325 326 /** 327 * Check if the datanode is in stale state. Here if 328 * the namenode has not received heartbeat msg from a 329 * datanode for more than staleInterval (default value is 330 * {@link DFSConfigKeys#DFS_NAMENODE_STALE_DATANODE_INTERVAL_DEFAULT}), 331 * the datanode will be treated as stale node. 332 * 333 * @param staleInterval 334 * the time interval for marking the node as stale. If the last 335 * update time is beyond the given time interval, the node will be 336 * marked as stale. 337 * @return true if the node is stale 338 */ 339 public boolean isStale(long staleInterval) { 340 return (Time.now() - lastUpdate) >= staleInterval; 341 } 342 343 /** 344 * Sets the admin state of this node. 345 */ 346 protected void setAdminState(AdminStates newState) { 347 if (newState == AdminStates.NORMAL) { 348 adminState = null; 349 } 350 else { 351 adminState = newState; 352 } 353 } 354 355 private transient int level; //which level of the tree the node resides 356 private transient Node parent; //its parent 357 358 /** Return this node's parent */ 359 @Override 360 public Node getParent() { return parent; } 361 @Override 362 public void setParent(Node parent) {this.parent = parent;} 363 364 /** Return this node's level in the tree. 365 * E.g. the root of a tree returns 0 and its children return 1 366 */ 367 @Override 368 public int getLevel() { return level; } 369 @Override 370 public void setLevel(int level) {this.level = level;} 371 372 @Override 373 public int hashCode() { 374 // Super implementation is sufficient 375 return super.hashCode(); 376 } 377 378 @Override 379 public boolean equals(Object obj) { 380 // Sufficient to use super equality as datanodes are uniquely identified 381 // by DatanodeID 382 return (this == obj) || super.equals(obj); 383 } 384 }