使用写时复制 (COW) 在 Python 中复制文件

问题描述

我的文件系统 (FS)(特别是 ZFS)支持写时复制 (COW),即复制(如果做得对)是一种非常便宜的常量操作,实际上并不复制底层内容内容仅在我写入/修改文件时复制。

实际上,我刚刚发现,ZFS-on-Linux 实际上还没有为用户空间实现它(对吧?)。 但是例如BTRFS 或 XFS 都有。 (见herehereherehere。)

对于 (GNU) cp 实用程序,您将传递 --reflink=always 选项 (见here。) cp 调用 ioctl (dest_fd,FICLONE,src_fd) (见herehere)。

我将如何在 Python 中获得这种行为(如果可能)?

我认为“零拷贝”(例如 here via os.sendfile)不会导致这种行为,对吗?因为查看 shutil_fastcopy_sendfile 实现(here),它仍然是使用一些自定义字节计数(应该是块大小,os.sendfile }})。或者会吗?

COW,这是在文件级别还是块级别?

如果可能的话,我也希望它是通用的和跨平台的,尽管我在这里的问题有点侧重于 Linux。 一个专门关于 Mac 的相关问题似乎是 this。 MacOSX max(os.fstat(infd).st_size,2 ** 23) 具有用于克隆文件cp 选项。

解决方法

在进一步搜索时,我确实找到了答案,以及相关的问题报告。

Issue 37157 (shutil: add reflink=False to file copy functions to control clone/CoW copies (use copy_file_range)) 正是关于这一点,它将在 Linux 上使用 FICLONE/FICLONERANGE

所以我假设 shutil 会在即将推出的 Python 版本中支持这一点(也许从 Python 3.9 开始?)。

os.copy_file_range(自 Python 3.8 起),它包装了 copy_file_range (Linux)。

然而,根据 issue 37159 (Use copy_file_range() in shutil.copyfile() (server-side copy)) 的说法,Giampaolo Rodola:

不,[copy_file_range] 不[支持 CoW](参见手册页)。我们可以简单地使用 FICLONE(cp 也是如此)。

但是,我不确定这是否正确,正如 copy_file_range man page 所说:

copy_file_range() 给文件系统一个实现的机会 “复制加速”技术,例如使用引用链接 (即,共享指向同一副本的指针的两个或多个 inode- 写入磁盘块)或服务器端复制(在 NFS 的情况下)。

Issue 26826 (Expose new copy_file_range() syscall in os module) 有 Giampaolo Rodola 的评论:

我认为通过 FICLONE 更好地实现重复数据删除 / CoW / reflink 复制。 “cp --reflink”使用它,我认为是因为它比 copy_file_range() 更旧。 ...