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