CorruptReplicasMap用于存储文件系统中所有损坏数据块的信息。仅当它的所有副本损坏时一个数据块才被认定为损坏。当汇报数据块的副本时,我们隐藏所有损坏副本。一旦一个数据块被发现完好副本达到预期,它将从CorruptReplicasMap中被移除。

我们先看下CorruptReplicasMap都有哪些成员变量,如下所示:

  1. // 存储损坏数据块Block与它对应每个数据节点与损坏原因集合映射关系的集合
  2. private final SortedMap<Block, Map<DatanodeDescriptor, Reason>> corruptReplicasMap =
  3. new TreeMap<Block, Map<DatanodeDescriptor, Reason>>();

是的,你没看错,就这一个corruptReplicasMap集合,它是一个用来存储损坏数据块Block实例与它对应每个数据节点和损坏原因集合的映射关系的集合。

我们看下CorruptReplicasMap都提供了哪些有用的方法。

一、addToCorruptReplicasMap()

标记属于指定数据节点的数据块为损坏

  1. /**
  2. * Mark the block belonging to datanode as corrupt.
  3. * 标记属于指定数据节点的数据块为损坏
  4. *
  5. * @param blk Block to be added to CorruptReplicasMap
  6. * @param dn DatanodeDescriptor which holds the corrupt replica
  7. * @param reason a textual reason (for logging purposes)
  8. * @param reasonCode the enum representation of the reason
  9. */
  10. void addToCorruptReplicasMap(Block blk, DatanodeDescriptor dn,
  11. String reason, Reason reasonCode) {
  12. / 先从corruptReplicasMap集合中查找是否存在对应数据块blk
  13. Map <DatanodeDescriptor, Reason> nodes = corruptReplicasMap.get(blk);
  14. // 如果不存在,构造一个HashMap<DatanodeDescriptor, Reason>集合nodes,将blk与nodes存入corruptReplicasMap
  15. if (nodes == null) {
  16. nodes = new HashMap<DatanodeDescriptor, Reason>();
  17. corruptReplicasMap.put(blk, nodes);
  18. }
  19. String reasonText;
  20. if (reason != null) {
  21. reasonText = " because " + reason;
  22. } else {
  23. reasonText = "";
  24. }
  25. // 判断nodes中是否存在对应数据节点dn,分别记录日志信息
  26. if (!nodes.keySet().contains(dn)) {
  27. NameNode.blockStateChangeLog.info("BLOCK NameSystem.addToCorruptReplicasMap: "+
  28. blk.getBlockName() +
  29. " added as corrupt on " + dn +
  30. " by " + Server.getRemoteIp() +
  31. reasonText);
  32. } else {
  33. NameNode.blockStateChangeLog.info("BLOCK NameSystem.addToCorruptReplicasMap: "+
  34. "duplicate requested for " +
  35. blk.getBlockName() + " to add as corrupt " +
  36. "on " + dn +
  37. " by " + Server.getRemoteIp() +
  38. reasonText);
  39. }
  40. // Add the node or update the reason.
  41. // 将数据节点dn、损坏原因编码reasonCode加入或更新入nodes
  42. nodes.put(dn, reasonCode);
  43. }

处理逻辑很简单,大体如下:

1、先从corruptReplicasMap集合中查找是否存在对应数据块blk;

2、如果不存在,构造一个HashMap<DatanodeDescriptor, Reason>集合nodes,将blk与nodes存入corruptReplicasMap;

3、判断nodes中是否存在对应数据节点dn,分别记录日志信息;

4、将数据节点dn、损坏原因编码reasonCode加入或更新入nodes。

二、removeFromCorruptReplicasMap()

将指定数据块、数据节点,根据指定原因从集合corruptReplicasMap移除

  1. // 将指定数据块、数据节点,根据指定原因从集合corruptReplicasMap移除
  2. boolean removeFromCorruptReplicasMap(Block blk, DatanodeDescriptor datanode,
  3. Reason reason) {
  4. / 先从corruptReplicasMap集合中查找是否存在对应数据块blk,获得datanodes
  5. Map <DatanodeDescriptor, Reason> datanodes = corruptReplicasMap.get(blk);
  6. // 如果不存在,直接返回false,表明移除失败
  7. if (datanodes==null)
  8. return false;
  9. // if reasons can be compared but don't match, return false.
  10. // 取出数据节点datanode对应的存储损坏原因storedReason
  11. Reason storedReason = datanodes.get(datanode);
  12. // 判断存储损坏原因storedReason与参数损坏原因reason是否一致,不一致直接返回false,表明移除失败,
  13. // 判断的依据为参数损坏原因reason不是ANY且存储损坏原因storedReason不为空的情况下,两者不一致
  14. if (reason != Reason.ANY && storedReason != null &&
  15. reason != storedReason) {
  16. return false;
  17. }
  18. // 将datanode对应数据从datanodes中移除
  19. if (datanodes.remove(datanode) != null) { // remove the replicas
  20. // 移除datanode后,如果datanodes为空
  21. if (datanodes.isEmpty()) {
  22. // remove the block if there is no more corrupted replicas
  23. // 将数据块blk从集合corruptReplicasMap中移除
  24. corruptReplicasMap.remove(blk);
  25. }
  26. // 返回true,表明移除成功
  27. return true;
  28. }
  29. // 其他情况下直接返回false,表明移除失败
  30. return false;
  31. }

