1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.hdfs.protocol;
19 
20 import org.apache.hadoop.classification.InterfaceAudience;
21 import org.apache.hadoop.classification.InterfaceStability;
22 import org.apache.hadoop.hdfs.DFSConfigKeys;
23 import org.apache.hadoop.hdfs.DFSUtil;
24 import org.apache.hadoop.net.NetUtils;
25 import org.apache.hadoop.net.NetworkTopology;
26 import org.apache.hadoop.net.Node;
27 import org.apache.hadoop.net.NodeBase;
28 import org.apache.hadoop.util.StringUtils;
29 import org.apache.hadoop.util.Time;
30 
31 import java.util.Date;
32 import java.util.LinkedList;
33 import java.util.List;
34 
35 import static org.apache.hadoop.hdfs.DFSUtil.percent2String;
36 
37 /**
38  * This class extends the primary identifier of a Datanode with ephemeral
39  * state, eg usage information, current administrative state, and the
40  * network location that is communicated to clients.
41  */
42 @InterfaceAudience.Private
43 @InterfaceStability.Evolving
44 public class DatanodeInfo extends DatanodeID implements Node {
45   private long capacity;
46   private long dfsUsed;
47   private long remaining;
48   private long blockPoolUsed;
49   private long cacheCapacity;
50   private long cacheUsed;
51   private long lastUpdate;
52   private long lastUpdateMonotonic;
53   private int xceiverCount;
54   private String location = NetworkTopology.DEFAULT_RACK;
55   private String softwareVersion;
56   private List<String> dependentHostNames = new LinkedList<String>();
57 
58 
59   // Datanode administrative states
60   public enum AdminStates {
61     NORMAL("In Service"),
62     DECOMMISSION_INPROGRESS("Decommission In Progress"),
63     DECOMMISSIONED("Decommissioned");
64 
65     final String value;
66 
AdminStates(final String v)67     AdminStates(final String v) {
68       this.value = v;
69     }
70 
71     @Override
toString()72     public String toString() {
73       return value;
74     }
75 
fromValue(final String value)76     public static AdminStates fromValue(final String value) {
77       for (AdminStates as : AdminStates.values()) {
78         if (as.value.equals(value)) return as;
79       }
80       return NORMAL;
81     }
82   }
83 
84   protected AdminStates adminState;
85 
DatanodeInfo(DatanodeInfo from)86   public DatanodeInfo(DatanodeInfo from) {
87     super(from);
88     this.capacity = from.getCapacity();
89     this.dfsUsed = from.getDfsUsed();
90     this.remaining = from.getRemaining();
91     this.blockPoolUsed = from.getBlockPoolUsed();
92     this.cacheCapacity = from.getCacheCapacity();
93     this.cacheUsed = from.getCacheUsed();
94     this.lastUpdate = from.getLastUpdate();
95     this.lastUpdateMonotonic = from.getLastUpdateMonotonic();
96     this.xceiverCount = from.getXceiverCount();
97     this.location = from.getNetworkLocation();
98     this.adminState = from.getAdminState();
99   }
100 
DatanodeInfo(DatanodeID nodeID)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 
DatanodeInfo(DatanodeID nodeID, String location)115   public DatanodeInfo(DatanodeID nodeID, String location) {
116     this(nodeID);
117     this.location = location;
118   }
119 
DatanodeInfo(DatanodeID nodeID, String location, final long capacity, final long dfsUsed, final long remaining, final long blockPoolUsed, final long cacheCapacity, final long cacheUsed, final long lastUpdate, final long lastUpdateMonotonic, final int xceiverCount, final AdminStates adminState)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 */
DatanodeInfo(final String ipAddr, final String hostName, final String datanodeUuid, final int xferPort, final int infoPort, final int infoSecurePort, final int ipcPort, final long capacity, final long dfsUsed, final long remaining, final long blockPoolUsed, final long cacheCapacity, final long cacheUsed, final long lastUpdate, final long lastUpdateMonotonic, final int xceiverCount, final String networkLocation, final AdminStates adminState)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
getName()158   public String getName() {
159     return getXferAddr();
160   }
161 
162   /** The raw capacity. */
getCapacity()163   public long getCapacity() { return capacity; }
164 
165   /** The used space by the data node. */
getDfsUsed()166   public long getDfsUsed() { return dfsUsed; }
167 
168   /** The used space by the block pool on data node. */
getBlockPoolUsed()169   public long getBlockPoolUsed() { return blockPoolUsed; }
170 
171   /** The used space by the data node. */
getNonDfsUsed()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 */
getDfsUsedPercent()178   public float getDfsUsedPercent() {
179     return DFSUtil.getPercentUsed(dfsUsed, capacity);
180   }
181 
182   /** The raw free space. */
getRemaining()183   public long getRemaining() { return remaining; }
184 
185   /** Used space by the block pool as percentage of present capacity */
getBlockPoolUsedPercent()186   public float getBlockPoolUsedPercent() {
187     return DFSUtil.getPercentUsed(blockPoolUsed, capacity);
188   }
189 
190   /** The remaining space as percentage of configured capacity. */
getRemainingPercent()191   public float getRemainingPercent() {
192     return DFSUtil.getPercentRemaining(remaining, capacity);
193   }
194 
195   /**
196    * @return Amount of cache capacity in bytes
197    */
getCacheCapacity()198   public long getCacheCapacity() {
199     return cacheCapacity;
200   }
201 
202   /**
203    * @return Amount of cache used in bytes
204    */
getCacheUsed()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    */
getCacheUsedPercent()212   public float getCacheUsedPercent() {
213     return DFSUtil.getPercentUsed(cacheUsed, cacheCapacity);
214   }
215 
216   /**
217    * @return Amount of cache remaining in bytes
218    */
getCacheRemaining()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    */
getCacheRemainingPercent()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    */
getLastUpdate()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    */
getLastUpdateMonotonic()242   public long getLastUpdateMonotonic() { return lastUpdateMonotonic;}
243 
244   /**
245    * Set lastUpdate monotonic time
246    */
setLastUpdateMonotonic(long lastUpdateMonotonic)247   public void setLastUpdateMonotonic(long lastUpdateMonotonic) {
248     this.lastUpdateMonotonic = lastUpdateMonotonic;
249   }
250 
251   /** number of active connections */
getXceiverCount()252   public int getXceiverCount() { return xceiverCount; }
253 
254   /** Sets raw capacity. */
setCapacity(long capacity)255   public void setCapacity(long capacity) {
256     this.capacity = capacity;
257   }
258 
259   /** Sets the used space for the datanode. */
setDfsUsed(long dfsUsed)260   public void setDfsUsed(long dfsUsed) {
261     this.dfsUsed = dfsUsed;
262   }
263 
264   /** Sets raw free space. */
setRemaining(long remaining)265   public void setRemaining(long remaining) {
266     this.remaining = remaining;
267   }
268 
269   /** Sets block pool used space */
setBlockPoolUsed(long bpUsed)270   public void setBlockPoolUsed(long bpUsed) {
271     this.blockPoolUsed = bpUsed;
272   }
273 
274   /** Sets cache capacity. */
setCacheCapacity(long cacheCapacity)275   public void setCacheCapacity(long cacheCapacity) {
276     this.cacheCapacity = cacheCapacity;
277   }
278 
279   /** Sets cache used. */
setCacheUsed(long cacheUsed)280   public void setCacheUsed(long cacheUsed) {
281     this.cacheUsed = cacheUsed;
282   }
283 
284   /** Sets time when this information was accurate. */
setLastUpdate(long lastUpdate)285   public void setLastUpdate(long lastUpdate) {
286     this.lastUpdate = lastUpdate;
287   }
288 
289   /** Sets number of active connections */
setXceiverCount(int xceiverCount)290   public void setXceiverCount(int xceiverCount) {
291     this.xceiverCount = xceiverCount;
292   }
293 
294   /** network location */
getNetworkLocation()295   public synchronized String getNetworkLocation() {return location;}
296 
297   /** Sets the network location */
setNetworkLocation(String 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 */
addDependentHostName(String hostname)303   public void addDependentHostName(String hostname) {
304     dependentHostNames.add(hostname);
305   }
306 
307   /** List of Network dependencies */
getDependentHostNames()308   public List<String> getDependentHostNames() {
309     return dependentHostNames;
310   }
311 
312   /** Sets the network dependencies */
setDependentHostNames(List<String> dependencyList)313   public void setDependentHostNames(List<String> dependencyList) {
314     dependentHostNames = dependencyList;
315   }
316 
317   /** A formatted string for reporting the status of the DataNode. */
getDatanodeReport()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. */
dumpDatanode()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    */
startDecommission()405   public void startDecommission() {
406     adminState = AdminStates.DECOMMISSION_INPROGRESS;
407   }
408 
409   /**
410    * Stop decommissioning a node.
411    * old state.
412    */
stopDecommission()413   public void stopDecommission() {
414     adminState = null;
415   }
416 
417   /**
418    * Returns true if the node is in the process of being decommissioned
419    */
isDecommissionInProgress()420   public boolean isDecommissionInProgress() {
421     return adminState == AdminStates.DECOMMISSION_INPROGRESS;
422   }
423 
424   /**
425    * Returns true if the node has been decommissioned.
426    */
isDecommissioned()427   public boolean isDecommissioned() {
428     return adminState == AdminStates.DECOMMISSIONED;
429   }
430 
431   /**
432    * Sets the admin state to indicate that decommission is complete.
433    */
setDecommissioned()434   public void setDecommissioned() {
435     adminState = AdminStates.DECOMMISSIONED;
436   }
437 
438   /**
439    * Retrieves the admin state of this node.
440    */
getAdminState()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    */
isStale(long staleInterval)461   public boolean isStale(long staleInterval) {
462     return (Time.monotonicNow() - lastUpdateMonotonic) >= staleInterval;
463   }
464 
465   /**
466    * Sets the admin state of this node.
467    */
setAdminState(AdminStates newState)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
getParent()482   public Node getParent() { return parent; }
483   @Override
setParent(Node parent)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
getLevel()490   public int getLevel() { return level; }
491   @Override
setLevel(int level)492   public void setLevel(int level) {this.level = level;}
493 
494   @Override
hashCode()495   public int hashCode() {
496     // Super implementation is sufficient
497     return super.hashCode();
498   }
499 
500   @Override
equals(Object obj)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 
getSoftwareVersion()507   public String getSoftwareVersion() {
508     return softwareVersion;
509   }
510 
setSoftwareVersion(String softwareVersion)511   public void setSoftwareVersion(String softwareVersion) {
512     this.softwareVersion = softwareVersion;
513   }
514 }
515