From a43ee44b6f06036e8f2d10ef885e15188b2e1f9a Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:11:57 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[=EC=84=B1=EB=8A=A5=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0]=20FileSystemArtifactStore=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20Files.exists()=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `Files.exists()` 호출과 `Files.readAllBytes()` 간에 발생할 수 있는 TOCTOU (Time-Of-Check to Time-Of-Use) 경쟁 상태를 방지하기 위해 파일의 존재 여부 확인을 생략합니다. * 파일 읽기를 바로 시도하고 `NoSuchFileException` 예외를 처리하여 파일 시스템의 stat 시스템 콜을 1회 줄여 성능을 향상시켰습니다. --- .jules/bolt.md | 3 +++ .../clearfolio/viewer/artifact/FileSystemArtifactStore.java | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 284d180a7..e5d348ea5 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -19,3 +19,6 @@ ## 2026-07-13 - 단일 패스 문자열 치환 최적화 (O(N) 단일 스캔 및 지연 할당) **Learning:** `String.replace()`를 여러 번 체이닝하여 호출하면, 문자열 치환이 발생하지 않는 경우에도 내부적으로 불필요한 스캔이 중복 발생하고, 치환 시마다 새로운 문자열 객체와 char 배열이 할당되어 메모리 낭비와 성능 저하(GC 압박)가 발생한다. **Action:** 여러 문자를 한 번에 치환해야 하는 경우, O(N) 단일 스캔을 통해 `charAt()`으로 문자를 확인하고, 치환이 실제로 필요한 경우에만 `StringBuilder`를 지연 할당(Lazy allocation)하여 성능을 최적화하고 불필요한 메모리 할당을 방지한다. +## 2026-07-24 - File System Existence Check Overhead +**Learning:** Checking `Files.exists()` immediately before `Files.readAllBytes()` introduces an unnecessary Time-of-Check to Time-of-Use (TOCTOU) race condition and incurs an extra `stat` system call penalty on every read path. +**Action:** When performing local file I/O operations inside `try-catch` blocks, directly attempt the read operation (e.g., `Files.readAllBytes()`) and gracefully handle `java.nio.file.NoSuchFileException` to achieve better performance and eliminate the race condition. diff --git a/src/main/java/com/clearfolio/viewer/artifact/FileSystemArtifactStore.java b/src/main/java/com/clearfolio/viewer/artifact/FileSystemArtifactStore.java index fe69737f4..354932a0c 100644 --- a/src/main/java/com/clearfolio/viewer/artifact/FileSystemArtifactStore.java +++ b/src/main/java/com/clearfolio/viewer/artifact/FileSystemArtifactStore.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -86,14 +87,13 @@ public Optional getPdf(UUID docId) { } Path pdfPath = pdfPath(docId); - if (!Files.exists(pdfPath)) { - return Optional.empty(); - } try { byte[] loaded = bytesReader.read(pdfPath); cache.put(docId, loaded); return Optional.of(loaded.clone()); + } catch (NoSuchFileException ex) { + return Optional.empty(); } catch (IOException ex) { throw new IllegalStateException("failed to read artifact for docId " + docId, ex); }