三、getCorruptReplicaBlockIds()

获取指定大小和起始数据块ID的损坏数据块ID数组

  1. /**
  2. * Return a range of corrupt replica block ids. Up to numExpectedBlocks
  3. * blocks starting at the next block after startingBlockId are returned
  4. * (fewer if numExpectedBlocks blocks are unavailable). If startingBlockId
  5. * is null, up to numExpectedBlocks blocks are returned from the beginning.
  6. * If startingBlockId cannot be found, null is returned.
  7. * 获取指定大小和起始数据块ID的损坏数据块ID数组
  8. *
  9. * @param numExpectedBlocks Number of block ids to return.
  10. *  0 <= numExpectedBlocks <= 100
  11. * @param startingBlockId Block id from which to start. If null, start at
  12. *  beginning.
  13. * @return Up to numExpectedBlocks blocks from startingBlockId if it exists
  14. *
  15. */
  16. long[] getCorruptReplicaBlockIds(int numExpectedBlocks,
  17. Long startingBlockId) {
  18. / 校验numExpectedBlocks,需要获取的数据块ID数组最多有100个元素
  19. if (numExpectedBlocks < 0 || numExpectedBlocks > 100) {
  20. return null;
  21. }
  22. // 获得corruptReplicasMap集合的数据块迭代器blockIt
  23. Iterator<Block> blockIt = corruptReplicasMap.keySet().iterator();
  24. // if the starting block id was specified, iterate over keys until
  25. // we find the matching block. If we find a matching block, break
  26. // to leave the iterator on the next block after the specified block.
  27. // 如果设定了起始数据块艾迪startingBlockId
  28. if (startingBlockId != null) {
  29. boolean isBlockFound = false;
  30. // 遍历corruptReplicasMap,查看是否存在startingBlockId,如果存在,跳出循环,此时已记录住迭代器的位置了
  31. while (blockIt.hasNext()) {
  32. Block b = blockIt.next();
  33. if (b.getBlockId() == startingBlockId) {
  34. isBlockFound = true;
  35. break;
  36. }
  37. }
  38. // 如果不存在,直接返回null
  39. if (!isBlockFound) {
  40. return null;
  41. }
  42. }
  43. // 构造一个存储数据块ID的列表corruptReplicaBlockIds
  44. ArrayList<Long> corruptReplicaBlockIds = new ArrayList<Long>();
  45. // append up to numExpectedBlocks blockIds to our list
  46. // 遍历corruptReplicasMap,将最多numExpectedBlocks个数据块ID添加到列表corruptReplicaBlockIds,
  47. // 此时的迭代器可能不是从头开始取数据的,在startingBlockId需要并存在的情况下,它是从下一个元素开始获取的
  48. for(int i=0; i<numExpectedBlocks && blockIt.hasNext(); i++) {
  49. corruptReplicaBlockIds.add(blockIt.next().getBlockId());
  50. }
  51. // 将数据块ID列表corruptReplicaBlockIds转换成数组ret
  52. long[] ret = new long[corruptReplicaBlockIds.size()];
  53. for(int i=0; i<ret.length; i++) {
  54. ret[i] = corruptReplicaBlockIds.get(i);
  55. }
  56. // 返回数据块ID数组ret
  57. return ret;
  58. }

四、getNodes()

根据损坏数据块获取对应数据节点集合

  1. /**
  2. * Get Nodes which have corrupt replicas of Block
  3. * 根据损坏数据块获取对应数据节点集合
  4. *
  5. * @param blk Block for which nodes are requested
  6. * @return collection of nodes. Null if does not exists
  7. */
  8. Collection<DatanodeDescriptor> getNodes(Block blk) {
  9. Map <DatanodeDescriptor, Reason> nodes = corruptReplicasMap.get(blk);
  10. if (nodes == null)
  11. return null;
  12. return nodes.keySet();
  13. }

五、isReplicaCorrupt()

