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    import java.util.LinkedList;
033    import java.util.List;
034    
035    import 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
044    public 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    }