Skip to content

fix(download): 暂停后不再落盘正在读取的分块 - #85

Open
std-external wants to merge 1 commit into
std-microblock:masterfrom
std-external:fix/download-pause-stops-immediately
Open

std-external wants to merge 1 commit into
std-microblock:masterfrom
std-external:fix/download-pause-stops-immediately

Conversation

@std-external

Copy link
Copy Markdown
Contributor

问题

在「下载任务」页面点某一条任务的「暂停」之后,进度数字 / 文件大小还会继续涨,看起来暂停是假的。

原因

src-tauri/src/ureq.rs 里暂停标志只在每次 read() 之前检查,而正在阻塞的 read() 无法被中断:

loop {
    if cancel_flag.load(Ordering::Relaxed) { bail!("Download canceled"); }
    wait_if_paused(cancel_flag, pause_flag)?;   // 暂停只在这里生效
    let n = reader.read(&mut buffer)?;          // 阻塞期间按暂停不会立刻生效
    file.write_all(&buffer[..n])?;              // 这一块照样写盘并上报进度
    ...
}

按下暂停时正在读取的那一块(最多 256 KiB)读完后仍然会落盘并计入进度;多线程分段下载有 8 条连接,同一时刻最多会多写约 2 MiB。download_single 和 download_range_part 都是这个结构。

修复

  • 读到一块之后、写盘之前再等一次暂停:暂停期间把这一块留在内存里,恢复后再写。数据不会丢(最终文件字节完全一致),但暂停后文件大小与进度会立刻停住。
  • download_multi_thread 开头也等一次暂停,暂停期间不再为新任务发起 HEAD / Range 探测请求。

只改 src-tauri/src/ureq.rs,不动下载协议、重试与断点续传逻辑。

验证

新增两个回归测试(本地 TCP 服务器 + 真实 ureq 下载路径):

  • pause_stops_writes_until_resumed:单连接下载到 4 MiB 后暂停,断言文件不再增长,恢复后仍能完整下载。
  • multi_thread_pause_stops_writes_until_resumed:8 线程分段下载,服务器每个分段只发 64 KiB 前缀后卡住,暂停后放行剩余数据,断言进度计数器不再增长。

修复前 cargo test --lib pause_ -- --test-threads=1:

test backend::ureq::tests::multi_thread_pause_stops_writes_until_resumed ... FAILED
  paused multi-thread download still wrote 65536 bytes
test backend::ureq::tests::pause_stops_writes_until_resumed ... FAILED
  paused download still wrote 8192 bytes

修复后:

test result: ok. 2 passed; 0 failed; 0 ignored

完整 cargo test --lib:109 passed / 0 failed;cargo fmt --all -- --check 通过(nightly toolchain)。

说明

  • 暂停期间如果连接已经卡死,仍然要等这次 read() 返回才会生效(当前没有 read 超时,PR fix(download): 下载链路走 ureq 自带的环境代理 + 补上读写超时 #84 在补);本 PR 没有改这一点。
  • 暂停只能停住字节传输;下载完成之后的校验 / 替换 zip / 解压阶段本来就不受暂停控制。
  • 前端 stores/download.ts:133 忽略了 set_mod_download_paused 的返回值,所以后端说「没找到这个任务」(例如下载已经结束)时界面依然会显示「已暂停」;这条没有在本 PR 里改。

来源:社区群里的用户反馈(1.2.1)「下载任务里面的暂停是假的吧」。

下载线程只在每次 read 之前检查暂停标志,而 read 本身无法中断:暂停时
正在读取的那一块读完后仍会被写入文件并上报进度,8 线程分段下载时会
×8,用户看到的就是「按了暂停还在下载」。

现在读到的一块先留在内存里,等恢复后再落盘,暂停后文件大小与进度会
立刻停住;同时多线程下载在暂停期间不再发起 HEAD / Range 探测请求。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant