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

Posted 你是小KS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();执行了!小心这个问题)

以上是关于Apache IoTDB源码解析(0.11.2版本):MultiFileLogNodeManager服务解析的主要内容,如果未能解决你的问题,请参考以下文章

Apache IoTDB源码解析(0.11.2版本):Session的源码解析

Apache IoTDB源码解析(0.11.2版本):RPC服务启动解析

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

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

Apache IoTDB源码解析(0.11.2版本):Session执行executeQueryStatement的源码解析

Apache IoTDB源码解析(0.11.2版本):Session执行executeQueryStatement的源码解析