zoukankan      html  css  js  c++  java
  • HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()

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

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

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

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

            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是一个数据块标记为坏块的抽象数据结构,它包含四个成员变量,如下:

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    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()方法,不再赘述!

  • 相关阅读:
    第三章第四章总结
    java学习2打架代码编写
    windows server 2008 远程桌面(授权、普通用户登录)
    Windows组建网络服务 ——WEB服务器的组建与架构
    windows server 2008 站点系列
    将 Ubuntu 加入到 Windows 2003 AD域
    Windows Server 2008组策略管理与配置
    AD用户设置系列
    利用windows 2003实现服务器群集的搭建与架设
    server2008 跨进新的平台(三)高端的备份还原工具
  • 原文地址:https://www.cnblogs.com/jirimutu01/p/5556264.html
Copyright © 2011-2022 走看看