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