USN日志处理移动事件时的补充

在写完通过读取USN日志监控文件变动之后,又陆陆续续踩了一些坑,修复了一些客户反馈的bug,主要是移动相关的问题。在这做一下记录,希望能帮到其他的人(应该也没人会去踩这种坑吧。。。)

等待移动队列

通过读取USN日志监控文件变动中提到:

  1. 文件id为X的文件从A移动到B
  2. 文件id为Y的文件从C移动到A

这种场景,在部分情况下会上报

  1. file id为X,USN_REASON包含RENAME_OLD_NAME,名称为A的记录
  2. file id为Y,USN_REASON包含RENAME_OLD_NAME,名称为C的记录
  3. file id为Y,USN_REASON包含RENAME_NEW_NAME和CLOSE,名称为A的记录
  4. file id为X,USN_REASON包含RENAME_NEW_NAME和CLOSE,名称为B的记录

原本认为是使用Transactional NTFS (TxF)技术的软件造成的,但无法复现出来,具体原因仍然有待调查。
如果直接依靠USN_REASON_RENAME_NEW_NAME的到达顺序来判断文件实际的移动顺序,则就会将该场景误判为C移动到B再移动到A。
为了解决这个问题,我们实现了一个等待移动队列,里面的单个元素,包含发生移动的文件ID,以及对应的包含USN_REASON_RENAME_NEW_NAME | CLOSE的记录

  1. USN_REASON_RENAME_OLD_NAME抵达后,向队列尾部添加对应文件ID,记录为空的元素。
  2. 在USN_REASON_RENAME_NEW_NAME | CLOSE记录抵达后,根据记录中的文件ID,查找队列中该ID对应的元素位置并存储记录。并将队列起始位置开始取元素的记录,直到遇到记录为空的情况。

最终输出的事件顺序即为真实的移动顺序。

对移动后仍然保持打开状态文件的处理

在上线等待移动队列后,我们发现部分客户出现了监控事件延迟的问题。经过排查后发现,部分文件(常见于系统日志)在移动后不发送包含USN_REASON_RENAME_NEW_NAME | CLOSE的记录,或发送间隔极长,导致移动事件都积压在等待移动队列中。
为了适配这种场景,我们又在等待队列中的元素中记录了入队时间。并做了如下修改:

  1. USN_REASON_RENAME_OLD_NAME抵达后,除了添加文件ID,还会删除队列中同文件ID的元素。
  2. USN_REASON_RENAME_NEW_NAME | CLOSE记录抵达后,除了存储记录,还会将队列前记录为空但入队时间超过指定间隔的元素移到最后并重置入队时间,之后再从队列起始位置开始取元素的记录。

两种操作的目的都是为了将相关记录移动到队列尾部,确保不阻塞其他文件的移动事件。