IoTDB删除通过添加Modification 文件来实现,每一个TsFile都可能有一个Modification文件,该文件记录了对应TsFile文件中数据被删除的情况。
IoTDB的删除操作并不会真正删除TsFile中的实际数据,而是在查询过程中排除已被删除的数据,从而使用户得到的结果中不包含已被删除的部分数据。

0.12 之前版本
Modification 文件中的记录由timeseries path,删除version值,删除最小时间和最大时间组成。
删除version值用来记录执行删除时的版本,Modification文件中每条删除记录只会对version值较小的chunk起作用,不会对拥有更大version值的chunk起作用。


0.12 以后

Modification 文件中的记录由timeseries path,tsFileOffset,删除最小时间和最大时间组成。

tsFileOffset,用于表示delete对于相应的Tsfile文件生效的文件位置,如果TsFile中一个chunk的offset小于等于tsFileOffset,则表示delete对这个chunk生效。


对于以下的任意删除语句

DELETE FROM <PrefixPath> [COMMA <PrefixPath>]*

实际的删除过程分为Delete和Query两部分,执行delete语句之后IoTDB实际上只有Delete流程被执行,删除记录写入Modification文件。其他的删除工作在Query过程中生效。


若对某个正在被合并的TsFile产生删除操作时,会往对应的mods文件追加一条deletion记录,并新建一个.compaction.mods文件用于记录合并中产生的删除记录,当合并完成后会将源文件的.compaction.mods文件里的删除记录追加写入到目标文件的.mods文件里,并删除源文件的相关文件。


Delete流程

对于以上delete语句中每一个PrefixPath,考虑到用户输入的中可能包含通配符"*",0.11版本中delete操作需要考虑一条delete语句删除多个时间序列数据的情况

StorageEngine.java 中的delete接口为:

   delete(PartialPath path, long startTime, long endTime)

在delete流程中需要考虑如下三种情景下的数据删除。

  1. 删除working memory table中的数据

    由于working memory table存在于内存中,在delete语句执行过程中可以直接删除满足条件的数据。
    在TVList.java中通过delete()方法将所有已被删除的数据直接排除在最终结果之外。

    public int delete(long lowerBound, long upperBound) {
       int newSize = 0;
       minTime = Long.MAX_VALUE;
       for (int i = 0; i < size; i++) {
         long time = getTime(i);
         if (time < lowerBound || time > upperBound) {
           set(i, newSize++);
           minTime = time < minTime ? time : minTime;
        }
      }

  2. 删除flushing memory table中的数据

    正在处于flushing状态中的memory table是不可变的,因此不能像working memory table那样直接删除。
    对于flushing状态中的memory table,每做一次删除操作,该memory table将这个deletion对象添加到自己的deletionList当中。

    public void delete(Deletion deletion) {
       this.modifications.add(deletion);
    }

  3. 删除TsFile中的数据

    对于已存在与tsfile中的数据,直接在相应的Tsfile的modification file中添加一行删除记录即可,在之后的查询过程中会提取删除记录用于查询数据过滤。


Query流程

在上述Delete流程所提到的三种情况中,对于2和3的删除只是将删除记录到变量中或Modification file中,实际的删除操作由查询流程完成。

查询flushing memory table中的数据

AbstractMemtable.java 的query()方法负责对给定的timeseries进行查询。

由于在delete流程中已经储存了所有该timeseries的所有deletion记录,查询前只需要对deletionList的所有的TimeRange元素按照删除起始时间进行排序,以提高查询时检索删除记录的速度。
查询时遍历TVList中每一个数据点,使用已排好序的deletionList对所有数据点进行过滤,将未被删除的数据加入到结果集中。具体的过滤过程由TVlist.java中的isPointDeleted()方法完成。

  private boolean isPointDeleted(long timestamp) {
    while (deletionList != null && deleteCursor < deletionList.size()) {
      if (deletionList.get(deleteCursor).contains(timestamp)) {
         return true;
      } else if (deletionList.get(deleteCursor).getMax() < timestamp) {
         deleteCursor++;
      } else {
         return false;
      }
  }
    return false;
}

查询TsFile中的数据

查询TsFile中被删除的数据过程也分为两个阶段

  1. 调用StorageEngine.java中的query()方法,用来得到所有相关的顺序文件和乱序文件。

    在此过程中,所有对于TsFile的删除记录将会被存入每个chunkMetadata中,为阶段2中的查询做准备。
    这一过程位于QueryUtils.java的modifyChunkMetaData()方法中。首先取得每个TsFile对应的Modification file中的deletion记录,遍历TsFile中所有的chunkMetadata结构,

    如果deletion的version值大于chunkMetadata中的version 值,则说明这个deletion对此chunkMetadata是应该生效的,加入此chunkMetadata的deletionList。
    在此处也可以判断一个chunkMetadata是否被完全删除,被完全删除的chunkMetadata也会从Tsfile的chunkMetadataList中删除。

  2. 在SeriesReader中查询具体的数据点

    所有相关的delete信息已被存入chunkMetadata的deletionList中,因此每个chunk中的page也能够得到与该page相关的deletion信息。

    在扫描page时即可去掉所有被deletionList所覆盖的数据点,从而得到最终的查询结果。


  • No labels