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 */ 018package org.apache.hadoop.hdfs.server.blockmanagement; 019 020import java.util.ArrayList; 021import java.util.BitSet; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.Iterator; 027import java.util.LinkedList; 028import java.util.List; 029import java.util.Map; 030import java.util.Queue; 031import java.util.Set; 032 033import com.google.common.annotations.VisibleForTesting; 034 035import com.google.common.collect.ImmutableList; 036import org.apache.commons.logging.Log; 037import org.apache.commons.logging.LogFactory; 038import org.apache.hadoop.classification.InterfaceAudience; 039import org.apache.hadoop.classification.InterfaceStability; 040import org.apache.hadoop.fs.StorageType; 041import org.apache.hadoop.hdfs.protocol.Block; 042import org.apache.hadoop.hdfs.protocol.DatanodeID; 043import org.apache.hadoop.hdfs.protocol.DatanodeInfo; 044import org.apache.hadoop.hdfs.server.namenode.CachedBlock; 045import org.apache.hadoop.hdfs.server.protocol.BlockReportContext; 046import org.apache.hadoop.hdfs.server.protocol.DatanodeStorage; 047import org.apache.hadoop.hdfs.server.protocol.StorageReport; 048import org.apache.hadoop.hdfs.server.protocol.VolumeFailureSummary; 049import org.apache.hadoop.hdfs.util.EnumCounters; 050import org.apache.hadoop.hdfs.util.LightWeightHashSet; 051import org.apache.hadoop.util.IntrusiveCollection; 052import org.apache.hadoop.util.Time; 053 054import com.google.common.annotations.VisibleForTesting; 055 056/** 057 * This class extends the DatanodeInfo class with ephemeral information (eg 058 * health, capacity, what blocks are associated with the Datanode) that is 059 * private to the Namenode, ie this class is not exposed to clients. 060 */ 061@InterfaceAudience.Private 062@InterfaceStability.Evolving 063public class DatanodeDescriptor extends DatanodeInfo { 064 public static final Log LOG = LogFactory.getLog(DatanodeDescriptor.class); 065 public static final DatanodeDescriptor[] EMPTY_ARRAY = {}; 066 067 // Stores status of decommissioning. 068 // If node is not decommissioning, do not use this object for anything. 069 public final DecommissioningStatus decommissioningStatus = new DecommissioningStatus(); 070 071 private long curBlockReportId = 0; 072 073 private BitSet curBlockReportRpcsSeen = null; 074 075 public int updateBlockReportContext(BlockReportContext context) { 076 if (curBlockReportId != context.getReportId()) { 077 curBlockReportId = context.getReportId(); 078 curBlockReportRpcsSeen = new BitSet(context.getTotalRpcs()); 079 } 080 curBlockReportRpcsSeen.set(context.getCurRpc()); 081 return curBlockReportRpcsSeen.cardinality(); 082 } 083 084 public void clearBlockReportContext() { 085 curBlockReportId = 0; 086 curBlockReportRpcsSeen = null; 087 } 088 089 /** Block and targets pair */ 090 @InterfaceAudience.Private 091 @InterfaceStability.Evolving 092 public static class BlockTargetPair { 093 public final Block block; 094 public final DatanodeStorageInfo[] targets; 095 096 BlockTargetPair(Block block, DatanodeStorageInfo[] targets) { 097 this.block = block; 098 this.targets = targets; 099 } 100 } 101 102 /** A BlockTargetPair queue. */ 103 private static class BlockQueue<E> { 104 private final Queue<E> blockq = new LinkedList<E>(); 105 106 /** Size of the queue */ 107 synchronized int size() {return blockq.size();} 108 109 /** Enqueue */ 110 synchronized boolean offer(E e) { 111 return blockq.offer(e); 112 } 113 114 /** Dequeue */ 115 synchronized List<E> poll(int numBlocks) { 116 if (numBlocks <= 0 || blockq.isEmpty()) { 117 return null; 118 } 119 120 List<E> results = new ArrayList<E>(); 121 for(; !blockq.isEmpty() && numBlocks > 0; numBlocks--) { 122 results.add(blockq.poll()); 123 } 124 return results; 125 } 126 127 /** 128 * Returns <tt>true</tt> if the queue contains the specified element. 129 */ 130 boolean contains(E e) { 131 return blockq.contains(e); 132 } 133 134 synchronized void clear() { 135 blockq.clear(); 136 } 137 } 138 139 private final Map<String, DatanodeStorageInfo> storageMap = 140 new HashMap<String, DatanodeStorageInfo>(); 141 142 /** 143 * A list of CachedBlock objects on this datanode. 144 */ 145 public static class CachedBlocksList extends IntrusiveCollection<CachedBlock> { 146 public enum Type { 147 PENDING_CACHED, 148 CACHED, 149 PENDING_UNCACHED 150 } 151 152 private final DatanodeDescriptor datanode; 153 154 private final Type type; 155 156 CachedBlocksList(DatanodeDescriptor datanode, Type type) { 157 this.datanode = datanode; 158 this.type = type; 159 } 160 161 public DatanodeDescriptor getDatanode() { 162 return datanode; 163 } 164 165 public Type getType() { 166 return type; 167 } 168 } 169 170 /** 171 * The blocks which we want to cache on this DataNode. 172 */ 173 private final CachedBlocksList pendingCached = 174 new CachedBlocksList(this, CachedBlocksList.Type.PENDING_CACHED); 175 176 /** 177 * The blocks which we know are cached on this datanode. 178 * This list is updated by periodic cache reports. 179 */ 180 private final CachedBlocksList cached = 181 new CachedBlocksList(this, CachedBlocksList.Type.CACHED); 182 183 /** 184 * The blocks which we want to uncache on this DataNode. 185 */ 186 private final CachedBlocksList pendingUncached = 187 new CachedBlocksList(this, CachedBlocksList.Type.PENDING_UNCACHED); 188 189 public CachedBlocksList getPendingCached() { 190 return pendingCached; 191 } 192 193 public CachedBlocksList getCached() { 194 return cached; 195 } 196 197 public CachedBlocksList getPendingUncached() { 198 return pendingUncached; 199 } 200 201 /** 202 * The time when the last batch of caching directives was sent, in 203 * monotonic milliseconds. 204 */ 205 private long lastCachingDirectiveSentTimeMs; 206 207 // isAlive == heartbeats.contains(this) 208 // This is an optimization, because contains takes O(n) time on Arraylist 209 public boolean isAlive = false; 210 public boolean needKeyUpdate = false; 211 212 213 // A system administrator can tune the balancer bandwidth parameter 214 // (dfs.balance.bandwidthPerSec) dynamically by calling 215 // "dfsadmin -setBalanacerBandwidth <newbandwidth>", at which point the 216 // following 'bandwidth' variable gets updated with the new value for each 217 // node. Once the heartbeat command is issued to update the value on the 218 // specified datanode, this value will be set back to 0. 219 private long bandwidth; 220 221 /** A queue of blocks to be replicated by this datanode */ 222 private final BlockQueue<BlockTargetPair> replicateBlocks = new BlockQueue<BlockTargetPair>(); 223 /** A queue of blocks to be recovered by this datanode */ 224 private final BlockQueue<BlockInfoContiguousUnderConstruction> recoverBlocks = 225 new BlockQueue<BlockInfoContiguousUnderConstruction>(); 226 /** A set of blocks to be invalidated by this datanode */ 227 private final LightWeightHashSet<Block> invalidateBlocks = new LightWeightHashSet<Block>(); 228 229 /* Variables for maintaining number of blocks scheduled to be written to 230 * this storage. This count is approximate and might be slightly bigger 231 * in case of errors (e.g. datanode does not report if an error occurs 232 * while writing the block). 233 */ 234 private EnumCounters<StorageType> currApproxBlocksScheduled 235 = new EnumCounters<StorageType>(StorageType.class); 236 private EnumCounters<StorageType> prevApproxBlocksScheduled 237 = new EnumCounters<StorageType>(StorageType.class); 238 private long lastBlocksScheduledRollTime = 0; 239 private static final int BLOCKS_SCHEDULED_ROLL_INTERVAL = 600*1000; //10min 240 private int volumeFailures = 0; 241 private VolumeFailureSummary volumeFailureSummary = null; 242 243 /** 244 * When set to true, the node is not in include list and is not allowed 245 * to communicate with the namenode 246 */ 247 private boolean disallowed = false; 248 249 // The number of replication work pending before targets are determined 250 private int PendingReplicationWithoutTargets = 0; 251 252 // HB processing can use it to tell if it is the first HB since DN restarted 253 private boolean heartbeatedSinceRegistration = false; 254 255 /** 256 * DatanodeDescriptor constructor 257 * @param nodeID id of the data node 258 */ 259 public DatanodeDescriptor(DatanodeID nodeID) { 260 super(nodeID); 261 updateHeartbeatState(StorageReport.EMPTY_ARRAY, 0L, 0L, 0, 0, null); 262 } 263 264 /** 265 * DatanodeDescriptor constructor 266 * @param nodeID id of the data node 267 * @param networkLocation location of the data node in network 268 */ 269 public DatanodeDescriptor(DatanodeID nodeID, 270 String networkLocation) { 271 super(nodeID, networkLocation); 272 updateHeartbeatState(StorageReport.EMPTY_ARRAY, 0L, 0L, 0, 0, null); 273 } 274 275 @VisibleForTesting 276 public DatanodeStorageInfo getStorageInfo(String storageID) { 277 synchronized (storageMap) { 278 return storageMap.get(storageID); 279 } 280 } 281 DatanodeStorageInfo[] getStorageInfos() { 282 synchronized (storageMap) { 283 final Collection<DatanodeStorageInfo> storages = storageMap.values(); 284 return storages.toArray(new DatanodeStorageInfo[storages.size()]); 285 } 286 } 287 288 public StorageReport[] getStorageReports() { 289 final DatanodeStorageInfo[] infos = getStorageInfos(); 290 final StorageReport[] reports = new StorageReport[infos.length]; 291 for(int i = 0; i < infos.length; i++) { 292 reports[i] = infos[i].toStorageReport(); 293 } 294 return reports; 295 } 296 297 boolean hasStaleStorages() { 298 synchronized (storageMap) { 299 for (DatanodeStorageInfo storage : storageMap.values()) { 300 if (storage.areBlockContentsStale()) { 301 return true; 302 } 303 } 304 return false; 305 } 306 } 307 308 static final private List<DatanodeStorageInfo> EMPTY_STORAGE_INFO_LIST = 309 ImmutableList.of(); 310 311 List<DatanodeStorageInfo> removeZombieStorages() { 312 List<DatanodeStorageInfo> zombies = null; 313 synchronized (storageMap) { 314 Iterator<Map.Entry<String, DatanodeStorageInfo>> iter = 315 storageMap.entrySet().iterator(); 316 while (iter.hasNext()) { 317 Map.Entry<String, DatanodeStorageInfo> entry = iter.next(); 318 DatanodeStorageInfo storageInfo = entry.getValue(); 319 if (storageInfo.getLastBlockReportId() != curBlockReportId) { 320 LOG.info(storageInfo.getStorageID() + " had lastBlockReportId 0x" + 321 Long.toHexString(storageInfo.getLastBlockReportId()) + 322 ", but curBlockReportId = 0x" + 323 Long.toHexString(curBlockReportId)); 324 iter.remove(); 325 if (zombies == null) { 326 zombies = new LinkedList<DatanodeStorageInfo>(); 327 } 328 zombies.add(storageInfo); 329 } 330 storageInfo.setLastBlockReportId(0); 331 } 332 } 333 return zombies == null ? EMPTY_STORAGE_INFO_LIST : zombies; 334 } 335 336 /** 337 * Remove block from the list of blocks belonging to the data-node. Remove 338 * data-node from the block. 339 */ 340 boolean removeBlock(BlockInfoContiguous b) { 341 final DatanodeStorageInfo s = b.findStorageInfo(this); 342 // if block exists on this datanode 343 if (s != null) { 344 return s.removeBlock(b); 345 } 346 return false; 347 } 348 349 /** 350 * Remove block from the list of blocks belonging to the data-node. Remove 351 * data-node from the block. 352 */ 353 boolean removeBlock(String storageID, BlockInfoContiguous b) { 354 DatanodeStorageInfo s = getStorageInfo(storageID); 355 if (s != null) { 356 return s.removeBlock(b); 357 } 358 return false; 359 } 360 361 public void resetBlocks() { 362 setCapacity(0); 363 setRemaining(0); 364 setBlockPoolUsed(0); 365 setDfsUsed(0); 366 setXceiverCount(0); 367 this.invalidateBlocks.clear(); 368 this.volumeFailures = 0; 369 // pendingCached, cached, and pendingUncached are protected by the 370 // FSN lock. 371 this.pendingCached.clear(); 372 this.cached.clear(); 373 this.pendingUncached.clear(); 374 } 375 376 public void clearBlockQueues() { 377 synchronized (invalidateBlocks) { 378 this.invalidateBlocks.clear(); 379 this.recoverBlocks.clear(); 380 this.replicateBlocks.clear(); 381 } 382 // pendingCached, cached, and pendingUncached are protected by the 383 // FSN lock. 384 this.pendingCached.clear(); 385 this.cached.clear(); 386 this.pendingUncached.clear(); 387 } 388 389 public int numBlocks() { 390 int blocks = 0; 391 for (DatanodeStorageInfo entry : getStorageInfos()) { 392 blocks += entry.numBlocks(); 393 } 394 return blocks; 395 } 396 397 /** 398 * Updates stats from datanode heartbeat. 399 */ 400 public void updateHeartbeat(StorageReport[] reports, long cacheCapacity, 401 long cacheUsed, int xceiverCount, int volFailures, 402 VolumeFailureSummary volumeFailureSummary) { 403 updateHeartbeatState(reports, cacheCapacity, cacheUsed, xceiverCount, 404 volFailures, volumeFailureSummary); 405 heartbeatedSinceRegistration = true; 406 } 407 408 /** 409 * process datanode heartbeat or stats initialization. 410 */ 411 public void updateHeartbeatState(StorageReport[] reports, long cacheCapacity, 412 long cacheUsed, int xceiverCount, int volFailures, 413 VolumeFailureSummary volumeFailureSummary) { 414 long totalCapacity = 0; 415 long totalRemaining = 0; 416 long totalBlockPoolUsed = 0; 417 long totalDfsUsed = 0; 418 Set<DatanodeStorageInfo> failedStorageInfos = null; 419 420 // Decide if we should check for any missing StorageReport and mark it as 421 // failed. There are different scenarios. 422 // 1. When DN is running, a storage failed. Given the current DN 423 // implementation doesn't add recovered storage back to its storage list 424 // until DN restart, we can assume volFailures won't decrease 425 // during the current DN registration session. 426 // When volumeFailures == this.volumeFailures, it implies there is no 427 // state change. No need to check for failed storage. This is an 428 // optimization. Recent versions of the DataNode report a 429 // VolumeFailureSummary containing the date/time of the last volume 430 // failure. If that's available, then we check that instead for greater 431 // accuracy. 432 // 2. After DN restarts, volFailures might not increase and it is possible 433 // we still have new failed storage. For example, admins reduce 434 // available storages in configuration. Another corner case 435 // is the failed volumes might change after restart; a) there 436 // is one good storage A, one restored good storage B, so there is 437 // one element in storageReports and that is A. b) A failed. c) Before 438 // DN sends HB to NN to indicate A has failed, DN restarts. d) After DN 439 // restarts, storageReports has one element which is B. 440 final boolean checkFailedStorages; 441 if (volumeFailureSummary != null && this.volumeFailureSummary != null) { 442 checkFailedStorages = volumeFailureSummary.getLastVolumeFailureDate() > 443 this.volumeFailureSummary.getLastVolumeFailureDate(); 444 } else { 445 checkFailedStorages = (volFailures > this.volumeFailures) || 446 !heartbeatedSinceRegistration; 447 } 448 449 if (checkFailedStorages) { 450 LOG.info("Number of failed storage changes from " 451 + this.volumeFailures + " to " + volFailures); 452 failedStorageInfos = new HashSet<DatanodeStorageInfo>( 453 storageMap.values()); 454 } 455 456 setCacheCapacity(cacheCapacity); 457 setCacheUsed(cacheUsed); 458 setXceiverCount(xceiverCount); 459 setLastUpdate(Time.now()); 460 setLastUpdateMonotonic(Time.monotonicNow()); 461 this.volumeFailures = volFailures; 462 this.volumeFailureSummary = volumeFailureSummary; 463 for (StorageReport report : reports) { 464 DatanodeStorageInfo storage = updateStorage(report.getStorage()); 465 if (checkFailedStorages) { 466 failedStorageInfos.remove(storage); 467 } 468 469 storage.receivedHeartbeat(report); 470 totalCapacity += report.getCapacity(); 471 totalRemaining += report.getRemaining(); 472 totalBlockPoolUsed += report.getBlockPoolUsed(); 473 totalDfsUsed += report.getDfsUsed(); 474 } 475 rollBlocksScheduled(getLastUpdateMonotonic()); 476 477 // Update total metrics for the node. 478 setCapacity(totalCapacity); 479 setRemaining(totalRemaining); 480 setBlockPoolUsed(totalBlockPoolUsed); 481 setDfsUsed(totalDfsUsed); 482 if (checkFailedStorages) { 483 updateFailedStorage(failedStorageInfos); 484 } 485 486 if (storageMap.size() != reports.length) { 487 pruneStorageMap(reports); 488 } 489 } 490 491 /** 492 * Remove stale storages from storageMap. We must not remove any storages 493 * as long as they have associated block replicas. 494 */ 495 private void pruneStorageMap(final StorageReport[] reports) { 496 if (LOG.isDebugEnabled()) { 497 LOG.debug("Number of storages reported in heartbeat=" + reports.length + 498 "; Number of storages in storageMap=" + storageMap.size()); 499 } 500 501 HashMap<String, DatanodeStorageInfo> excessStorages; 502 503 synchronized (storageMap) { 504 // Init excessStorages with all known storages. 505 excessStorages = new HashMap<String, DatanodeStorageInfo>(storageMap); 506 507 // Remove storages that the DN reported in the heartbeat. 508 for (final StorageReport report : reports) { 509 excessStorages.remove(report.getStorage().getStorageID()); 510 } 511 512 // For each remaining storage, remove it if there are no associated 513 // blocks. 514 for (final DatanodeStorageInfo storageInfo : excessStorages.values()) { 515 if (storageInfo.numBlocks() == 0) { 516 storageMap.remove(storageInfo.getStorageID()); 517 LOG.info("Removed storage " + storageInfo + " from DataNode" + this); 518 } else if (LOG.isDebugEnabled()) { 519 // This can occur until all block reports are received. 520 LOG.debug("Deferring removal of stale storage " + storageInfo + 521 " with " + storageInfo.numBlocks() + " blocks"); 522 } 523 } 524 } 525 } 526 527 private void updateFailedStorage( 528 Set<DatanodeStorageInfo> failedStorageInfos) { 529 for (DatanodeStorageInfo storageInfo : failedStorageInfos) { 530 if (storageInfo.getState() != DatanodeStorage.State.FAILED) { 531 LOG.info(storageInfo + " failed."); 532 storageInfo.setState(DatanodeStorage.State.FAILED); 533 } 534 } 535 } 536 537 private static class BlockIterator implements Iterator<BlockInfoContiguous> { 538 private int index = 0; 539 private final List<Iterator<BlockInfoContiguous>> iterators; 540 541 private BlockIterator(final DatanodeStorageInfo... storages) { 542 List<Iterator<BlockInfoContiguous>> iterators = new ArrayList<Iterator<BlockInfoContiguous>>(); 543 for (DatanodeStorageInfo e : storages) { 544 iterators.add(e.getBlockIterator()); 545 } 546 this.iterators = Collections.unmodifiableList(iterators); 547 } 548 549 @Override 550 public boolean hasNext() { 551 update(); 552 return !iterators.isEmpty() && iterators.get(index).hasNext(); 553 } 554 555 @Override 556 public BlockInfoContiguous next() { 557 update(); 558 return iterators.get(index).next(); 559 } 560 561 @Override 562 public void remove() { 563 throw new UnsupportedOperationException("Remove unsupported."); 564 } 565 566 private void update() { 567 while(index < iterators.size() - 1 && !iterators.get(index).hasNext()) { 568 index++; 569 } 570 } 571 } 572 573 Iterator<BlockInfoContiguous> getBlockIterator() { 574 return new BlockIterator(getStorageInfos()); 575 } 576 Iterator<BlockInfoContiguous> getBlockIterator(final String storageID) { 577 return new BlockIterator(getStorageInfo(storageID)); 578 } 579 580 void incrementPendingReplicationWithoutTargets() { 581 PendingReplicationWithoutTargets++; 582 } 583 584 void decrementPendingReplicationWithoutTargets() { 585 PendingReplicationWithoutTargets--; 586 } 587 588 /** 589 * Store block replication work. 590 */ 591 void addBlockToBeReplicated(Block block, DatanodeStorageInfo[] targets) { 592 assert(block != null && targets != null && targets.length > 0); 593 replicateBlocks.offer(new BlockTargetPair(block, targets)); 594 } 595 596 /** 597 * Store block recovery work. 598 */ 599 void addBlockToBeRecovered(BlockInfoContiguousUnderConstruction block) { 600 if(recoverBlocks.contains(block)) { 601 // this prevents adding the same block twice to the recovery queue 602 BlockManager.LOG.info(block + " is already in the recovery queue"); 603 return; 604 } 605 recoverBlocks.offer(block); 606 } 607 608 /** 609 * Store block invalidation work. 610 */ 611 void addBlocksToBeInvalidated(List<Block> blocklist) { 612 assert(blocklist != null && blocklist.size() > 0); 613 synchronized (invalidateBlocks) { 614 for(Block blk : blocklist) { 615 invalidateBlocks.add(blk); 616 } 617 } 618 } 619 620 /** 621 * The number of work items that are pending to be replicated 622 */ 623 int getNumberOfBlocksToBeReplicated() { 624 return PendingReplicationWithoutTargets + replicateBlocks.size(); 625 } 626 627 /** 628 * The number of block invalidation items that are pending to 629 * be sent to the datanode 630 */ 631 int getNumberOfBlocksToBeInvalidated() { 632 synchronized (invalidateBlocks) { 633 return invalidateBlocks.size(); 634 } 635 } 636 637 public List<BlockTargetPair> getReplicationCommand(int maxTransfers) { 638 return replicateBlocks.poll(maxTransfers); 639 } 640 641 public BlockInfoContiguousUnderConstruction[] getLeaseRecoveryCommand(int maxTransfers) { 642 List<BlockInfoContiguousUnderConstruction> blocks = recoverBlocks.poll(maxTransfers); 643 if(blocks == null) 644 return null; 645 return blocks.toArray(new BlockInfoContiguousUnderConstruction[blocks.size()]); 646 } 647 648 /** 649 * Remove the specified number of blocks to be invalidated 650 */ 651 public Block[] getInvalidateBlocks(int maxblocks) { 652 synchronized (invalidateBlocks) { 653 Block[] deleteList = invalidateBlocks.pollToArray(new Block[Math.min( 654 invalidateBlocks.size(), maxblocks)]); 655 return deleteList.length == 0 ? null : deleteList; 656 } 657 } 658 659 /** 660 * @return Approximate number of blocks currently scheduled to be written 661 */ 662 public long getRemaining(StorageType t) { 663 long remaining = 0; 664 for(DatanodeStorageInfo s : getStorageInfos()) { 665 if (s.getStorageType() == t) { 666 remaining += s.getRemaining(); 667 } 668 } 669 return remaining; 670 } 671 672 /** 673 * @return Approximate number of blocks currently scheduled to be written 674 * to the given storage type of this datanode. 675 */ 676 public int getBlocksScheduled(StorageType t) { 677 return (int)(currApproxBlocksScheduled.get(t) 678 + prevApproxBlocksScheduled.get(t)); 679 } 680 681 /** 682 * @return Approximate number of blocks currently scheduled to be written 683 * to this datanode. 684 */ 685 public int getBlocksScheduled() { 686 return (int)(currApproxBlocksScheduled.sum() 687 + prevApproxBlocksScheduled.sum()); 688 } 689 690 /** Increment the number of blocks scheduled. */ 691 void incrementBlocksScheduled(StorageType t) { 692 currApproxBlocksScheduled.add(t, 1);; 693 } 694 695 /** Decrement the number of blocks scheduled. */ 696 void decrementBlocksScheduled(StorageType t) { 697 if (prevApproxBlocksScheduled.get(t) > 0) { 698 prevApproxBlocksScheduled.subtract(t, 1); 699 } else if (currApproxBlocksScheduled.get(t) > 0) { 700 currApproxBlocksScheduled.subtract(t, 1); 701 } 702 // its ok if both counters are zero. 703 } 704 705 /** Adjusts curr and prev number of blocks scheduled every few minutes. */ 706 private void rollBlocksScheduled(long now) { 707 if (now - lastBlocksScheduledRollTime > BLOCKS_SCHEDULED_ROLL_INTERVAL) { 708 prevApproxBlocksScheduled.set(currApproxBlocksScheduled); 709 currApproxBlocksScheduled.reset(); 710 lastBlocksScheduledRollTime = now; 711 } 712 } 713 714 @Override 715 public int hashCode() { 716 // Super implementation is sufficient 717 return super.hashCode(); 718 } 719 720 @Override 721 public boolean equals(Object obj) { 722 // Sufficient to use super equality as datanodes are uniquely identified 723 // by DatanodeID 724 return (this == obj) || super.equals(obj); 725 } 726 727 /** Decommissioning status */ 728 public class DecommissioningStatus { 729 private int underReplicatedBlocks; 730 private int decommissionOnlyReplicas; 731 private int underReplicatedInOpenFiles; 732 private long startTime; 733 734 synchronized void set(int underRep, 735 int onlyRep, int underConstruction) { 736 if (isDecommissionInProgress() == false) { 737 return; 738 } 739 underReplicatedBlocks = underRep; 740 decommissionOnlyReplicas = onlyRep; 741 underReplicatedInOpenFiles = underConstruction; 742 } 743 744 /** @return the number of under-replicated blocks */ 745 public synchronized int getUnderReplicatedBlocks() { 746 if (isDecommissionInProgress() == false) { 747 return 0; 748 } 749 return underReplicatedBlocks; 750 } 751 /** @return the number of decommission-only replicas */ 752 public synchronized int getDecommissionOnlyReplicas() { 753 if (isDecommissionInProgress() == false) { 754 return 0; 755 } 756 return decommissionOnlyReplicas; 757 } 758 /** @return the number of under-replicated blocks in open files */ 759 public synchronized int getUnderReplicatedInOpenFiles() { 760 if (isDecommissionInProgress() == false) { 761 return 0; 762 } 763 return underReplicatedInOpenFiles; 764 } 765 /** Set start time */ 766 public synchronized void setStartTime(long time) { 767 startTime = time; 768 } 769 /** @return start time */ 770 public synchronized long getStartTime() { 771 if (isDecommissionInProgress() == false) { 772 return 0; 773 } 774 return startTime; 775 } 776 } // End of class DecommissioningStatus 777 778 /** 779 * Set the flag to indicate if this datanode is disallowed from communicating 780 * with the namenode. 781 */ 782 public void setDisallowed(boolean flag) { 783 disallowed = flag; 784 } 785 /** Is the datanode disallowed from communicating with the namenode? */ 786 public boolean isDisallowed() { 787 return disallowed; 788 } 789 790 /** 791 * @return number of failed volumes in the datanode. 792 */ 793 public int getVolumeFailures() { 794 return volumeFailures; 795 } 796 797 /** 798 * Returns info about volume failures. 799 * 800 * @return info about volume failures, possibly null 801 */ 802 public VolumeFailureSummary getVolumeFailureSummary() { 803 return volumeFailureSummary; 804 } 805 806 /** 807 * @param nodeReg DatanodeID to update registration for. 808 */ 809 @Override 810 public void updateRegInfo(DatanodeID nodeReg) { 811 super.updateRegInfo(nodeReg); 812 813 // must re-process IBR after re-registration 814 for(DatanodeStorageInfo storage : getStorageInfos()) { 815 storage.setBlockReportCount(0); 816 } 817 heartbeatedSinceRegistration = false; 818 } 819 820 /** 821 * @return balancer bandwidth in bytes per second for this datanode 822 */ 823 public long getBalancerBandwidth() { 824 return this.bandwidth; 825 } 826 827 /** 828 * @param bandwidth balancer bandwidth in bytes per second for this datanode 829 */ 830 public void setBalancerBandwidth(long bandwidth) { 831 this.bandwidth = bandwidth; 832 } 833 834 @Override 835 public String dumpDatanode() { 836 StringBuilder sb = new StringBuilder(super.dumpDatanode()); 837 int repl = replicateBlocks.size(); 838 if (repl > 0) { 839 sb.append(" ").append(repl).append(" blocks to be replicated;"); 840 } 841 int inval = invalidateBlocks.size(); 842 if (inval > 0) { 843 sb.append(" ").append(inval).append(" blocks to be invalidated;"); 844 } 845 int recover = recoverBlocks.size(); 846 if (recover > 0) { 847 sb.append(" ").append(recover).append(" blocks to be recovered;"); 848 } 849 return sb.toString(); 850 } 851 852 DatanodeStorageInfo updateStorage(DatanodeStorage s) { 853 synchronized (storageMap) { 854 DatanodeStorageInfo storage = storageMap.get(s.getStorageID()); 855 if (storage == null) { 856 LOG.info("Adding new storage ID " + s.getStorageID() + 857 " for DN " + getXferAddr()); 858 storage = new DatanodeStorageInfo(this, s); 859 storageMap.put(s.getStorageID(), storage); 860 } else if (storage.getState() != s.getState() || 861 storage.getStorageType() != s.getStorageType()) { 862 // For backwards compatibility, make sure that the type and 863 // state are updated. Some reports from older datanodes do 864 // not include these fields so we may have assumed defaults. 865 storage.updateFromStorage(s); 866 storageMap.put(storage.getStorageID(), storage); 867 } 868 return storage; 869 } 870 } 871 872 /** 873 * @return The time at which we last sent caching directives to this 874 * DataNode, in monotonic milliseconds. 875 */ 876 public long getLastCachingDirectiveSentTimeMs() { 877 return this.lastCachingDirectiveSentTimeMs; 878 } 879 880 /** 881 * @param time The time at which we last sent caching directives to this 882 * DataNode, in monotonic milliseconds. 883 */ 884 public void setLastCachingDirectiveSentTimeMs(long time) { 885 this.lastCachingDirectiveSentTimeMs = time; 886 } 887 888 /** 889 * checks whether atleast first block report has been received 890 * @return 891 */ 892 public boolean checkBlockReportReceived() { 893 if(this.getStorageInfos().length == 0) { 894 return false; 895 } 896 for(DatanodeStorageInfo storageInfo: this.getStorageInfos()) { 897 if(storageInfo.getBlockReportCount() == 0 ) 898 return false; 899 } 900 return true; 901 } 902} 903