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 cacheCapacity;
048 private long cacheUsed;
049 private long lastUpdate;
050 private int xceiverCount;
051 private String location = NetworkTopology.DEFAULT_RACK;
052 private String softwareVersion;
053
054 // Datanode administrative states
055 public enum AdminStates {
056 NORMAL("In Service"),
057 DECOMMISSION_INPROGRESS("Decommission In Progress"),
058 DECOMMISSIONED("Decommissioned");
059
060 final String value;
061
062 AdminStates(final String v) {
063 this.value = v;
064 }
065
066 @Override
067 public String toString() {
068 return value;
069 }
070
071 public static AdminStates fromValue(final String value) {
072 for (AdminStates as : AdminStates.values()) {
073 if (as.value.equals(value)) return as;
074 }
075 return NORMAL;
076 }
077 }
078
079 protected AdminStates adminState;
080
081 public DatanodeInfo(DatanodeInfo from) {
082 super(from);
083 this.capacity = from.getCapacity();
084 this.dfsUsed = from.getDfsUsed();
085 this.remaining = from.getRemaining();
086 this.blockPoolUsed = from.getBlockPoolUsed();
087 this.cacheCapacity = from.getCacheCapacity();
088 this.cacheUsed = from.getCacheUsed();
089 this.lastUpdate = from.getLastUpdate();
090 this.xceiverCount = from.getXceiverCount();
091 this.location = from.getNetworkLocation();
092 this.adminState = from.getAdminState();
093 }
094
095 public DatanodeInfo(DatanodeID nodeID) {
096 super(nodeID);
097 this.capacity = 0L;
098 this.dfsUsed = 0L;
099 this.remaining = 0L;
100 this.blockPoolUsed = 0L;
101 this.cacheCapacity = 0L;
102 this.cacheUsed = 0L;
103 this.lastUpdate = 0L;
104 this.xceiverCount = 0;
105 this.adminState = null;
106 }
107
108 public DatanodeInfo(DatanodeID nodeID, String location) {
109 this(nodeID);
110 this.location = location;
111 }
112
113 public DatanodeInfo(DatanodeID nodeID, String location,
114 final long capacity, final long dfsUsed, final long remaining,
115 final long blockPoolUsed, final long cacheCapacity, final long cacheUsed,
116 final long lastUpdate, final int xceiverCount,
117 final AdminStates adminState) {
118 this(nodeID.getIpAddr(), nodeID.getHostName(), nodeID.getDatanodeUuid(),
119 nodeID.getXferPort(), nodeID.getInfoPort(), nodeID.getInfoSecurePort(),
120 nodeID.getIpcPort(), capacity, dfsUsed, remaining, blockPoolUsed,
121 cacheCapacity, cacheUsed, lastUpdate, xceiverCount, location, adminState);
122 }
123
124 /** Constructor */
125 public DatanodeInfo(final String ipAddr, final String hostName,
126 final String datanodeUuid, final int xferPort, final int infoPort,
127 final int infoSecurePort, final int ipcPort,
128 final long capacity, final long dfsUsed, final long remaining,
129 final long blockPoolUsed, final long cacheCapacity, final long cacheUsed,
130 final long lastUpdate, final int xceiverCount,
131 final String networkLocation, final AdminStates adminState) {
132 super(ipAddr, hostName, datanodeUuid, xferPort, infoPort,
133 infoSecurePort, ipcPort);
134 this.capacity = capacity;
135 this.dfsUsed = dfsUsed;
136 this.remaining = remaining;
137 this.blockPoolUsed = blockPoolUsed;
138 this.cacheCapacity = cacheCapacity;
139 this.cacheUsed = cacheUsed;
140 this.lastUpdate = lastUpdate;
141 this.xceiverCount = xceiverCount;
142 this.location = networkLocation;
143 this.adminState = adminState;
144 }
145
146 /** Network location name */
147 @Override
148 public String getName() {
149 return getXferAddr();
150 }
151
152 /** The raw capacity. */
153 public long getCapacity() { return capacity; }
154
155 /** The used space by the data node. */
156 public long getDfsUsed() { return dfsUsed; }
157
158 /** The used space by the block pool on data node. */
159 public long getBlockPoolUsed() { return blockPoolUsed; }
160
161 /** The used space by the data node. */
162 public long getNonDfsUsed() {
163 long nonDFSUsed = capacity - dfsUsed - remaining;
164 return nonDFSUsed < 0 ? 0 : nonDFSUsed;
165 }
166
167 /** The used space by the data node as percentage of present capacity */
168 public float getDfsUsedPercent() {
169 return DFSUtil.getPercentUsed(dfsUsed, capacity);
170 }
171
172 /** The raw free space. */
173 public long getRemaining() { return remaining; }
174
175 /** Used space by the block pool as percentage of present capacity */
176 public float getBlockPoolUsedPercent() {
177 return DFSUtil.getPercentUsed(blockPoolUsed, capacity);
178 }
179
180 /** The remaining space as percentage of configured capacity. */
181 public float getRemainingPercent() {
182 return DFSUtil.getPercentRemaining(remaining, capacity);
183 }
184
185 /**
186 * @return Amount of cache capacity in bytes
187 */
188 public long getCacheCapacity() {
189 return cacheCapacity;
190 }
191
192 /**
193 * @return Amount of cache used in bytes
194 */
195 public long getCacheUsed() {
196 return cacheUsed;
197 }
198
199 /**
200 * @return Cache used as a percentage of the datanode's total cache capacity
201 */
202 public float getCacheUsedPercent() {
203 return DFSUtil.getPercentUsed(cacheUsed, cacheCapacity);
204 }
205
206 /**
207 * @return Amount of cache remaining in bytes
208 */
209 public long getCacheRemaining() {
210 return cacheCapacity - cacheUsed;
211 }
212
213 /**
214 * @return Cache remaining as a percentage of the datanode's total cache
215 * capacity
216 */
217 public float getCacheRemainingPercent() {
218 return DFSUtil.getPercentRemaining(getCacheRemaining(), cacheCapacity);
219 }
220
221 /** The time when this information was accurate. */
222 public long getLastUpdate() { return lastUpdate; }
223
224 /** number of active connections */
225 public int getXceiverCount() { return xceiverCount; }
226
227 /** Sets raw capacity. */
228 public void setCapacity(long capacity) {
229 this.capacity = capacity;
230 }
231
232 /** Sets the used space for the datanode. */
233 public void setDfsUsed(long dfsUsed) {
234 this.dfsUsed = dfsUsed;
235 }
236
237 /** Sets raw free space. */
238 public void setRemaining(long remaining) {
239 this.remaining = remaining;
240 }
241
242 /** Sets block pool used space */
243 public void setBlockPoolUsed(long bpUsed) {
244 this.blockPoolUsed = bpUsed;
245 }
246
247 /** Sets cache capacity. */
248 public void setCacheCapacity(long cacheCapacity) {
249 this.cacheCapacity = cacheCapacity;
250 }
251
252 /** Sets cache used. */
253 public void setCacheUsed(long cacheUsed) {
254 this.cacheUsed = cacheUsed;
255 }
256
257 /** Sets time when this information was accurate. */
258 public void setLastUpdate(long lastUpdate) {
259 this.lastUpdate = lastUpdate;
260 }
261
262 /** Sets number of active connections */
263 public void setXceiverCount(int xceiverCount) {
264 this.xceiverCount = xceiverCount;
265 }
266
267 /** network location */
268 public synchronized String getNetworkLocation() {return location;}
269
270 /** Sets the network location */
271 public synchronized void setNetworkLocation(String location) {
272 this.location = NodeBase.normalize(location);
273 }
274
275 /** A formatted string for reporting the status of the DataNode. */
276 public String getDatanodeReport() {
277 StringBuilder buffer = new StringBuilder();
278 long c = getCapacity();
279 long r = getRemaining();
280 long u = getDfsUsed();
281 long nonDFSUsed = getNonDfsUsed();
282 float usedPercent = getDfsUsedPercent();
283 float remainingPercent = getRemainingPercent();
284 long cc = getCacheCapacity();
285 long cr = getCacheRemaining();
286 long cu = getCacheUsed();
287 float cacheUsedPercent = getCacheUsedPercent();
288 float cacheRemainingPercent = getCacheRemainingPercent();
289 String lookupName = NetUtils.getHostNameOfIP(getName());
290
291 buffer.append("Name: "+ getName());
292 if (lookupName != null) {
293 buffer.append(" (" + lookupName + ")");
294 }
295 buffer.append("\n");
296 buffer.append("Hostname: " + getHostName() + "\n");
297
298 if (!NetworkTopology.DEFAULT_RACK.equals(location)) {
299 buffer.append("Rack: "+location+"\n");
300 }
301 buffer.append("Decommission Status : ");
302 if (isDecommissioned()) {
303 buffer.append("Decommissioned\n");
304 } else if (isDecommissionInProgress()) {
305 buffer.append("Decommission in progress\n");
306 } else {
307 buffer.append("Normal\n");
308 }
309 buffer.append("Configured Capacity: "+c+" ("+StringUtils.byteDesc(c)+")"+"\n");
310 buffer.append("DFS Used: "+u+" ("+StringUtils.byteDesc(u)+")"+"\n");
311 buffer.append("Non DFS Used: "+nonDFSUsed+" ("+StringUtils.byteDesc(nonDFSUsed)+")"+"\n");
312 buffer.append("DFS Remaining: " +r+ " ("+StringUtils.byteDesc(r)+")"+"\n");
313 buffer.append("DFS Used%: "+percent2String(usedPercent) + "\n");
314 buffer.append("DFS Remaining%: "+percent2String(remainingPercent) + "\n");
315 buffer.append("Configured Cache Capacity: "+cc+" ("+StringUtils.byteDesc(cc)+")"+"\n");
316 buffer.append("Cache Used: "+cu+" ("+StringUtils.byteDesc(cu)+")"+"\n");
317 buffer.append("Cache Remaining: " +cr+ " ("+StringUtils.byteDesc(cr)+")"+"\n");
318 buffer.append("Cache Used%: "+percent2String(cacheUsedPercent) + "\n");
319 buffer.append("Cache Remaining%: "+percent2String(cacheRemainingPercent) + "\n");
320
321 buffer.append("Last contact: "+new Date(lastUpdate)+"\n");
322 return buffer.toString();
323 }
324
325 /** A formatted string for printing the status of the DataNode. */
326 public String dumpDatanode() {
327 StringBuilder buffer = new StringBuilder();
328 long c = getCapacity();
329 long r = getRemaining();
330 long u = getDfsUsed();
331 long cc = getCacheCapacity();
332 long cr = getCacheRemaining();
333 long cu = getCacheUsed();
334 buffer.append(getName());
335 if (!NetworkTopology.DEFAULT_RACK.equals(location)) {
336 buffer.append(" "+location);
337 }
338 if (isDecommissioned()) {
339 buffer.append(" DD");
340 } else if (isDecommissionInProgress()) {
341 buffer.append(" DP");
342 } else {
343 buffer.append(" IN");
344 }
345 buffer.append(" " + c + "(" + StringUtils.byteDesc(c)+")");
346 buffer.append(" " + u + "(" + StringUtils.byteDesc(u)+")");
347 buffer.append(" " + percent2String(u/(double)c));
348 buffer.append(" " + r + "(" + StringUtils.byteDesc(r)+")");
349 buffer.append(" " + cc + "(" + StringUtils.byteDesc(cc)+")");
350 buffer.append(" " + cu + "(" + StringUtils.byteDesc(cu)+")");
351 buffer.append(" " + percent2String(cu/(double)cc));
352 buffer.append(" " + cr + "(" + StringUtils.byteDesc(cr)+")");
353 buffer.append(" " + new Date(lastUpdate));
354 return buffer.toString();
355 }
356
357 /**
358 * Start decommissioning a node.
359 * old state.
360 */
361 public void startDecommission() {
362 adminState = AdminStates.DECOMMISSION_INPROGRESS;
363 }
364
365 /**
366 * Stop decommissioning a node.
367 * old state.
368 */
369 public void stopDecommission() {
370 adminState = null;
371 }
372
373 /**
374 * Returns true if the node is in the process of being decommissioned
375 */
376 public boolean isDecommissionInProgress() {
377 return adminState == AdminStates.DECOMMISSION_INPROGRESS;
378 }
379
380 /**
381 * Returns true if the node has been decommissioned.
382 */
383 public boolean isDecommissioned() {
384 return adminState == AdminStates.DECOMMISSIONED;
385 }
386
387 /**
388 * Sets the admin state to indicate that decommission is complete.
389 */
390 public void setDecommissioned() {
391 adminState = AdminStates.DECOMMISSIONED;
392 }
393
394 /**
395 * Retrieves the admin state of this node.
396 */
397 public AdminStates getAdminState() {
398 if (adminState == null) {
399 return AdminStates.NORMAL;
400 }
401 return adminState;
402 }
403
404 /**
405 * Check if the datanode is in stale state. Here if
406 * the namenode has not received heartbeat msg from a
407 * datanode for more than staleInterval (default value is
408 * {@link DFSConfigKeys#DFS_NAMENODE_STALE_DATANODE_INTERVAL_DEFAULT}),
409 * the datanode will be treated as stale node.
410 *
411 * @param staleInterval
412 * the time interval for marking the node as stale. If the last
413 * update time is beyond the given time interval, the node will be
414 * marked as stale.
415 * @return true if the node is stale
416 */
417 public boolean isStale(long staleInterval) {
418 return (Time.now() - lastUpdate) >= staleInterval;
419 }
420
421 /**
422 * Sets the admin state of this node.
423 */
424 protected void setAdminState(AdminStates newState) {
425 if (newState == AdminStates.NORMAL) {
426 adminState = null;
427 }
428 else {
429 adminState = newState;
430 }
431 }
432
433 private transient int level; //which level of the tree the node resides
434 private transient Node parent; //its parent
435
436 /** Return this node's parent */
437 @Override
438 public Node getParent() { return parent; }
439 @Override
440 public void setParent(Node parent) {this.parent = parent;}
441
442 /** Return this node's level in the tree.
443 * E.g. the root of a tree returns 0 and its children return 1
444 */
445 @Override
446 public int getLevel() { return level; }
447 @Override
448 public void setLevel(int level) {this.level = level;}
449
450 @Override
451 public int hashCode() {
452 // Super implementation is sufficient
453 return super.hashCode();
454 }
455
456 @Override
457 public boolean equals(Object obj) {
458 // Sufficient to use super equality as datanodes are uniquely identified
459 // by DatanodeID
460 return (this == obj) || super.equals(obj);
461 }
462
463 public String getSoftwareVersion() {
464 return softwareVersion;
465 }
466
467 public void setSoftwareVersion(String softwareVersion) {
468 this.softwareVersion = softwareVersion;
469 }
470 }