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的源码解析