New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reflink(Copy On Write)支持 #39
Conversation
|
我怀疑我是***但是我没有证据 |
在 review 前,请完成充分的测试,包括但不限于在不同系统平台下,开启/关闭所述功能的拷贝准确性,以及速度对比 |
拷贝准确性已完成测试,速度对比进行 |
为保证准确性删除session.lock后进行压缩对比md5 |
arch linux+ntfs:37.6s-48.1s windows11iso md5相同 |
windows+ntfs:60.9-61.5 |
原版qbm: 除了btrfs其他的都是误差范围 |
请在进行完所有的测试后,进行统一的结果汇总展示,而不是把这里当做测试实况播报 |
误差很大,但是除了btrfs其他的都是误差范围 拷贝准确性没有任何问题 |
测试方式是什么,包括速度的测试方式,以及准确性的测试方式 测试的环境是什么,包括具体系统版本,硬盘硬件信息 是否有测试多world_names的情况,world_names含单独文件的情况,world_name含文件路径分隔符的各种特殊情况 |
quick_backup_multi/__init__.py
Outdated
shutil.copy(src_path, dst_path) | ||
else: | ||
|
||
_cpcow(src_path, dst_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以考虑使用 shutil.copytree
函数的 copy_function
参数来实现自定义的拷贝,而非自己造一套递归拼路径的轮子(更容易出错,维护更麻烦)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果当前环境不支持 os.copy_file_range
,那就没必要走新的这堆逻辑了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以考虑使用
shutil.copytree
函数的copy_function
参数来实现自定义的拷贝,而非自己造一套递归拼路径的轮子(更容易出错,维护更麻烦)
已修改
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果当前环境不支持
os.copy_file_range
,那就没必要走新的这堆逻辑了
如果不支持,和shutil.copy2一样
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果不支持,和shutil.copy2一样
什么叫“一样”
quick_backup_multi/__init__.py
Outdated
shutil.copy(src_path, dst_path) | ||
else: | ||
shutil.copy(src_path, dst_path) | ||
elif os.path.isdir(src_path): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对于 elif
仍不匹配的情况,建议输出一条警告日志。现在这样什么都不做,在出问题时不好定位
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对于
elif
仍不匹配的情况,建议输出一条警告日志。现在这样什么都不做,在出问题时不好定位
134-135
if not os.path.isdir(src_path) and not os.path.isfile(src_path):
server_inst.logger.warning('{} does not exist while copying ({} -> {})'.format(src_path, src_path, dst_path))
确实移到拷贝函数里好一点
应该是没问题了 |
请不遗漏地阅读我提出的所有测试/实现的修改点,并做出完善/回应 |
备份三次时间,md5 只改了复制函数,world_names的判定还是之前的 |
#39 (comment) with open(src_path,'rb') as f11, open(dst_path,'wb+') as f21:
f1 = f11.fileno()
f2 = f21.fileno()
size = os.path.getsize(src_path)
if size > COW_COPY_LIMIT:
for i in range(0, size, COW_COPY_LIMIT):
os.copy_file_range(f1, f2, COW_COPY_LIMIT, i)
else:
os.copy_file_range(f1, f2, size) |
注意 with open(src_file, 'rb') as src, open(dst_file, 'wb') as dst:
while True:
if os.copy_file_range(src.fileno(), dst.fileno(), BLOCK_SIZE) <= 0:
break 同时,正如文档中所述
|
那样的话也许应该试试通用的增量备份? |
这是另一个 feature request,与本 PR 无关 |
也许应该更进一步成这样? with open(src_file, 'rb') as src, open(dst_file, 'wb') as dst:
while os.copy_file_range(src.fileno(), dst.fileno(), BLOCK_SIZE) :
pass |
当然可以。#39 (comment) 的代码仅仅是一个例子,并非必须实现 不过,修改后的实现进行了从 |
quick_backup_multi/__init__.py
Outdated
@@ -76,6 +76,30 @@ def get_backup_file_name(backup_format: BackupFormat): | |||
raise ValueError('unknown backup mode {}'.format(backup_format)) | |||
|
|||
|
|||
copy_file_range_supported=hasattr(os, "copy_file_range") | |||
COW_COPY_LIMIT = 2**30 # 1GB / need int, may overflow, so cannot copy files larger than 2GB in a single pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
现在这个变量的含义已经不再是个“limit”,更像是个“buffer/block size”。改成 COW_COPY_BUFFER_SIZE
什么的会不会更加准确?对应的,其注释也有些过时了。
除此之外,是否有测试过这个值取 1MiB、10MiB、1GiB 等情况下的性能表现。可以测一下取最优的
基本没什么问题了,然后就是得整理下代码格式,包括运算符前后的空格、 最后就是给 readme 加上新配置项的文档了 |
#39 (comment) 这里提的 |
更大的值会带来提升,但边际效应明显,精准测试不好做,因为提升还没有误差大, |
对于 #39 (comment) 中建议的测试,使用的 buffer 取值是更小的值,而非更大的值。毕竟这只是个 buffer,调整成 buffer 常见的大小可能会有不一样的性能表现 |
这不是buffer,这是减少python层循环次数的buffer-like 使用大量杂乱文件与其压缩包进行测试, 4k约为5s 边际效应非常明显,但是增加这个值没有任何坏处,在不出错的情况下应当尽可能提升这个值 |
在 cpython 的实现下,这个参数是会直接传递给系统调用的,因此这可能会对实际性能产生影响。虽然正如 #39 (comment) 所说,glibc 的实现是没问题的
我不认为 1E3 以下数量级的 python 循环会产生任何瓶颈,除非有相关的性能分析证明
能详细说明下吗,是分别测试,还是同时测试。没啥没问题的话,这样就 ok 了 |
同时
我的测试文件大概1E4, 1s确实不算瓶颈,但是总共也就几s欸 |
“我不认为 1E3 以下数量级”,这里的 1E3 指的是,使用 #39 (comment) 中建议取值最小的 10MiB 的情况,循环拷贝可能较大文件 10GiB,需要 10GiB / 10MiB = 约 1E3 次 python 循环调用 |
文件数量 不要低估日用linux平台的config目录 |
这跟你在 #39 (comment) 说的是不是不太匹配? “这不是buffer,这是减少python层循环次数的buffer-like。因为c循环不会构成瓶颈,但py循环会” 在谈论 buffer 作为上下文的时,循环次数应该指的是循环调用 |
对于 #39 (comment) 中的 对于测试结果,我已经反复多次提出该怎么客观严谨表述一份测试结果。#39 (comment) 中对结果的描述是非常含糊不清缺少信息的。 算了,估计你也不会好好测,就不浪费时间了,buffer 大小这部分影响也不大,就这样吧 |
不仅仅是大量小文件,还有整个打包的zip |
#38
未经过充分测试,基本功能正常
在btrfs下备份时间由30.1s缩短至2.2s
xfs,zfs同理
其他文件系统理论上无影响,未测试