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