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 }