From 32d77a0ccda6b9155e95dffbaf3c90e65825b1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 6 Oct 2026 18:49:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=B3=A8=E5=86=8C=E8=A1=A8?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=96=87=E4=BB=B6=E5=90=8D=E6=8C=89=E5=86=99?= =?UTF-8?q?=E5=85=A5=E5=BA=8F=E5=8F=B7=E5=94=AF=E4=B8=80=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - registry.rs 的 temp_path 在 pid 之外加入进程内原子自增序号,同一注册表路径的并发写不再共用同一个 .tmp 文件 --- .../src-tauri/src/export/registry.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs b/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs index 7033e8c9c..569758eb9 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/registry.rs @@ -8,6 +8,7 @@ use std::fmt; use std::fs; use std::io::Write as _; use std::path::{Path, PathBuf}; +use std::sync::atomic::Ordering; use serde::de::DeserializeOwned; use serde::Serialize; @@ -150,9 +151,18 @@ fn temp_path(path: &Path) -> PathBuf { .file_name() .map(|name| name.to_string_lossy().into_owned()) .unwrap_or_else(|| "registry.json".to_string()); - path.with_file_name(format!(".{file_name}.{}.tmp", std::process::id())) + // 临时文件名必须**每次写都不同**:只用 pid 的话,同一进程里两个并发写共用同一个临时文件, + // 一个会截断另一个正在写的内容,rename 也会互相抢。进程内原子计数器保证不重名。 + let sequence = TEMP_FILE_SEQUENCE.fetch_add(1, Ordering::Relaxed); + path.with_file_name(format!( + ".{file_name}.{}.{sequence}.tmp", + std::process::id() + )) } +/// 同进程内临时文件名的序号,见 [`temp_path`]。 +static TEMP_FILE_SEQUENCE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); + #[cfg(test)] mod tests { use super::*;