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