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 */ 018package org.apache.hadoop.hdfs.protocol; 019 020import org.apache.hadoop.classification.InterfaceAudience; 021import org.apache.hadoop.classification.InterfaceStability; 022import org.apache.hadoop.hdfs.DFSConfigKeys; 023import org.apache.hadoop.hdfs.DFSUtil; 024import org.apache.hadoop.net.NetUtils; 025import org.apache.hadoop.net.NetworkTopology; 026import org.apache.hadoop.net.Node; 027import org.apache.hadoop.net.NodeBase; 028import org.apache.hadoop.util.StringUtils; 029import org.apache.hadoop.util.Time; 030 031import java.util.Date; 032import java.util.LinkedList; 033import java.util.List; 034 035import static org.apache.hadoop.hdfs.DFSUtil.percent2String; 036 037/** 038 * This class extends the primary identifier of a Datanode with ephemeral 039 * state, eg usage information, current administrative state, and the 040 * network location that is communicated to clients. 041 */ 042@InterfaceAudience.Private 043@InterfaceStability.Evolving 044public class DatanodeInfo extends DatanodeID implements Node { 045 private long capacity; 046 private long dfsUsed; 047 private long remaining; 048 private long blockPoolUsed; 049 private long cacheCapacity; 050 private long cacheUsed; 051 private long lastUpdate; 052 private long lastUpdateMonotonic; 053 private int xceiverCount; 054 private String location = NetworkTopology.DEFAULT_RACK; 055 private String softwareVersion; 056 private List<String> dependentHostNames = new LinkedList<String>(); 057 058 059 // Datanode administrative states 060 public enum AdminStates { 061 NORMAL("In Service"), 062 DECOMMISSION_INPROGRESS("Decommission In Progress"), 063 DECOMMISSIONED("Decommissioned"); 064 065 final String value; 066 067 AdminStates(final String v) { 068 this.value = v; 069 } 070 071 @Override 072 public String toString() { 073 return value; 074 } 075 076 public static AdminStates fromValue(final String value) { 077 for (AdminStates as : AdminStates.values()) { 078 if (as.value.equals(value)) return as; 079 } 080 return NORMAL; 081 } 082 } 083 084 protected AdminStates adminState; 085 086 public DatanodeInfo(DatanodeInfo from) { 087 super(from); 088 this.capacity = from.getCapacity(); 089 this.dfsUsed = from.getDfsUsed(); 090 this.remaining = from.getRemaining(); 091 this.blockPoolUsed = from.getBlockPoolUsed(); 092 this.cacheCapacity = from.getCacheCapacity(); 093 this.cacheUsed = from.getCacheUsed(); 094 this.lastUpdate = from.getLastUpdate(); 095 this.lastUpdateMonotonic = from.getLastUpdateMonotonic(); 096 this.xceiverCount = from.getXceiverCount(); 097 this.location = from.getNetworkLocation(); 098 this.adminState = from.getAdminState(); 099 } 100 101 public DatanodeInfo(DatanodeID nodeID) { 102 super(nodeID); 103 this.capacity = 0L; 104 this.dfsUsed = 0L; 105 this.remaining = 0L; 106 this.blockPoolUsed = 0L; 107 this.cacheCapacity = 0L; 108 this.cacheUsed = 0L; 109 this.lastUpdate = 0L; 110 this.lastUpdateMonotonic = 0L; 111 this.xceiverCount = 0; 112 this.adminState = null; 113 } 114 115 public DatanodeInfo(DatanodeID nodeID, String location) { 116 this(nodeID); 117 this.location = location; 118 } 119 120 public DatanodeInfo(DatanodeID nodeID, String location, 121 final long capacity, final long dfsUsed, final long remaining, 122 final long blockPoolUsed, final long cacheCapacity, final long cacheUsed, 123 final long lastUpdate, final long lastUpdateMonotonic, 124 final int xceiverCount, final AdminStates adminState) { 125 this(nodeID.getIpAddr(), nodeID.getHostName(), nodeID.getDatanodeUuid(), 126 nodeID.getXferPort(), nodeID.getInfoPort(), nodeID.getInfoSecurePort(), 127 nodeID.getIpcPort(), capacity, dfsUsed, remaining, blockPoolUsed, 128 cacheCapacity, cacheUsed, lastUpdate, lastUpdateMonotonic, 129 xceiverCount, location, adminState); 130 } 131 132 /** Constructor */ 133 public DatanodeInfo(final String ipAddr, final String hostName, 134 final String datanodeUuid, final int xferPort, final int infoPort, 135 final int infoSecurePort, final int ipcPort, 136 final long capacity, final long dfsUsed, final long remaining, 137 final long blockPoolUsed, final long cacheCapacity, final long cacheUsed, 138 final long lastUpdate, final long lastUpdateMonotonic, 139 final int xceiverCount, final String networkLocation, 140 final AdminStates adminState) { 141 super(ipAddr, hostName, datanodeUuid, xferPort, infoPort, 142 infoSecurePort, ipcPort); 143 this.capacity = capacity; 144 this.dfsUsed = dfsUsed; 145 this.remaining = remaining; 146 this.blockPoolUsed = blockPoolUsed; 147 this.cacheCapacity = cacheCapacity; 148 this.cacheUsed = cacheUsed; 149 this.lastUpdate = lastUpdate; 150 this.lastUpdateMonotonic = lastUpdateMonotonic; 151 this.xceiverCount = xceiverCount; 152 this.location = networkLocation; 153 this.adminState = adminState; 154 } 155 156 /** Network location name */ 157 @Override 158 public String getName() { 159 return getXferAddr(); 160 } 161 162 /** The raw capacity. */ 163 public long getCapacity() { return capacity; } 164 165 /** The used space by the data node. */ 166 public long getDfsUsed() { return dfsUsed; } 167 168 /** The used space by the block pool on data node. */ 169 public long getBlockPoolUsed() { return blockPoolUsed; } 170 171 /** The used space by the data node. */ 172 public long getNonDfsUsed() { 173 long nonDFSUsed = capacity - dfsUsed - remaining; 174 return nonDFSUsed < 0 ? 0 : nonDFSUsed; 175 } 176 177 /** The used space by the data node as percentage of present capacity */ 178 public float getDfsUsedPercent() { 179 return DFSUtil.getPercentUsed(dfsUsed, capacity); 180 } 181 182 /** The raw free space. */ 183 public long getRemaining() { return remaining; } 184 185 /** Used space by the block pool as percentage of present capacity */ 186 public float getBlockPoolUsedPercent() { 187 return DFSUtil.getPercentUsed(blockPoolUsed, capacity); 188 } 189 190 /** The remaining space as percentage of configured capacity. */ 191 public float getRemainingPercent() { 192 return DFSUtil.getPercentRemaining(remaining, capacity); 193 } 194 195 /** 196 * @return Amount of cache capacity in bytes 197 */ 198 public long getCacheCapacity() { 199 return cacheCapacity; 200 } 201 202 /** 203 * @return Amount of cache used in bytes 204 */ 205 public long getCacheUsed() { 206 return cacheUsed; 207 } 208 209 /** 210 * @return Cache used as a percentage of the datanode's total cache capacity 211 */ 212 public float getCacheUsedPercent() { 213 return DFSUtil.getPercentUsed(cacheUsed, cacheCapacity); 214 } 215 216 /** 217 * @return Amount of cache remaining in bytes 218 */ 219 public long getCacheRemaining() { 220 return cacheCapacity - cacheUsed; 221 } 222 223 /** 224 * @return Cache remaining as a percentage of the datanode's total cache 225 * capacity 226 */ 227 public float getCacheRemainingPercent() { 228 return DFSUtil.getPercentRemaining(getCacheRemaining(), cacheCapacity); 229 } 230 231 /** 232 * Get the last update timestamp. 233 * Return value is suitable for Date conversion. 234 */ 235 public long getLastUpdate() { return lastUpdate; } 236 237 /** 238 * The time when this information was accurate. <br> 239 * Ps: So return value is ideal for calculation of time differences. 240 * Should not be used to convert to Date. 241 */ 242 public long getLastUpdateMonotonic() { return lastUpdateMonotonic;} 243 244 /** 245 * Set lastUpdate monotonic time 246 */ 247 public void setLastUpdateMonotonic(long lastUpdateMonotonic) { 248 this.lastUpdateMonotonic = lastUpdateMonotonic; 249 } 250 251 /** number of active connections */ 252 public int getXceiverCount() { return xceiverCount; } 253 254 /** Sets raw capacity. */ 255 public void setCapacity(long capacity) { 256 this.capacity = capacity; 257 } 258 259 /** Sets the used space for the datanode. */ 260 public void setDfsUsed(long dfsUsed) { 261 this.dfsUsed = dfsUsed; 262 } 263 264 /** Sets raw free space. */ 265 public void setRemaining(long remaining) { 266 this.remaining = remaining; 267 } 268 269 /** Sets block pool used space */ 270 public void setBlockPoolUsed(long bpUsed) { 271 this.blockPoolUsed = bpUsed; 272 } 273 274 /** Sets cache capacity. */ 275 public void setCacheCapacity(long cacheCapacity) { 276 this.cacheCapacity = cacheCapacity; 277 } 278 279 /** Sets cache used. */ 280 public void setCacheUsed(long cacheUsed) { 281 this.cacheUsed = cacheUsed; 282 } 283 284 /** Sets time when this information was accurate. */ 285 public void setLastUpdate(long lastUpdate) { 286 this.lastUpdate = lastUpdate; 287 } 288 289 /** Sets number of active connections */ 290 public void setXceiverCount(int xceiverCount) { 291 this.xceiverCount = xceiverCount; 292 } 293 294 /** network location */ 295 public synchronized String getNetworkLocation() {return location;} 296 297 /** Sets the network location */ 298 public synchronized void setNetworkLocation(String location) { 299 this.location = NodeBase.normalize(location); 300 } 301 302 /** Add a hostname to a list of network dependencies */ 303 public void addDependentHostName(String hostname) { 304 dependentHostNames.add(hostname); 305 } 306 307 /** List of Network dependencies */ 308 public List<String> getDependentHostNames() { 309 return dependentHostNames; 310 } 311 312 /** Sets the network dependencies */ 313 public void setDependentHostNames(List<String> dependencyList) { 314 dependentHostNames = dependencyList; 315 } 316 317 /** A formatted string for reporting the status of the DataNode. */ 318 public String getDatanodeReport() { 319 StringBuilder buffer = new StringBuilder(); 320 long c = getCapacity(); 321 long r = getRemaining(); 322 long u = getDfsUsed(); 323 long nonDFSUsed = getNonDfsUsed(); 324 float usedPercent = getDfsUsedPercent(); 325 float remainingPercent = getRemainingPercent(); 326 long cc = getCacheCapacity(); 327 long cr = getCacheRemaining(); 328 long cu = getCacheUsed(); 329 float cacheUsedPercent = getCacheUsedPercent(); 330 float cacheRemainingPercent = getCacheRemainingPercent(); 331 String lookupName = NetUtils.getHostNameOfIP(getName()); 332 333 buffer.append("Name: "+ getName()); 334 if (lookupName != null) { 335 buffer.append(" (" + lookupName + ")"); 336 } 337 buffer.append("\n"); 338 buffer.append("Hostname: " + getHostName() + "\n"); 339 340 if (!NetworkTopology.DEFAULT_RACK.equals(location)) { 341 buffer.append("Rack: "+location+"\n"); 342 } 343 buffer.append("Decommission Status : "); 344 if (isDecommissioned()) { 345 buffer.append("Decommissioned\n"); 346 } else if (isDecommissionInProgress()) { 347 buffer.append("Decommission in progress\n"); 348 } else { 349 buffer.append("Normal\n"); 350 } 351 buffer.append("Configured Capacity: "+c+" ("+StringUtils.byteDesc(c)+")"+"\n"); 352 buffer.append("DFS Used: "+u+" ("+StringUtils.byteDesc(u)+")"+"\n"); 353 buffer.append("Non DFS Used: "+nonDFSUsed+" ("+StringUtils.byteDesc(nonDFSUsed)+")"+"\n"); 354 buffer.append("DFS Remaining: " +r+ " ("+StringUtils.byteDesc(r)+")"+"\n"); 355 buffer.append("DFS Used%: "+percent2String(usedPercent) + "\n"); 356 buffer.append("DFS Remaining%: "+percent2String(remainingPercent) + "\n"); 357 buffer.append("Configured Cache Capacity: "+cc+" ("+StringUtils.byteDesc(cc)+")"+"\n"); 358 buffer.append("Cache Used: "+cu+" ("+StringUtils.byteDesc(cu)+")"+"\n"); 359 buffer.append("Cache Remaining: " +cr+ " ("+StringUtils.byteDesc(cr)+")"+"\n"); 360 buffer.append("Cache Used%: "+percent2String(cacheUsedPercent) + "\n"); 361 buffer.append("Cache Remaining%: "+percent2String(cacheRemainingPercent) + "\n"); 362 buffer.append("Xceivers: "+getXceiverCount()+"\n"); 363 buffer.append("Last contact: "+new Date(lastUpdate)+"\n"); 364 return buffer.toString(); 365 } 366 367 /** A formatted string for printing the status of the DataNode. */ 368 public String dumpDatanode() { 369 StringBuilder buffer = new StringBuilder(); 370 long c = getCapacity(); 371 long r = getRemaining(); 372 long u = getDfsUsed(); 373 float usedPercent = getDfsUsedPercent(); 374 long cc = getCacheCapacity(); 375 long cr = getCacheRemaining(); 376 long cu = getCacheUsed(); 377 float cacheUsedPercent = getCacheUsedPercent(); 378 buffer.append(getName()); 379 if (!NetworkTopology.DEFAULT_RACK.equals(location)) { 380 buffer.append(" "+location); 381 } 382 if (isDecommissioned()) { 383 buffer.append(" DD"); 384 } else if (isDecommissionInProgress()) { 385 buffer.append(" DP"); 386 } else { 387 buffer.append(" IN"); 388 } 389 buffer.append(" " + c + "(" + StringUtils.byteDesc(c)+")"); 390 buffer.append(" " + u + "(" + StringUtils.byteDesc(u)+")"); 391 buffer.append(" " + percent2String(usedPercent)); 392 buffer.append(" " + r + "(" + StringUtils.byteDesc(r)+")"); 393 buffer.append(" " + cc + "(" + StringUtils.byteDesc(cc)+")"); 394 buffer.append(" " + cu + "(" + StringUtils.byteDesc(cu)+")"); 395 buffer.append(" " + percent2String(cacheUsedPercent)); 396 buffer.append(" " + cr + "(" + StringUtils.byteDesc(cr)+")"); 397 buffer.append(" " + new Date(lastUpdate)); 398 return buffer.toString(); 399 } 400 401 /** 402 * Start decommissioning a node. 403 * old state. 404 */ 405 public void startDecommission() { 406 adminState = AdminStates.DECOMMISSION_INPROGRESS; 407 } 408 409 /** 410 * Stop decommissioning a node. 411 * old state. 412 */ 413 public void stopDecommission() { 414 adminState = null; 415 } 416 417 /** 418 * Returns true if the node is in the process of being decommissioned 419 */ 420 public boolean isDecommissionInProgress() { 421 return adminState == AdminStates.DECOMMISSION_INPROGRESS; 422 } 423 424 /** 425 * Returns true if the node has been decommissioned. 426 */ 427 public boolean isDecommissioned() { 428 return adminState == AdminStates.DECOMMISSIONED; 429 } 430 431 /** 432 * Sets the admin state to indicate that decommission is complete. 433 */ 434 public void setDecommissioned() { 435 adminState = AdminStates.DECOMMISSIONED; 436 } 437 438 /** 439 * Retrieves the admin state of this node. 440 */ 441 public AdminStates getAdminState() { 442 if (adminState == null) { 443 return AdminStates.NORMAL; 444 } 445 return adminState; 446 } 447 448 /** 449 * Check if the datanode is in stale state. Here if 450 * the namenode has not received heartbeat msg from a 451 * datanode for more than staleInterval (default value is 452 * {@link DFSConfigKeys#DFS_NAMENODE_STALE_DATANODE_INTERVAL_DEFAULT}), 453 * the datanode will be treated as stale node. 454 * 455 * @param staleInterval 456 * the time interval for marking the node as stale. If the last 457 * update time is beyond the given time interval, the node will be 458 * marked as stale. 459 * @return true if the node is stale 460 */ 461 public boolean isStale(long staleInterval) { 462 return (Time.monotonicNow() - lastUpdateMonotonic) >= staleInterval; 463 } 464 465 /** 466 * Sets the admin state of this node. 467 */ 468 protected void setAdminState(AdminStates newState) { 469 if (newState == AdminStates.NORMAL) { 470 adminState = null; 471 } 472 else { 473 adminState = newState; 474 } 475 } 476 477 private transient int level; //which level of the tree the node resides 478 private transient Node parent; //its parent 479 480 /** Return this node's parent */ 481 @Override 482 public Node getParent() { return parent; } 483 @Override 484 public void setParent(Node parent) {this.parent = parent;} 485 486 /** Return this node's level in the tree. 487 * E.g. the root of a tree returns 0 and its children return 1 488 */ 489 @Override 490 public int getLevel() { return level; } 491 @Override 492 public void setLevel(int level) {this.level = level;} 493 494 @Override 495 public int hashCode() { 496 // Super implementation is sufficient 497 return super.hashCode(); 498 } 499 500 @Override 501 public boolean equals(Object obj) { 502 // Sufficient to use super equality as datanodes are uniquely identified 503 // by DatanodeID 504 return (this == obj) || super.equals(obj); 505 } 506 507 public String getSoftwareVersion() { 508 return softwareVersion; 509 } 510 511 public void setSoftwareVersion(String softwareVersion) { 512 this.softwareVersion = softwareVersion; 513 } 514}