使用 inotifywait 和 mkfifo 的“即时”文件系统

使用 inotifywait 和 mkfifo 的“即时”文件系统

我正在编写一些粗略的中间件 - 基本上,我有一些旧代码需要打开 100,000 个文件进行只读,并期望它们都位于一个文件夹中。它从不写入。它是多进程,因此它可以尝试同时打开约 30 个文件。按照旧方法,我必须将文件实际复制到该文件夹​​中(或使用链接、NFS 等)。值得注意的是,我无法更改这个旧代码 - 它只是一个二进制文件。

我有一些新的、奇特的代码,可以几乎立即检索文件。我想把这些东西结合在一起,这样当旧代码尝试打开文件时,它实际上是在实时运行新代码。

所以我想到了 mkfifo 和 inotifywait。我可以创建一个包含 100,000 个命名管道的文件夹,而不是一个包含 100,000 个文件的文件夹。到目前为止一切顺利。遗留代码会打开文件,但不知道它们确实是命名管道。问题是,我不知道遗留代码将以什么顺序打开文件(很好,对吧?)。因此,当遗留代码进入读取时,我想触发命名管道写入(来自我新奇的代码)。我无法生成 100,000 次写入并让它们全部阻塞。所以我想嘿 - inotifywait 是有意义的。每次遗留打开管道时,它都会触发读取事件,然后可以使用该事件在后台生成管道写入器。问题是.. inotifywait 直到生成写入器后才会触发读取事件!

有什么办法可以解决这个问题吗?基本上 - 我想拦截一个文件的打开,在检索文件内容时阻塞几百毫秒,然后返回该内容。理想情况下,我不必创建自定义 FUSE 文件系统来执行此操作。它只是一个只读文件打开。问题是这需要快速并行运行。我不知道哪些文件将以什么顺序打开。必须是一种快速而粗略的方法!

提前感谢大家的时间。

编辑 - 了解更多详细信息。基本上,我有一些遗留的代码,它们想要加载一个装满 PNG 文件的文件夹。我希望这些 PNG 文件实际上来自返回 DICOM 文件的 Web 服务器。这需要一些丑陋的转换等。遗留的 PNG 加载代码非常不灵活……它希望这些东西是文件。所以基本上,我想拦截 PNG 加载代码的 fopen,并首先运行以下四行 bash 伪代码。以下内容$URL_FOR_DICOM可以从文件名中得出$LADY_LOADED.png

wget -q -O $LAZY_LOADED.dcm $URL_FOR_DICOM
dcmj2pnm --write-png $LAZY_LOADED.dcm $LAZY_LOADED.png
rm $LAZY_LOADED.dcm
convert $LAZY_LOADED.png -resize 1024x1024^ -gravity center -extent 1024x1024 $LAZY_LOADED.png

因此,当 PNG 加载器尝试加载时$LAZY_LOADED.png(实际上是 FIFO),它将使用上述方法进行填充,理想情况下由 inotify 触发。我无法提前执行此操作,因为数据集非常庞大 - 接近 0.5PB.. 所以我无法保留第二份副本,我需要从 Web 服务器动态加载它。

编辑 2- 当在命名管道上尝试 ifnotifywait 时,它会阻止任何事件(包括打开、访问、读取等),直到命名管道打开进行写入和读取...(即无法检测读取器是否已准备就绪)... 有什么想法吗?另一个用户遇到了类似的问题这里没有解决方案:(

答案1

如果你需要它“快速且并行”,请尽量不要重新发明轮子:内核文件系统和页面缓存是具体来说调得非常快,很多比您自定义的“用户空间中的文件系统”更快。

您有多个更好的选择:

  • 将文件复制到临时位置;
  • 甚至更好的是,而不是复制它们,使用软链接或硬链接;
  • 通过只读 NFS 挂载导出它们

最后,请注意 inotify 是一个最大努力框架来传递文件事件。在高负载下,通知可能会丢失,尤其是在使用高级语言绑定(即 Python)时。

编辑:因此,您需要拦截读取以进行即时文件转换。从空管道读取时,您的旧代码将阻塞,因此inotifywait只有在您将某些内容写入同一管道后才会显示 READ 事件。为避免此问题,您应该尝试监听 OPEN 事件(而不是 READ)。另一个选择是使用 LD_PRELOAD 将经典的 open() 系统调用替换为自定义版本,该版本将根据需要转换文件。

答案2

OK - so not ideal but I hope it helps:

This seems to work (perhaps with threading issues but fine for my use case?).

$ echo hello > hello.txt
$ mknod tmp p
$ while true; do  cat /dev/null > tmp; done &
$ (inotifywait -m -e open ./tmp | while read f; do cat hello.txt > tmp; done) &


$ cat tmp
hello
$ cat tmp
hello

相关内容