1

我有三个设计为在 Linux 和 Mac OS X 环境中持续运行的进程。一个进程(下载程序)每 30 秒下载并存储一个大型 XML 文件的本地副本。另外两个进程(Worker)使用存储的 XML 文件进行输入。每个 Worker 随机启动和运行。由于 XML 文件很大,因此下载需要很长时间。工人也需要很长时间来阅读和解析它。

设置进程的最安全方法是什么,以便在工作人员尝试读取文件时,下载程序不会破坏存储的文件?

4

1 回答 1

4

对于使用基于inode的文件系统的 Linux 和 Mac OS X 机器,在下载数据时使用临时文件来存储数据(并且是不完整的状态)。下载完成后,使用原子操作将临时文件移动到其最终位置。

更详细一点,当一个进程(例如 Downloader)写入一个被其他进程(例如 Workers)主动读取的文件时,有两件主要的事情需要注意:

  1. 确保在下载器完成写入文件之前,Worker 不会尝试读取文件。
  2. 确保下载器在工作人员读取文件时不会更改文件。

使用临时文件可以满足这两点。

举个更具体的例子,当下载器主动拉取 XML 文件时,让它写入将存储最终文件的同一设备/磁盘*上的临时位置(例如“data-storage.tmp”)。一旦文件被完全下载并写入,让下载器通过一个原子(又名可线性化)重命名命令(如 bash 的mv.

*请注意,临时文件需要与最终文件位置位于同一设备上的原因是为了确保 inode 编号保持不变并且可以原子地进行重命名。

这种方法确保在下载/写入文件时,Worker 不会看到它,因为它位于 .tmp 位置。由于重命名与 inode 一起工作的方式,它还确保打开文件的任何 Worker 继续看到旧内容,即使放置了新版本的数据存储文件。

下载器在重命名时会将“data-storage.xml”指向一个新的 inode 编号,但 Worker 将继续从之前的 inode 编号访问“data-storage.xml”,从而继续在该状态下处理文件. 同时,任何在 Downloader 完成重命名后打开新副本“data-storage.xml”的 Worker 都将看到来自新 inode 编号的内容,因为它现在是文件系统中直接引用的内容。因此,两个 Worker 可以从相同的文件名 (data-storage.xml) 中读取,但每个 Worker 都会看到文件内容的不同(和完整)版本,这取决于文件名首次打开时指向的 inode .

为了看到这一点,我在github上创建了一组简单的示例脚本来演示此功能。它们还可用于测试/验证使用临时文件解决方案是否适用于您的环境。


重要的一点是,重要的是特定设备上的文件系统。如果您使用的是 Linux 或 Mac 机器,但使用的是 FAT 文件系统(例如,USB 拇指驱动器),则此方法不起作用。

于 2013-03-20T09:02:06.143 回答