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

Copy file in Python with copy-on-write (COW)

我的文件系统 (FS)(特别是 ZFS)支持写时复制 (COW),即复制(如果做得好的话)是一种非常便宜的常量操作,实际上并不复制底层内容。内容只复制一次 write/modify 新文件。

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

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

如何在 Python 中获得此行为(如果可能)?

我假设“零拷贝”(例如 here via os.sendfile) would not result in such behavior, right? Because looking at shutils _fastcopy_sendfile implementation (here),它仍然是一个循环 os.sendfile 使用一些自定义字节数(应该是块大小,max(os.fstat(infd).st_size, 2 ** 23)).还是会?

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

如果可能的话,我希望它也是通用的和跨平台的,尽管我这里的问题有点 Linux 重点。 一个专门关于 Mac 的相关问题似乎是 。 MacOSX cp 具有克隆文件的 -c 选项。

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

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 (since Python 3.8), which wraps copy_file_range (Linux).

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

Nope, [copy_file_range] doesn't [support CoW] (see man page). We can simply use FICLONE (cp does the same).

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

copy_file_range() gives filesystems an opportunity to implement "copy acceleration" techniques, such as the use of reflinks (i.e., two or more inodes that share pointers to the same copy- on-write disk blocks) or server-side-copy (in the case of NFS).

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

I think data deduplication / CoW / reflink copy is better implemented via FICLONE. "cp --reflink" uses it, I presume because it's older than copy_file_range(). ...