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