检测指定数据块和数据节点是否为损坏的

  1. /**
  2. * Check if replica belonging to Datanode is corrupt
  3. * 检测指定数据块和数据节点是否为损坏的
  4. *
  5. * @param blk Block to check
  6. * @param node DatanodeDescriptor which holds the replica
  7. * @return true if replica is corrupt, false if does not exists in this map
  8. */
  9. boolean isReplicaCorrupt(Block blk, DatanodeDescriptor node) {
  10. Collection<DatanodeDescriptor> nodes = getNodes(blk);
  11. return ((nodes != null) && (nodes.contains(node)));
  12. }

六、numCorruptReplicas()

获取给定数据块对应数据节点数量

  1. // 获取给定数据块对应数据节点数量
  2. int numCorruptReplicas(Block blk) {
  3. Collection<DatanodeDescriptor> nodes = getNodes(blk);
  4. return (nodes == null) ? 0 : nodes.size();
  5. }

七、size()

获取损坏数据块数量

  1. // 获取损坏数据块数量
  2. int size() {
  3. return corruptReplicasMap.size();
  4. }

HDFS源码分析数据块之CorruptReplicasMap的更多相关文章

  1. HDFS源码分析数据块校验之DataBlockScanner

    DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...

  2. HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

    HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

  3. HDFS源码分析数据块复制监控线程ReplicationMonitor(一)

    ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...

  4. HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()

    无论是第一次,还是之后的每次数据块汇报,名字名字节点都会对汇报上来的数据块进行检测,看看其是否为损坏的数据块.那么,损坏数据块是如何被检测的呢?本文,我们将研究下损坏数据块检测的checkReplic ...

  5. HDFS源码分析数据块复制选取复制源节点

    数据块的复制当然需要一个源数据节点,从其上拷贝数据块至目标数据节点.那么数据块复制是如何选取复制源节点的呢?本文我们将针对这一问题进行研究. 在BlockManager中,chooseSourceDa ...

  6. HDFS源码分析数据块复制之PendingReplicationBlocks

    PendingReplicationBlocks实现了所有正在复制的数据块的记账工作.它实现以下三个主要功能: 1.记录此时正在复制的块: 2.一种对复制请求进行跟踪的粗粒度计时器: 3.一个定期识别 ...

  7. HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState

    关于数据块.副本的介绍,请参考文章<HDFS源码分析之数据块Block.副本Replica>. 一.数据块状态BlockUCState 数据块状态用枚举类BlockUCState来表示,代 ...

  8. HDFS源码分析心跳汇报之数据块汇报

    在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...

  9. HDFS源码分析心跳汇报之数据块增量汇报

    在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...

随机推荐

  1. Linux/Unix编程中的线程安全问题【转】

    转自:http://blog.csdn.net/zhengzhoudaxue2/article/details/6432984 在目前的计算机科学中,线程是操作系统调度的最小单元,进程是资源分配的最小 ...

  2. MySQL命令行导入脚本文件

    通过命令行执行sql脚本文件的方法: cmd命令行下: C:\users\test_dir>"C:\Program Files\MySQL\MySQL Server 5.7\bin\m ...

  3. Java IO 学习(零)概述

    参考文献 Doug Lea的  <Scalable IO in Java> Java NIO trick and trap IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇) 网络编程释疑 ...

  4. mysql查询练习题

    建库建表 a.建立一个公司数据库(gongsi)    CREATE DATABASE gongsi b.建立一张部门表(部门编号b_id,部门名称b_name) ,             其中b_ ...

  5. 洛谷 P2089 烤鸡【DFS递归/10重枚举】

    [链接]:https://www.luogu.org/problemnew/show/P2089 题目描述 猪猪Hanke特别喜欢吃烤鸡(本是同畜牲,相煎何太急!)Hanke吃鸡很特别,为什么特别呢? ...

  6. ES6十大特性

    本文主要针对ES6做一个简要介绍. 主要译自:  http://webapplog.com/ES6/comment-page-1/.也许你还不知道ES6是什么, 实际上, 它是一种新的javascri ...

  7. 某考试T1 game

    题目背景 无 题目描述 Alice 和 Bob 在一个圆环上玩游戏.圆环上有 n 个位置,按照顺时针顺序 依次标号为 1 到 n.Alice 和 Bob 分别有一个数字集合,集合中都是在 [1, n− ...

  8. 超实用的Nginx极简教程,覆盖了常用场景

    概述 安装与使用 安装 使用 nginx 配置实战 http 反向代理配置 负载均衡配置 网站有多个 webapp 的配置 https 反向代理配置 静态站点配置 搭建文件服务器 跨域解决方案 参考 ...

  9. Apache Openwhisk学习(一)

    一.背景 最近中途参与的一个项目是和Serverless.Faas相关的,项目的整体架构和实现都参考了开源项目openwhisk,因此,同事们在编码时都会参考openwhisk的源码.因为以前从没有接 ...

  10. 【hibernate】Hibernate SQL 方言(hibernate.dialect)

    参考如下: RDBMS Dialect DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dial ...