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