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 }