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