You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

一、TsFileResource及接口设计修改目标

1. 每个数据文件 TsFile 在内存中对应一个文件索引信息TsFileResource,供查询使用。

2. 目标:目前tsfile采用一对一的索引方式,每个tsfile都有一个索引文件TsFileResource。由于TsFileResource常驻内存中,当有过多设备的情况下,就会报内存。

本次针对TsFileResouce的改进总目标为可以支持更多的设备。

3. 本次接口化目标:区分【文件句柄TsFileResouce】【文件索引FileIndexEntries】,将TsFileResouce中的字段放入FileIndexEntries中;

利用FileIndexEntries的接口完成文件索引相关功能;TsFileResouce中仅保留文件句柄的功能。


二、新增和修改的数据结构

具体而言,涉及到数据结构如下:

1. FileIndexEntries:

private TimeIndexEntry[] indexEntries; // TimeIndexEntry 列表,记录文件中所有的设备路径、开始时间和结束时间

private String tsFilePath; // TsFile 路径

2. TimeIndexEntry:

private PartialPath path; // 设备路径

private long startTime; // 开始时间

private long endTime; // 结束时间


第一步接口化(本次)的修改中,可以从TsFileResource中转移走的字段:

protected long[] startTimes; //  开始时间列表

protected long[] endTimes; // 结束时间列表,未封口则为 Long.MIN_VALUE

protected Map<String, Integer> deviceToIndex; // device设备名 => 开始 / 结束时间列表index


3. 相关接口:

1. FileIndexEntries convertFromTsFileResource(TsFileResource resource) // 将TsFileResource转化为FileIndexEntries,用于版本升级

2. List<FileIndexEntries> filterByPath(PartialPath path, Filter timeFilter) // 获得与查询相关的FileIndexEntries

3. boolean addIndexForPaths(FileIndexEntries fileIndexEntries) // 为路径增加索引,用于:(1)文件刷盘封口;(2)版本升级

4. boolean deleteIndexForPaths(FileIndexEntries fileIndexEntries) // 为路径删除索引,用于:(1)删除文件;(2)根据TTL标记失效的文件


4. 第二步的修改(后续)涉及到【封口文件句柄SealedTsfileResource】和【未封口文件句柄UnsealedTsfileResource

因为封口文件句柄需要的字段较少,未封口文件句柄可以继承封口文件句柄;文件封口时再转化为封口文件句柄。


三、涉及到使用文件索引的操作

【数据的插入和批量插入】

总入口: public void insert(InsertRowPlan insertRowPlan) StorageEngine.java

1. 找到对应的 StorageGroupProcessor

2. 根据写入数据的时间以及当前设备落盘的最后时间戳,找到对应的 TsFileProcessor

3. 【需修改】写入 TsFileProcessor 对应的 memtable 中:

(1) 如果是乱序文件,则更新tsfileResource中的endTimeMap (deviceToIndex, endTimes)

(2) 如果tsfile中没有该设备的信息,或新插入数据的时间小于已存startTime,则更新tsfileResource中的startTimeMap

4. 记录写前日志

5. 根据 memtable 大小,来判断是否触发异步持久化 memtable 操作。如果是顺序文件且执行了刷盘动作,则更新tsfileResource中的endTimeMap

6. 根据当前磁盘 TsFile 的大小,判断是否触发文件关闭操作


【数据的访问】

总入口StorageEngine: public QueryDataSource query(SingleSeriesExpression seriesExpression, QueryContext context, QueryFileManager filePathsManager)

需修改找到所有包含这个时间序列的顺序和乱序的 TsFileResource (文件索引)进行返回,供查询引擎使用


【重启恢复流程】

StorageGroupProcessorrecover()

1. 需修改恢复每个分区的顺序 / 乱序文件,将上一步获得的每个分区的乱序 TsFile 文件作为参数,调用recoverTsFiles进行恢复,该方法会将恢复后的顺序 / 乱序 TsFile 以 TsFileResource (文件句柄+文件索引)的形式放入(un)SequenceFileList中,若该 TsFile 是此分区的最后一个,且未封口,则还要为其构造TsFileProcessor对象,并加入work(Un)sequenceTsFileProcessors中

  • 若该 TsFile 文件不是最后一个文件,或者该 TsFile 文件是最后一个文件,但已经被关闭或标记被关闭,只需将该 TsFile 文件在内存中对应的TsFileResource(文件句柄)的closed属性置成true即可。
  • 若该 TsFile 文件可以继续写入,则表示这是此分区的最后一个 TsFile,且未封口,则继续保持其未封口的状态,需要为它构造一个TsFileProcessor对象,并将其放到workSequenceTsFileProcessors或workUnsequenceTsFileProcessors中。
  • 最后将恢复出来的 TsFile 文件在内存中对应的TsFileResource(文件句柄+文件索引)对象放入sequenceFileTreeSet或unSequenceFileList中,用于更新分区对应的版本号等

2. 需修改若该 TsFile 文件完整

若 TsFile 文件对应的 resource 文件(文件句柄+文件索引)存在,则将 resource 文件反序列化,并恢复文件版本号

若 TsFile 文件对应的 resource 文件(文件句柄+文件索引)不存在,则重新生成resource(文件句柄+文件索引) 文件

返回生成的 RestorableTsFileIOWriter

3. 需修改若 TsFile 文件不完整

调用recoverResourceFromWriter,通过RestorableTsFileIOWriter中的ChunkMetadata信息,恢复出resource信息

调用redoLogs方法将这个文件对应的一个或多个写前日志文件中的数据都写到一个临时 Memtable 中,并持久化到这个不完整的 TsFile 中

  • 对于顺序文件,跳过时间戳小于等于当前 resource(文件句柄) 的 WAL
  • 对于乱序文件,将 WAL 全部重做,有可能重复写入多个 device 的 ChunkGroup

如果该 TsFile 不是当前分区的最后一个 TsFile,或者该 TsFile 有.closing文件存在,则调用RestorableTsFileIOWriter的endFile()方法,将文件封口,并删除.closing文件,并为其生成resource(文件句柄)

四、涉及到使用文件句柄类的操作

【数据的删除】

StorageEngine.java中的入口: public void delete(String deviceId, String measurementId, long timestamp)

1. 找到对应的 StorageGroupProcessor

2. 【保留使用文件句柄类】找到受影响的所有 working TsFileProcessor 记录写前日志

3. 【保留使用文件句柄类】找到受影响的所有 TsFileResource,在其对应的 mods 文件中记录一条记录:pathversionstartTimeendTime

(1) 如果存在 working memtable:则删除内存中的数据

(2) 如果存在 正在 flush memtable,记录一条记录,查询时跳过删掉的数据(注意此时文件中已经为这些 memtable 记录了 mods




  • No labels