如何仅在文件完成后才处理 nfsv3 上的文件?

如何仅在文件完成后才处理 nfsv3 上的文件?

我有一个 NFS 挂载,文件(有时具有一定大小)正在由不同的系统写入,现在我正在轮询新文件。我需要等到文件完全完成才能使用我的脚本处理它。我不控制写入这些文件或其名称的过程。

fusionr 和 lsof 似乎检查了我的本地系统,但如果不同的系统正在写入 NFS 挂载,则无法正确处理。我不相信如果它是 v3,我可以监听文件事件(但我可以监听 v4?),并且不需要等待一段时间让文件大小停止增长(并祈祷网络不会出现问题),我不知道有什么方法可以保证它的完整性,就像您在本地查找文件句柄一样。有解决办法吗?如果没有,是否有适用于 NFSv4 的解决方案?

答案1

nfsv3是无状态的,没有办法保证它的状态。但是 NLM(网络锁定管理器)必须在两侧运行。

nfsv4 具有锁定操作 open/read/write/lock/close 并保持 OPEN CLOSE 状态。如果可以的话,您应该更改为 nfsv4。

http://nfs.sourceforge.net/#faq_a6

答案2

理想的解决方案是发送者将文件放置在带有临时后缀 ( .tmp) 的 NFS 共享上,并仅在复制完成后才重命名:

# Sender
# There are better ways of writing this code; it's just an illustration
#
if cp /from/source/data.xml /to/nfs/share/data.xml.tmp
then
    # copy succeeded; rename
    mv -f /to/nfs/share/data.xml.tmp /to/nfs/share/data.xml
fi

即使在 NFS 上,重命名也是原子的,因此只要接收者忽略带有后缀的文件.tmp,任何其他文件(data.xml在本示例中)都会在接收者看来立即完全到达 NFS 共享。

但是,您解释说不幸的是您无法控制发件人。

在这种情况下,您实际上无法做太多事情来保证文件已完全传输。各种选项包括在数据中查找 END 标记(特定于正在传输的数据的标记,不一定是文字“END”字符串),或在处理文件之前尝试解析文件。以下是检查 XML 文件的示例:

# XML validation
if xmlstarlet validate /to/nfs/share/data.xml
then
    # An XML file validated so it must be complete
    ...
fi

将此方法加入到仅考虑文件几分钟内未更改的方法中,您可能会得到一个可行的解决方案:

find /to/nfs/share -type f -mmin +5 -name '*.xml' -print0 |
    while IFS= read -d '' file
    do
        if validate-the-file "$file"
        then
            process-the-file "$file"
            rm -f "$file"
        fi
    done

或者

find /to/nfs/share -type f -mmin +5 -name '*.xml' -exec sh -c '
    for file in "$@"
    do
        process-the-file "$file"
        rm -f "$file"
    done
' _ {} +

相关内容