如何解决FSEventStream中的破坏事件压缩

时间:2017-04-26 15:16:04

标签: c++ macos fsevents

我们的C ++应用程序使用FSEventStream以文件级粒度监视文件系统(使用kFSEventStreamCreateFlagFileEvents标志创建流),每个卷有一个侦听器。但是,Apple FSEvent API中似乎存在一些错误/错误,这源于它们在将数据流发送给我们之前如何从流中压缩(删除重复)事件:

  1. 轻微但令人讨厌:当使用先前的事件id作为起点启动流时(为了捕获自上次监视以来对文件系统的更改),提供的事件的顺序是与我们在事件发生时监听事件时得到的不同,因为事件不是按照eventId顺序到达,而是按字母顺序按字母顺序排序。我们通过在处理集合之前在id-sorted列表中累积所有历史事件来解决这个问题。

  2. 重要:如果重命名事件发生得足够快,那么在回调函数中给我们的实际事件并不代表文件系统上实际发生的事件。考虑我们交换目录名称的测试用例:

    一个。更改文件

    湾将其父目录重命名为_temp

    ℃。将另一个目录重命名为以前父级的名称

    d。在步骤c中将_temp重命名为dir。

  3. 如果我们在每个步骤之间放置50毫秒的延迟(基本上,任何延迟保证给定事件不会与另一个事件在同一个回调中),我们得到正确的事件序列(重命名显示作为一对事件):

    fsEventsCallback: Received FSEvents callback with 1 events:
    fsEventsCallback: ID=34303406 PATH= /Users/stebro/swaptest/subdir1/file_1.txt FLAGS=kFSEventStreamEventFlagItemInodeMetaMod, kFSEventStreamEventFlagItemIsFile, kFSEventStreamEventFlagItemModified
    fsEventsCallback: Received FSEvents callback with 2 events:
    fsEventsCallback: ID=34303436 PATH= /Users/stebro/swaptest/subdir1 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: ID=34303437 PATH= /Users/stebro/swaptest/subdir1_temp FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: Received FSEvents callback with 2 events:
    fsEventsCallback: ID=34303620 PATH= /Users/stebro/swaptest/subdir2 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: ID=34303621 PATH= /Users/stebro/swaptest/subdir1 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: Received FSEvents callback with 2 events:
    fsEventsCallback: ID=34303741 PATH= /Users/stebro/swaptest/subdir1_temp FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: ID=34303742 PATH= /Users/stebro/swaptest/subdir2 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    

    但是,没有延迟(或者延迟足够小以至于多个重命名事件将在同一个回调调用中到达),操作系统似乎正在使用“支持”删除它所看到的冗余事件,从而产生在这个烂摊子里:

    fsEventsCallback: Received FSEvents callback with 4 events:
    fsEventsCallback: ID=34251572 PATH= /Users/stebro/swaptest/subdir1/file_1.txt FLAGS=kFSEventStreamEventFlagItemInodeMetaMod, kFSEventStreamEventFlagItemIsFile, kFSEventStreamEventFlagItemModified
    fsEventsCallback: ID=34251580 PATH= /Users/stebro/swaptest/subdir1 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: ID=34251583 PATH= /Users/stebro/swaptest/subdir1_temp FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    fsEventsCallback: ID=34251584 PATH= /Users/stebro/swaptest/subdir2 FLAGS=kFSEventStreamEventFlagItemIsDir, kFSEventStreamEventFlagItemRenamed
    

    我们可以做些什么来抑制这种压缩吗?我们正在使用此调用创建流:

    FSEventStreamCreateRelativeToDevice(kCFAllocatorDefault,
                                        &fsEventsCallback,
                                        &context,
                                        device,
                                        reinterpret_cast<CFArrayRef>(_monitoredPaths),
                                        lastEventId,
                                        0, // Latency - problem exists with values of 1, 0.1 and 3 as well
                                        kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer);
    

1 个答案:

答案 0 :(得分:1)

过度激进的事件折叠的解决方案可以使用kFSEventStreamCreateFlagUseExtendedData(自OS X 10.13起可用)。使用该标志创建的流将包含事件文件的 inode 。这样,您可以检测到在报告的事件批次中发生的“重命名链”。

P.S。我在文件监视器中尝试了您的方案;事件顺序是正确的。