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

关于数据块及其副本的状态,请阅读《HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState》一文。

checkReplicaCorrupt()方法专门用于损坏数据块检测,代码如下:

  1. /**
  2. * The next two methods test the various cases under which we must conclude
  3. * the replica is corrupt, or under construction.  These are laid out
  4. * as switch statements, on the theory that it is easier to understand
  5. * the combinatorics of reportedState and ucState that way.  It should be
  6. * at least as efficient as boolean expressions.
  7. *
  8. * @return a BlockToMarkCorrupt object, or null if the replica is not corrupt
  9. */
  10. private BlockToMarkCorrupt checkReplicaCorrupt(
  11. Block reported, ReplicaState reportedState,
  12. BlockInfo storedBlock, BlockUCState ucState,
  13. DatanodeDescriptor dn) {
  14. // 检测数据节点DataNode上的数据块副本状态ReplicaState实例reportedState
  15. switch(reportedState) {
  16. case FINALIZED:// 数据块副本如果为FINALIZED状态,即没有被修改的状态
  17. // 需要再看名字节点数据块状态BlockUCState,即ucState
  18. switch(ucState) {
  19. case COMPLETE:// 如果是COMPLETE状态,不应被汇报为坏块:这种情况下,数据节点副本已经处于不会被修改的FINALIZED状态,
  20. // 而名字节点中的数据块状态为COMPLETE,也是不会被修改的状态,
  21. // 并且其他数据节点已经汇报过该数据块对应的一个副本,所以不会是损坏的数据块
  22. case COMMITTED:// 如果是COMMITTED状态,虽然数据块不会被修改,但是还没有任何数据节点汇报过副本,还需要做以下时间戳和大小的判断:
  23. if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) {
  24. // 如果存储的数据块时间戳不等于汇报的数据块时间戳,需要汇报为坏块,
  25. // 且损坏原因为Reason.GENSTAMP_MISMATCH,即时间戳不匹配
  26. final long reportedGS = reported.getGenerationStamp();
  27. return new BlockToMarkCorrupt(storedBlock, reportedGS,
  28. "block is " + ucState + " and reported genstamp " + reportedGS
  29. + " does not match genstamp in block map "
  30. + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
  31. } else if (storedBlock.getNumBytes() != reported.getNumBytes()) {
  32. // 如果存储的数据块大小不等于汇报的数据块大小,需要汇报为坏块
  33. // 且损坏原因为Reason.SIZE_MISMATCH,即大小不匹配
  34. return new BlockToMarkCorrupt(storedBlock,
  35. "block is " + ucState + " and reported length " +
  36. reported.getNumBytes() + " does not match " +
  37. "length in block map " + storedBlock.getNumBytes(),
  38. Reason.SIZE_MISMATCH);
  39. } else {
  40. // 其它情况下不是一个坏块
  41. return null; // not corrupt
  42. }
  43. case UNDER_CONSTRUCTION:// 如果是UNDER_CONSTRUCTION状态,数据还在被写入,所以需要做以下时间戳的判断:
  44. if (storedBlock.getGenerationStamp() > reported.getGenerationStamp()) {
  45. // 如果存储的数据块时间戳不等于汇报的数据块时间戳,需要汇报为坏块,
  46. // 且损坏原因为Reason.GENSTAMP_MISMATCH,即时间戳不匹配
  47. final long reportedGS = reported.getGenerationStamp();
  48. return new BlockToMarkCorrupt(storedBlock, reportedGS, "block is "
  49. + ucState + " and reported state " + reportedState
  50. + ", But reported genstamp " + reportedGS
  51. + " does not match genstamp in block map "
  52. + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
  53. }
  54. return null;
  55. default:
  56. // 其他情况下均不是损坏的数据块
  57. return null;
  58. }
  59. case RBW:// 数据块副本为正在被写入状态,不应被汇报为坏块
  60. case RWR:// 数据块副本为正等待被恢复状态
  61. if (!storedBlock.isComplete()) {
  62. // 如果存储的数据块不是Complete状态,则不是一个坏块
  63. return null; // not corrupt
  64. } else if (storedBlock.getGenerationStamp() != reported.getGenerationStamp()) {
  65. // 否则需要判断时间戳是否一致
  66. final long reportedGS = reported.getGenerationStamp();
  67. return new BlockToMarkCorrupt(storedBlock, reportedGS,
  68. "reported " + reportedState + " replica with genstamp " + reportedGS
  69. + " does not match COMPLETE block's genstamp in block map "
  70. + storedBlock.getGenerationStamp(), Reason.GENSTAMP_MISMATCH);
  71. } else { // COMPLETE block, same genstamp
  72. if (reportedState == ReplicaState.RBW) {
  73. // 如果数据块副本为正在写入状态RBW,不会是一个损坏的数据块
  74. // If it's a RBW report for a COMPLETE block, it may just be that
  75. // the block report got a little bit delayed after the pipeline
  76. // closed. So, ignore this report, assuming we will get a
  77. // FINALIZED replica later. See HDFS-2791
  78. LOG.info("Received an RBW replica for " + storedBlock +
  79. " on " + dn + ": ignoring it, since it is " +
  80. "complete with the same genstamp");
  81. return null;
  82. } else {
  83. // 否则为一个损坏的数据块,且损坏原因为Reason.INVALID_STATE
  84. return new BlockToMarkCorrupt(storedBlock,
  85. "reported replica has invalid state " + reportedState,
  86. Reason.INVALID_STATE);
  87. }
  88. }
  89. case RUR:       // should not be reported 副本处于恢复状态下,不应被汇报为坏块
  90. case TEMPORARY: // should not be reported 副本为仅为复制而创建的临时副本,不应被汇报为坏块
  91. default:
  92. String msg = "Unexpected replica state " + reportedState
  93. + " for block: " + storedBlock +
  94. " on " + dn + " size " + storedBlock.getNumBytes();
  95. // log here at WARN level since this is really a broken HDFS invariant
  96. LOG.warn(msg);
  97. return new BlockToMarkCorrupt(storedBlock, msg, Reason.INVALID_STATE);
  98. }
  99. }

checkReplicaCorrupt()方法处理逻辑略显复杂,但是还算清晰,它需要被汇报的数据块Block实例reported、副本状态实例ReplicaState、数据块状态BlockUCState等参数,主要处理逻辑如下:

基于数据节点DataNode上的数据块副本状态ReplicaState实例reportedState进行检测,如果:

1、数据块副本状态ReplicaState为正在写入RBW、正在恢复RUR、为复制而创建的临时副本TEMPORARY三种状态,则肯定不是损坏的数据块,因为这些数据块副本还处于不确定的状态,还需要被写入或者被舍弃等;

2、数据块副本状态ReplicaState为FINALIZED的话,说明数据已被完全写入,数据块副本大小及时间戳均不会再发生变化,此时,就等着其所在数据节点DataNode进行数据块汇报,将该数据块副本汇报给名字节点NameNode,那么我们需要看数据块Block在名字节点内的状态:

2.1、如果是COMPLETE状态,不应被汇报为坏块:这种情况下,数据节点副本已经处于不会被修改的FINALIZED状态,而名字节点中的数据块状态为COMPLETE,也是不会被修改的状态,并且其他数据节点已经汇报过该数据块对应的一个副本,所以不会是损坏的数据块;

2.2、如果是COMMITTED状态,虽然数据块不会被修改,但是还没有任何数据节点汇报过副本,还需要做以下时间戳和大小的判断:

2.2.1、如果名字节点存储的数据块时间戳不等于汇报的数据块时间戳,需要汇报为坏块,且损坏原因为Reason.GENSTAMP_MISMATCH,即时间戳不匹配;

2.2.2、如果名字节点存储的数据块大小不等于汇报的数据块大小,需要汇报为坏块,且损坏原因为Reason.SIZE_MISMATCH,即大小不匹配;

2.2.3、其它情况下不是一个坏块;

2.3、如果是UNDER_CONSTRUCTION状态,数据还在被写入,所以可以忽略大小,只做以下时间戳的判断:

2.3.1、如果名字节点存储的数据块时间戳不等于汇报的数据块时间戳,需要汇报为坏块,且损坏原因为Reason.GENSTAMP_MISMATCH,即时间戳不匹配;

2.3.2、其它情况下不是一个坏块;

2.4、其他情况下均不是损坏的数据块;

3、数据块副本为正等待被恢复状态RWR的话,需要看数据块在名字节点NameNode的状态:

3.1、如果名字节点存储的数据块Block不是COMPLETE状态,则不是一个坏块,此时数据块尚未上报过名字节点NameNode;

3.2、如果名字节点存储的数据块是COMPLETE状态,说明之前已经上报过,需要判断时间戳是否一致,如果时间戳不一致的话,则说明其是一个坏块;

3.3、如果名字节点存储的数据块是COMPLETE状态,说明之前已经上报过,且时间戳一致的话,如果数据块副本为正在写入状态RBW,不会是一个损坏的数据块,否则为一个损坏的数据块,且损坏原因为Reason.INVALID_STATE;

4、其他情况下均为一个坏块,且损坏原因为Reason.INVALID_STATE。

BlockToMarkCorrupt是一个数据块标记为坏块的抽象数据结构,它包含四个成员变量,如下:

  1. /** The corrupted block in a datanode. */
  2. 数据节点上的坏块数据块信息
  3. final BlockInfo corrupted;
  4. /** The corresponding block stored in the BlockManager. */
  5. // 名字节点BlockManager中存储的相应的数据块信息
  6. final BlockInfo stored;
  7. // 损坏原因:字符串类型
  8. /** The reason to mark corrupt. */
  9. final String reason;
  10. // 损坏原因code:枚举类型
  11. /** The reason code to be stored */
  12. final Reason reasonCode;

其他的均是构造方法,及覆写的toString()方法,不再赘述!

HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. HDFS源码分析心跳汇报之数据结构初始化

    在<HDFS源码分析心跳汇报之整体结构>一文中,我们详细了解了HDFS中关于心跳的整体结构,知道了BlockPoolManager.BPOfferService和BPServiceActo ...

  8. HDFS源码分析心跳汇报之周期性心跳

    HDFS源码分析心跳汇报之周期性心跳,近期推出!

  9. HDFS源码分析心跳汇报之DataNode注册

    HDFS源码分析心跳汇报之DataNode注册,近期推出!

随机推荐

  1. POJ3687 Labeling Balls

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13645   Accepted: 3955 Description Wind ...

  2. linux中的vi编辑器(一)

    1.在linux中如果两个用户都在打开一个文件进行编辑,那么文件最后将以最后保存的版本为主. 2.vi仅仅是一个文本编辑器,相当于windows中的记事本,vi的工作模式, 命令模式:在该模式下,在键 ...

  3. duilib入门简明教程 -- 自绘标题栏(5) (转)

    原文转自 http://www.cnblogs.com/Alberl/p/3343667.html         如果大家有做过标题栏的自绘,肯定会感慨各种不容易,并且现有的一些资料虽然完美的实现了 ...

  4. css 之 position定位

    position属性一共有4个值,分别是static.absolute.relative.fixed. static为默认值,指块保持在原本应该在的位置上,即该值没有任何移动的效果. absolute ...

  5. C结构体struct用法小结

    结构体和int,float等类型一样是一种常用的类型,它是由各种基本数据类型构成,通常包含有struct关键字,结构体名,结构体成员,结构体变量. 一.结构体定义 通常有3种定义方式,以例子方式表示: ...

  6. Android代码中设置字体大小,字体颜色,显示两种颜色.倒计时效果

    Android代码中设置字体大小,字体颜色,显示两种颜色 在xml文件中字体大小用的像素 <TextView android:id="@+id/uppaid_time" an ...

  7. bzoj 5125: [Lydsy1712月赛]小Q的书架

    新学了一波 决策单调性 dp 套路.... 这种dp一般是长这样的 => f[i][j] = max/min  { f[i-1][k] + cost(k+1,j)} ,其中cost函数满足四边形 ...

  8. NOIP2016模拟赛三 Problem C: 不虚就是要AK

    题目大意 给定一棵带有边权的树, 问你在树上随机选两个点, 它们最短路径上的边权之和为\(4\)的倍数的概率为多少. Solution 树分治. 没什么好讲的. #include <cstdio ...

  9. Jenkins插件HTML Publisher Plugin的使用

    前提: 下载插件HTML Publisher plugin 一.安装 安装好HTML Publisher plugin之后,会在新建或者编辑项目时,在[增加构建后操作步骤]出现[Publish HTM ...

  10. Linux命令大总结

    from http://elain.blog.51cto.com/3339379/623310 Linux命令大总结------------------------------------------ ...