Apache IoTDB源码解析(0.11.2版本):MultiFileLogNodeManager服务解析

当前版本Apache IoTDB 0.11.2

1. 声明

当前内容主要为了解MultiFileLogNodeManager这个类的作用,再讨论Apache IoTDB的wal实现方式flush策略(这个类是由IoTDB这个类中使用RegisterManager进行注册的)

从名称看应该是多文件日志节点管理器(应该就是写Wal文件的管理器,这个类位于org\apache\iotdb\db\writelog\manager包下面)

2. 分析源码

由于registerManager的register方法,所以必定调用start方法,现在看一下该类的字段和构造函数
在这里插入图片描述
这里在无参构造器的下面,构建了一个从测点映射到写日志的并发Map,并且字段中有ScheduledExecutorService表明是一个定时任务

继续查看start方法

 @Override
  public void start() throws StartupException {
    try {
      // 从配置(iotdb-engine.properties)中得到当前是否开启wal,这里一般都是true
      if (!config.isEnableWal()) {
        return;
      }
      // 判断当前执行wal的间隔时间是否有,该事件必须大于0
      if (config.getForceWalPeriodInMs() > 0) {
        executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(this::forceTask, config.getForceWalPeriodInMs(),
            config.getForceWalPeriodInMs(), TimeUnit.MILLISECONDS);
      }
    } catch (Exception e) {
      throw new StartupException(this.getID().getName(), e.getMessage());
    }
  }

这里非常明显就是从配置中得到封口wal的间隔时间(毫秒),并周期性的执行当前类的forceTask方法,从配置文件中得到这个间隔时间为100ms
在这里插入图片描述

这里应该可以得到信息wal是定时任务写入的,应该和前面的一个并发Map有关(将内存中的日志写入到磁盘中的wal)

继续查看forceTask方法

 private final void forceTask() {
    if (IoTDBDescriptor.getInstance().getConfig().isReadOnly()) {
      logger.warn("system mode is read-only, the force flush WAL task is stopped");
      return;
    }
    if (Thread.interrupted()) {
      logger.info("WAL force thread exits.");
      return;
    }

    for (WriteLogNode node : nodeMap.values()) {
      try {
        node.forceSync();
      } catch (IOException e) {
        logger.error("Cannot force {}, because ", node, e);
      }
    }
  }

果然这里就是将内存中的测点映射的WriteLogNode(将内存的写入到磁盘的wal),这里调用WriteLogNode的forceSync()方法

这里发现getNode中new了一个ExclusiveWriteLogNode,在通过查看源码发现这就是该wal日志的实现类(发现WriteLogNode就是一个接口)

转到ExclusiveWriteLogNode的forceSync方法中
在这里插入图片描述

 @Override
  public void forceSync() {
    sync(); // 将内存中的byte写入到磁盘
    forceWal();//进行封口
  }

转到sync方法

 private void sync() {
    lock.writeLock().lock();
    try {
      if (bufferedLogNum == 0) {
        return;
      }
      try {
       // 得到文件写入器,将该buffer写入到文件中
        getCurrentFileWriter().write(logBuffer);
      } catch (IOException e) {
        logger.error("Log node {} sync failed, change system mode to read-only", identifier, e);
        IoTDBDescriptor.getInstance().getConfig().setReadOnly(true);
        return;
      }
      logBuffer.clear();
      bufferedLogNum = 0;
      logger.debug("Log node {} ends sync.", identifier);
    } finally {
      lock.writeLock().unlock();
    }
  }

这里得到将内存的buffer写入到磁盘中,但是肯定有些buffer的方法(为此找到一个write的方法)

@Override
  public void write(PhysicalPlan plan) throws IOException {
    lock.writeLock().lock();
    try {
      putLog(plan); // 存放一个物理计划到内存中
      if (bufferedLogNum >= config.getFlushWalThreshold()) {
        sync();
      }
    } catch (BufferOverflowException e) {
      throw new IOException(
          "Log cannot fit into the buffer, please increase wal_buffer_size", e);
    } finally {
      lock.writeLock().unlock();
    }
  }

  private void putLog(PhysicalPlan plan) {
    logBuffer.mark(); 
    try {
      // 将物理计划序列化到buffer中
      plan.serialize(logBuffer);
    } catch (BufferOverflowException e) {
      logger.info("WAL BufferOverflow !");
      logBuffer.reset();
      sync();
      plan.serialize(logBuffer);
    }
    bufferedLogNum ++;
  }

至此,所有线路全部通了,wal中就是一个物理计划类序列化并使用标记按各个标识进行存放的byte内容,所以是先有物理计划-->buffer-->wal

3. 观察写入时的wal

先保证所有的wal都已经flush了,然后在打开写入一个数据
在这里插入图片描述
观察服务器:
在这里插入图片描述
发现这个创建的是一个叫做root.test-1626312981377-1-0.tsfile的文件夹,从文件夹中发现了一个叫做wal1的文件
在这里插入图片描述
回看data中的tsfile文件,发现了这个1626312981377-1-0.tsfile文件 (这应该表示该wal1的前日志是对应的这个tsfile吗?)

上述中证明了的确是有wal文件的产生,并且类也是使用正确的,从上述中证明了IoTDB中的写前日志是先内存再写磁盘的

4. 总结

1. 总算解析完了这个类,证明这个MultiFileLogNodeManager就是定时将内存中的计划buffer写入到磁盘wal中

2. 这也解决了我在项目中的一个疑惑,为什么有的数据写着写着,当IoTDB进入只读后(此时是可以查询到数据的),重启IoTDB后之前写的数据会丢失的问题(查不到数据了)!(只读后,没有机会将内存中的计划写入磁盘wal中,不会有 node.forceSync();执行了!小心这个问题)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值