Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@
## 2026-07-13 - 단일 패스 문자열 치환 최적화 (O(N) 단일 스캔 및 지연 할당)
**Learning:** `String.replace()`를 여러 번 체이닝하여 호출하면, 문자열 치환이 발생하지 않는 경우에도 내부적으로 불필요한 스캔이 중복 발생하고, 치환 시마다 새로운 문자열 객체와 char 배열이 할당되어 메모리 낭비와 성능 저하(GC 압박)가 발생한다.
**Action:** 여러 문자를 한 번에 치환해야 하는 경우, O(N) 단일 스캔을 통해 `charAt()`으로 문자를 확인하고, 치환이 실제로 필요한 경우에만 `StringBuilder`를 지연 할당(Lazy allocation)하여 성능을 최적화하고 불필요한 메모리 할당을 방지한다.
## 2026-07-14 - 토큰 파싱 시 불필요한 String.join 객체 생성 방지 성능 최적화
**Learning:** 문자열을 특정 구분자로 나눌 때 `String.split()` 후 일부 배열 요소를 다시 `String.join()`으로 합치는 것은 불필요한 배열 복사와 문자열 생성으로 인한 가비지 컬렉션(GC) 압박과 성능 저하를 유발합니다.
**Action:** `lastIndexOf`와 `substring`을 사용하여 서명과 페이로드를 먼저 분리한 뒤, 필요한 부분만 `split()`하여 불필요한 `Arrays.copyOf` 및 `String.join` 연산을 방지함으로써 메모리 사용량과 성능을 최적화해야 합니다.
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,23 @@ public static String resolveToken(String queryToken, String authorizationHeader)
}

private ArtifactTokenClaims parseAndVerify(String token) {
String[] parts = token.split("\\.", -1);
if (parts.length != TOKEN_FIELD_COUNT + 1) {
int lastDotIndex = token.lastIndexOf('.');
if (lastDotIndex == -1) {
throw new ArtifactTokenException(HttpStatus.UNAUTHORIZED, "artifact token invalid");
}

String payload = token.substring(0, lastDotIndex);
String providedSignature = token.substring(lastDotIndex + 1);

String[] parts = payload.split("\\.", -1);
if (parts.length != TOKEN_FIELD_COUNT) {
throw new ArtifactTokenException(HttpStatus.UNAUTHORIZED, "artifact token invalid");
}

String payload = String.join(".", Arrays.copyOf(parts, TOKEN_FIELD_COUNT));
String expectedSignature = hmac(payload);
if (!MessageDigest.isEqual(
expectedSignature.getBytes(StandardCharsets.US_ASCII),
parts[TOKEN_FIELD_COUNT].getBytes(StandardCharsets.US_ASCII))) {
providedSignature.getBytes(StandardCharsets.US_ASCII))) {
throw new ArtifactTokenException(HttpStatus.UNAUTHORIZED, "artifact token invalid");
}

Expand Down
Loading