mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 01:15:14 +08:00
fix(daemon): 串行化 bat-status.json 的读-改-写
watch 循环线程(update_daemon_status/update_daemon_progress)与 RPC 处理线程 (update_daemon_state_only)都会对状态文件做“读→改字段→写回”。单次写虽原子, 但整段读-改-写非原子,无互斥时并发线程会 last-writer-wins 丢失对方的字段更新。 新增进程级 DAEMON_STATUS_FILE_LOCK,三处读-改-写函数入口统一获取该锁串行化 (锁中毒时取 into_inner 继续,不 panic)。 对应 issue #18 维护清单 3-4。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3042,6 +3042,19 @@ fn read_daemon_status_file(path: &Path) -> anyhow::Result<Option<DaemonStatusFil
|
||||
Ok(Some(serde_json::from_slice(&bytes)?))
|
||||
}
|
||||
|
||||
/// 串行化 `bat-status.json` 的读-改-写。
|
||||
///
|
||||
/// watch 循环线程(`update_daemon_status`/`update_daemon_progress`)与 RPC 处理线程
|
||||
/// (`update_daemon_state_only`)都会更新状态文件;单次写虽原子,但“读→改字段→写回”
|
||||
/// 整体非原子,无此锁会因 last-writer-wins 丢失并发线程的字段更新。
|
||||
static DAEMON_STATUS_FILE_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
fn lock_daemon_status_file() -> std::sync::MutexGuard<'static, ()> {
|
||||
DAEMON_STATUS_FILE_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(|poison| poison.into_inner())
|
||||
}
|
||||
|
||||
fn write_daemon_status_file(path: &Path, status: &DaemonStatusFile) -> anyhow::Result<()> {
|
||||
write_file_atomic(
|
||||
path,
|
||||
@@ -3054,6 +3067,7 @@ fn write_daemon_status_file(path: &Path, status: &DaemonStatusFile) -> anyhow::R
|
||||
}
|
||||
|
||||
fn update_daemon_status(state_dir: &Path, update: DaemonStatusUpdate<'_>) -> anyhow::Result<()> {
|
||||
let _guard = lock_daemon_status_file();
|
||||
let status_path = daemon_status_path(state_dir);
|
||||
let mut status = read_daemon_status_file(&status_path)?.unwrap_or_else(|| DaemonStatusFile {
|
||||
version: DAEMON_STATUS_VERSION,
|
||||
@@ -3099,6 +3113,7 @@ fn update_daemon_status(state_dir: &Path, update: DaemonStatusUpdate<'_>) -> any
|
||||
}
|
||||
|
||||
fn update_daemon_progress(state_dir: &Path, event: &OfficialUpdateProgress) -> anyhow::Result<()> {
|
||||
let _guard = lock_daemon_status_file();
|
||||
let status_path = daemon_status_path(state_dir);
|
||||
let Some(mut status) = read_daemon_status_file(&status_path)? else {
|
||||
return Ok(());
|
||||
@@ -3128,6 +3143,7 @@ fn update_daemon_progress(state_dir: &Path, event: &OfficialUpdateProgress) -> a
|
||||
}
|
||||
|
||||
fn update_daemon_state_only(state_dir: &Path, state: &str) -> anyhow::Result<()> {
|
||||
let _guard = lock_daemon_status_file();
|
||||
let status_path = daemon_status_path(state_dir);
|
||||
let Some(mut status) = read_daemon_status_file(&status_path)? else {
|
||||
return Ok(());
|
||||
|
||||
Reference in New Issue
Block a user