TISUnion / PrimeBackup

A powerful backup plugin for MCDR, an advanced backup solution for your Minecraft world
https://tisunion.github.io/PrimeBackup/
GNU Lesser General Public License v3.0
81 stars 5 forks source link

WSL中使用软链接回档失败 #7

Closed Worldy-MCX closed 10 months ago

Worldy-MCX commented 10 months ago

环境

WSL 版本: 2.0.9.0 内核版本: 5.15.133.1-1 WSLg 版本: 1.0.59 MSRDC 版本: 1.2.4677 Direct3D 版本: 1.611.1-81528511 DXCore 版本: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp Windows 版本: 10.0.22631.2861


mcdreforged 2.12.1 PrimeBackup 1.5.0 Python 3.9.18


日志

[MCDR] [19:07:07] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 10秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:08] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 9秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:09] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 8秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:10] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 7秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:11] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 6秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:12] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 5秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:13] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 4秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:14] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 3秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:15] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 2秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:16] [PB@7300-worker-heavy/INFO] [prime_backup]: [PB] !!! 1秒后将回档至备份#25: 测试pb1_5
[MCDR] [19:07:17] [PB@7300-worker-heavy/INFO] [prime_backup]: Wait for server to stop
[Server] [19:07:17] [Server thread/INFO]: Stopping the server
[Server] [19:07:17] [Server thread/INFO]: Stopping server
[MCDR] [19:07:17] [TaskExecutor/INFO]: rcon 已断开连接
[Server] [19:07:17] [Server thread/INFO]: Saving players
[Server] [19:07:17] [RCON Client /127.0.0.1 #2/INFO]: Thread RCON Client /127.0.0.1 shutting down
[Server] [19:07:17] [Server thread/INFO]: Saving worlds
[Server] [19:07:17] [Server thread/INFO]: Saving chunks for level 'ServerLevel[LMG空岛]'/minecraft:overworld
[Server] [19:07:18] [Server thread/INFO]: Saving chunks for level 'ServerLevel[LMG空岛]'/minecraft:the_end
[Server] [19:07:18] [Server thread/INFO]: Saving chunks for level 'ServerLevel[LMG空岛]'/minecraft:the_nether
[Server] [19:07:18] [Server thread/INFO]: ThreadedAnvilChunkStorage (world): All chunks are saved
[Server] [19:07:18] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved
[Server] [19:07:18] [Server thread/INFO]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved
[Server] [19:07:18] [Server thread/INFO]: ThreadedAnvilChunkStorage: All dimensions are saved
[Server] [19:07:19] [Server thread/WARN]: Found outdated translation keys in extension 'dev.dubhe.gugle.carpet.GcaExtension'!
[Server] These won't be supported in a later Carpet version!
[Server] Carpet will now try to map them to the correct keys in a best-effort basis
[Server] [19:07:19] [Server thread/INFO]: Thread RCON Listener stopped
[MCDR] [19:07:19] [MainThread/INFO]: 服务端进程返回代码: 0
[MCDR] [19:07:19] [PB@7300-worker-heavy/INFO] [prime_backup]: Creating backup of existing files to avoid idiot
[MCDR] [19:07:19] [MainThread/INFO]: 服务端已关闭
[MCDR] [19:07:19] [PB@7300-worker-heavy/INFO] [prime_backup]: Creating backup Backup(id=None, timestamp=1702984039584008800, creator='prime_backup:pre_restore', comment='__pb_translated__:pre_restore:25', targets=['world'], tags={'pre_restore_backup': True}, file_raw_size_sum=None, file_stored_size_sum=None) on ['world']
[MCDR] [19:07:20] [PB@7300-worker-heavy/INFO] [prime_backup]: Create backup #26 done, +44 blobs (size 6.49MiB / 33.36MiB)
[MCDR] [19:07:20] [PB@7300-worker-heavy/INFO] [prime_backup]: Restoring to backup #25 (fail_soft=False, verify_blob=True)
[MCDR] [19:07:20] [PB@7300-worker-heavy/INFO] [prime_backup]: Exporting Backup(id=25, timestamp=1702983099164029000, creator='console:', comment='测试pb1_5', targets=['world'], tags={}, file_raw_size_sum=242391100, file_stored_size_sum=28389502) to directory 1.20.1_fabric_lmg
[MCDR] [19:07:21] [PB@7300-worker-heavy/WARNING] [prime_backup]: Error occurs during export to directory, applying rollback
[MCDR] [19:07:21] [PB@7300-worker-heavy/ERROR] [prime_backup]: Task <prime_backup.mcdr.task.backup.restore_backup_task.RestoreBackupTask object at 0x7fec0db99520> run error
Traceback (most recent call last):
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/mcdr/task_manager.py", line 74, in run_task
    ret = holder.task.run()
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/mcdr/task/backup/restore_backup_task.py", line 96, in run
    failures = ExportBackupToDirectoryAction(
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/action/export_backup_action.py", line 49, in run
    failures = self._export_backup(session, backup)
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/action/export_backup_action.py", line 256, in _export_backup
    failures.add_or_raise(item.file, e)
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/types/export_failure.py", line 25, in add_or_raise
    raise error
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/action/export_backup_action.py", line 254, in _export_backup
    self.__export_file(item, trash_bin, exported_directories)
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/action/export_backup_action.py", line 170, in __export_file
    file_utils.copy_file_fast(blob_path, file_path)
  File "plugins/PrimeBackup-v1.5.0.pyz/prime_backup/utils/file_utils.py", line 19, in copy_file_fast
    while os.copy_file_range(f_src.fileno(), f_dst.fileno(), 2 ** 30):
OSError: [Errno 38] Function not implemented
[MCDR] [19:07:21] [PB@7300-worker-heavy/INFO]: [PB] 任务回档执行失败, 见控制台以了解错误详情

配置文件

./config/prime_backup/config.json

    "backup": {
        "source_root": "./1.20.1_fabric_lmg",
        "targets": [
            "world"
        ],
        "ignored_files": [
            "session.lock"
        ],
        "follow_target_symlink": true,
        "hash_method": "xxh128",
        "compress_method": "zstd",
        "compress_threshold": 64

./config.yml

language: zh_cn
working_directory: 1.20.1_fabric_lmg
start_command: ./mc_server_lanucher.sh start

MCDR工作目录:~/minecraft_server/mcdr_server/

软链接目录

~/minecraft_server -> /mnt/d/games/Minecraft/minecraft_server/
~/minecraft_server/mcdr_server/1.20.1_fabric_lmg -> /mnt/d/games/Minecraft/minecraft_server/1.20.1_fabric_lmg/
Fallen-Breath commented 10 months ago

这个 errno 挺怪的,也得支持下。参考着 coreutils 的 cp 指令完善了 copy_file_range 不受支持的时候的处理方式,可以试试 https://github.com/TISUnion/PrimeBackup/actions/runs/7262053115 (注:有 bug,见下面评论)

Fallen-Breath commented 10 months ago

可以试下 https://github.com/TISUnion/PrimeBackup/actions/runs/7262225372 ,应该解决了问题

Fallen-Breath commented 10 months ago

尝试复现了一下这个 issue,发现无法复现

复现尝试

环境:

目录结构(未列出全部内容):

/tmp/minecraft_server -> /mnt/d/test/minecraft_server/
├── 1.20.1_fabric_lmg  # MC 服务器工作目录
│   ├── minecraft_server.jar
│   ├── server.properties
│   └── world
└── mcdr_server  # MCDR 工作目录
    ├── 1.20.1_fabric_lmg -> /mnt/d/test/minecraft_server/1.20.1_fabric_lmg/
    ├── config
    ├── pb_files
    └── config.yml

其中,D 盘(/mnt/d)是 windows 下普通的一块 NTFS 文件系统的磁盘,/tmp 为 ext4 文件系统

配置文件 - MCDR:

working_directory: '1.20.1_fabric_lmg'

配置文件 - PB:

    "backup": {
        "source_root": "./1.20.1_fabric_lmg",
        "targets": [
            "world"
        ],
        "ignored_files": [
            "session.lock"
        ],
        "follow_target_symlink": true,
        "hash_method": "xxh128",
        "compress_method": "zstd",
        "compress_threshold": 64
    },

在 world 文件夹中手动创建 <64B 的小文件,确保 PB 未对其进行压缩,从而走到 file_utils.copy_file_fast 逻辑

经测试,可以正常创建备份、正常回档,未发生任何错误

copy_file_range 可行性验证

使用下面脚本在 /mnt/d 磁盘下尝试调用 os.copy_file_range,未见任何报错

import os

with open('1.txt', 'w') as f:
    f.write('aaaaa')

with open('1.txt', 'rb') as f1, open('2.txt', 'wb') as f2:
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
        pass

print('ok')
/mnt/d/test$ python3 test_copy_file_range.py
ok
/mnt/d/test$ cat 2.txt
aaaaa
Worldy-MCX commented 10 months ago

这个可以正常回档https://github.com/TISUnion/PrimeBackup/issues/7#issuecomment-1862725029

环境补充

WSL 发行版:Ubuntu 18.04.6 LTS

copy_file_range脚本复现测试

排除权限问题

python3 test_copy_file_range.py
Traceback (most recent call last):
  File "/mnt/d/test/test_copy_file_range.py", line 7, in <module>
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
OSError: [Errno 38] Function not implemented
/mnt/d/test$ sudo python3 test_copy_file_range.py
Traceback (most recent call last):
  File "/mnt/d/test/test_copy_file_range.py", line 7, in <module>
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
OSError: [Errno 38] Function not implemented
/mnt/d/test$ su -
Password:
/mnt/d/test# python3 test_copy_file_range.py
Traceback (most recent call last):
  File "/mnt/d/test/test_copy_file_range.py", line 7, in <module>
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
OSError: [Errno 38] Function not implemented

3次测试文件内容均为以下结果

/mnt/d/test$ cat 1.txt
aaaaa
/mnt/d/test$ cat 2.txt

/mnt/d/test$ls -l
-rwxrwxrwx 1 test test    5 Dec 20 02:07 1.txt*
-rwxrwxrwx 1 test  test     0 Dec 20 02:07 2.txt*
-rwxrwxrwx 1 test  test  213 Dec 20 02:03 test_copy_file_range.py*

难道是python版本问题?明天再试试

Fallen-Breath commented 10 months ago

Python 3.9.18,test_copy_file_range.py 运行正常

/mnt/d/test$ df -T .
Filesystem     Type  1K-blocks      Used Available Use% Mounted on
drvfs          9p   1463216468 894235964 568980504  62% /mnt/d
/mnt/d/test$ python3.9 -V
Python 3.9.18
/mnt/d/test$ python3.9 test_copy_file_range.py
ok
/mnt/d/test$ cat 2.txt
aaaaa

环境:

image

Worldy-MCX commented 10 months ago

提问:win下python3有没有copy_file_range这个函数 尝试:win10下python的两个版本都有报错

PS D:\test> python3.9.exe -V
Python 3.9.13
PS D:\test> python3.9.exe .\test_copy_file_range.py
Traceback (most recent call last):
  File "D:\test\test_copy_file_range.py", line 7, in <module>
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
AttributeError: module 'os' has no attribute 'copy_file_range'

PS D:\test> python3.10.exe .\test_copy_file_range.py
Traceback (most recent call last):
  File "D:\test\test_copy_file_range.py", line 7, in <module>
    while os.copy_file_range(f1.fileno(), f2.fileno(), 2 ** 30):
AttributeError: module 'os' has no attribute 'copy_file_range'

提问:copy_file_range 函数是在这个/usr/local/lib/python3.9/os.py模块内吗,如果是的话我在win下(C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\Lib\os.py)和wsl下的os.py内都没有找到copy_file_range这个函数. 要是提问的有不对的请指出来,谢谢

Fallen-Breath commented 10 months ago

win下python3有没有copy_file_range这个函数

https://docs.python.org/zh-cn/3/library/os.html#os.copy_file_range

提问:copy_file_range 函数是在这个/usr/local/lib/python3.9/os.py模块内吗,如果是的话我在win下(C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\Lib\os.py)和wsl下的os.py内都没有找到copy_file_range这个函数.

os 模块的 copy_file_range 是 c api 实现的,没有 .py 编写的代码。要看具体实现,你需要翻看 cpython 的源码

Worldy-MCX commented 10 months ago

明白了谢谢,找了好久没找到wsl相关的copy_file_range系统调用,无奈问了AI说wsl不支持os.copy_file_range函数.是不是AI忽悠我 有时间再研究吧,估计现在看源码很困难了.

Fallen-Breath commented 10 months ago

若需要,这里是 Python3.9.18 copy_file_range 的源码:https://github.com/python/cpython/blob/376d66eb5080cf8076d767b0916c103463343963/Modules/posixmodule.c#L10419

Fallen-Breath commented 10 months ago

在 Ubuntu 18.04.6 LTS 的 WSL 发行版中,编译 Python 3.9.18 后测试 test_copy_file_range.py,运行正常

/mnt/d/test$ cat /etc/os-release | grep VERSION=
VERSION="18.04.6 LTS (Bionic Beaver)"
/mnt/d/test$ uname -r
5.15.133.1-microsoft-standard-WSL2
/mnt/d/test$ python3.9 -V
Python 3.9.18
/mnt/d/test$ python3.9 test_copy_file_range.py
ok

环境同 https://github.com/TISUnion/PrimeBackup/issues/7#issuecomment-1863290804 ,只是换成了 Ubuntu 18.04.6

Worldy-MCX commented 10 months ago

破案了

发行版ubuntu使用wsl1安装,后来进行一次wsl --update虽然升级了wsl的内核,但是ubuntu发行版的内核没有跟着升级.还在使用wsl1,而不是wsl2,导致内核不支持从而无法使用copy_file_range() 也就是说wsl1不支持copy_file_range(),wsl2支持copy_file_range()


最开始使用这个命令来查看当前系统版本是错误的,这里只是wsl的版本

PS C:\Users> wsl --version
WSL 版本: 2.0.9.0
内核版本: 5.15.133.1-1
WSLg 版本: 1.0.59
MSRDC 版本: 1.2.4677
Direct3D 版本: 1.611.1-81528511
DXCore 版本: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows 版本: 10.0.22631.2861

进入wsl的ubuntu系统后实际查看的内核版本

wsl -d ubuntu
~$ uname -r
4.4.0-22621-Microsoft

使用wsl -l -v查看发行版,发现VERSION1

PS C:\Users> wsl -l -v
  NAME      STATE           VERSION
* Ubuntu    Running         1

使用以下命令重新导入后

# 导出发行版
wsl --export ubuntu G:\data\wsl\images\ubuntu-18.04.6-LTS.tar
# 注销并卸载发行版
wsl --unregister ubuntu
# 导入发行版
wsl --import  ubuntu-18.04.6-LTS  G:\data\wsl\ubuntu G:\data\wsl\images\ubuntu-18.04.6-LTS.tar  --version 2

可以成功运行test_copy_file_range.py脚本

PS C:\Users> wsl
~$ uname -r
5.15.133.1-microsoft-standard-WSL2
~$ python3 test_copy_file_range.py
ok
~$ cat 2.txt
aaaaa