重启恢复流程

重启恢复是以存储组为粒度进行的,恢复的入口是 StorageGroupProcessor 的 recover()

存储组恢复流程

  • org.apache.iotdb.db.engine.storagegroup.StorageGroupProcessor.recover()

  • 首先获得该存储组下所有以.tsfile结尾的数据文件,返回 TsFileResource,共有如下几个文件列表

  • 顺序文件

    • 0.10 版本的文件(封口/未封口)
    • 0.9 版本的文件(封口)
  • 乱序文件

    • 0.10 版本的文件(封口/未封口)
    • 0.9 版本的文件(封口)
  • 若该存储组下有 0.9 版本的 TsFile 文件,则将旧版本的顺序和乱序文件分别加入upgradeSeqFileListupgradeSeqFileList中,供升级和查询使用。

  • 将顺序、乱序文件按照分区分组 Map<Long, List>

  • 恢复每个分区的顺序文件,将上一步获得的每个分区的顺序 TsFile 文件作为参数,调用recoverTsFiles进行恢复,该方法会将恢复后的顺序 TsFile 以TsFileResource 的形式放入sequenceFileTreeSet中,若该 TsFile 是此分区的最后一个,且未封口,则还要为其构造TsFileProcessor对象,并加入workSequenceTsFileProcessors中,该方法的具体细节会在下一小节阐述。

  • 恢复每个分区的乱序文件,将上一步获得的每个分区的乱序 TsFile 文件作为参数,调用recoverTsFiles进行恢复,该方法会将恢复后的乱序 TsFile 以 TsFileResource 的形式放入unSequenceFileList中,若该 TsFile 是此分区的最后一个,且未封口,则还要为其构造TsFileProcessor对象,并加入workUnsequenceTsFileProcessors中,该方法的具体细节会在下一小节阐述。

  • 分别遍历上两步得到的sequenceFileTreeSetunSequenceFileList,更新分区对应的版本号

  • 检查有没有merge时候的Modification文件,并调用RecoverMergeTask.recoverMerge方法对merge进行恢复

  • 调用updateLastestFlushedTime()方法,用 0.9 版本的顺序tsfile文件,更新latestTimeForEachDevice, partitionLatestFlushedTimeForEachDevice以及globalLatestFlushedTimeForEachDevice

    • latestTimeForEachDevice 记录了所有device已经插入的各个分区下的最新的时间戳(包括未flush的和已flush的)
    • partitionLatestFlushedTimeForEachDevice 记录了所有device已经flush的各个分区下的最新的时间戳,它用来判断一个新插入的点是不是乱序点
    • globalLatestFlushedTimeForEachDevice 记录了所有device已经flush的最新时间戳(是各个分区的最新时间戳的汇总)
  • 最后遍历sequenceFileTreeSet,用恢复出来的顺序文件,再次更新latestTimeForEachDevice, partitionLatestFlushedTimeForEachDevice以及globalLatestFlushedTimeForEachDevice

恢复一个分区的(顺序/乱序) TsFile

  • org.apache.iotdb.db.engine.storagegroup.StorageGroupProcessor.recoverTsFiles

该方法主要负责遍历传进来的所有 TsFile,挨个进行恢复。

  • 构造出TsFileRecoverPerformer对象,对 TsFile 文件进行恢复,恢复的逻辑封装在TsFileRecoverPerformerrecover()方法中(具体细节在下一小节展开阐述),该方法会返回一个恢复后的RestorableTsFileIOWriter对象。

    • 若恢复过程失败,则记录log,并跳过该tsfile
  • 若该 TsFile 文件不是最后一个文件,或者该 TsFile 文件是最后一个文件,但已经被关闭或标记被关闭,只需将该 TsFile 文件在内存中对应的TsFileResource对象的closed属性置成true即可。

  • 若该 TsFile 文件可以继续写入,则表示这是此分区的最后一个 TsFile,且未封口,则继续保持其未封口的状态,需要为它构造一个TsFileProcessor对象,并将其放到workSequenceTsFileProcessorsworkUnsequenceTsFileProcessors中。

  • 最后将恢复出来的 TsFile 文件在内存中对应的TsFileResource对象放入sequenceFileTreeSetunSequenceFileList

恢复一个 TsFile 文件

  • org.apache.iotdb.db.writelog.recover.TsFileRecoverPerformer.recover

该方法主要负责每个具体的 TsFile 文件的恢复。

  • 首先用tsfile文件构造出一个RestorableTsFileIOWriter对象,在RestorableTsFileIOWriter的构造方法中,会对该tsfile的文件内容进行检查,必要时进行截断

    • 如果这个文件中没有任何内容,则为其写入MAGIC_STRINGVERSION_NUMBER后,直接返回,此时的crashedfalsecanWritetrue
    • 如果文件中有内容,构造TsFileSequenceReader对象对内容进行解析,调用selfCheck方法进行自检,并将不完整的内容截断,初始化truncatedSizeHeaderLength
      • 若文件内容完整(有完整的头部的MAGIC_STRINGVERSION_NUMBER,以及尾部的MAGIC_STRING),则返回TsFileCheckStatus.COMPLETE_FILE
      • 若文件长度小于HeaderLength(len(MAGIC_STRING) + len(VERSION_NUMBER)),或者文件头部内容不是MAGIC_STRING,则返回INCOMPATIBLE_FILE
      • 若文件长度刚好等于HeaderLength,且文件内容就是MAGIC_STRING + VERSION_NUMBER,则返回HeaderLength
      • 若文件长度大于HeaderLength,且文件头合法,但文件尾部没有MAGIC_STRING,表示该文件不完整,需要进行截断。从VERSION_NUMBER往后读,读出chunk中的数据,并根据chunk中的数据恢复出ChunkMetadata,若遇到CHUNK_GROUP_FOOTER,则表示整个ChunkGroup是完整的,更新truncatedSize至当前位置
      • 返回truncatedSize
    • 根据返回的truncatedSize,对文件进行截断
      • truncatedSize等于TsFileCheckStatus.COMPLETE_FILE,则将crashedcanWrite置为false,并关闭文件的输出流
      • truncatedSize等于TsFileCheckStatus.INCOMPATIBLE_FILE,则关闭文件的输出流,并抛异常
      • 否则,将crashedcanWrite置为true,并将文件截断至truncatedSize
  • 通过返回的 RestorableTsFileIOWriter 判断文件是否完整

    • 若该 TsFile 文件是完整的

      • 若 TsFile 文件对应的 resource 文件存在,则将 resource 文件反序列化(包括每个设备在该tsfile文件中的最小和最大时间戳),并恢复文件版本号
      • 若 TsFile 文件对应的 resource 文件不存在,则重新生成resource 文件
      • 返回生成的 RestorableTsFileIOWriter
    • 若 TsFile 不完整

      • 调用recoverResourceFromWriter,通过RestorableTsFileIOWriter中的ChunkMetadata信息,恢复出resource信息
      • 调用redoLogs方法将这个文件对应的一个或多个写前日志文件中的数据都写到一个临时 Memtable 中,并持久化到这个不完整的 TsFile 中
        • 对于顺序文件,跳过时间戳小于等于当前 resource 的 WAL
        • 对于乱序文件,将 WAL 全部重做,有可能重复写入多个 device 的 ChunkGroup
      • 如果该 TsFile 不是当前分区的最后一个 TsFile,或者该 TsFile 有.closing文件存在,则调用RestorableTsFileIOWriterendFile()方法,将文件封口,并删除.closing文件,并为其生成resource文件