From f7cfad459223767d085ee74e26443bc034a17cbc 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 21:07:27 +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=E5=8A=A0=E4=B8=8A?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=88=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit export/registry.rs:temp_path 在 pid 与序号之外再带纳秒时间戳,避免崩溃残骸被同 pid 新进程撞上导致 create_new 误失败。 --- .../src-tauri/src/export/registry.rs | 9 ++++++++- 1 file changed, 8 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 cbf66fa52..275146002 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 @@ -172,9 +172,16 @@ fn temp_path(path: &Path) -> PathBuf { .unwrap_or_else(|| "registry.json".to_string()); // 临时文件名必须**每次写都不同**:只用 pid 的话,同一进程里两个并发写共用同一个临时文件, // 一个会截断另一个正在写的内容,rename 也会互相抢。进程内原子计数器保证不重名。 + // + // 计数器从 0 重来,所以还要带上「现在」:上一次进程崩在 `create_new` 与 rename 之间时, + // 会留下 `.tmp` 残骸;系统把同一个 pid 再分给新进程时,只靠 pid + 序号会撞上那份残骸, + // 而 `create_new` 会直接以 already-exists 失败。纳秒时间戳让重启后的第一次写也不再撞名。 let sequence = TEMP_FILE_SEQUENCE.fetch_add(1, Ordering::Relaxed); + let stamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_or(0, |elapsed| elapsed.as_nanos()); path.with_file_name(format!( - ".{file_name}.{}.{sequence}.tmp", + ".{file_name}.{}.{sequence}.{stamp}.tmp", std::process::id() )) }