- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다 - 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5 (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를 techviz 로 만들었다 - 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs 돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다. Concept 이 인용한 코드가 SSOT 에 없어 뺐다 - candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
12 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | assets | evidence | source | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | a08-f005-transferbufferpool-maxborrowedbytes | 부재로 판정된 결합이 원본 증거의 출력 안에 있다 | file-transfer-and-storage | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:a08-f005-transferbufferpool-maxborrowedbytes | 2026-09-02 |
|
|
|
부재로 판정된 결합이 원본 증거의 출력 안에 있다
버퍼 풀의 접근자가 자기 자바독에 유계 메모리 회귀 시험이 이 값을 단언한다고 적는다. 원본 절은 그 결합이 없다고 판정했는데, 원본이 근거로 댄 증거 파일이 그 단언 줄을 화면에 출력하고 있다.
관계
- 소비자가 없는 fixture 셋 이쪽도 프로덕션 호출자가 0 이라는 것을 세어 확인했다.
- 그 속성을 보일 수 없는 대역 위에서 통과한 테스트는 증인이 아니다 단언의 변별력을 묻는 규칙이고, 이 기록의 뒷부분이 그것을 자기 대상에 적용한다.
- 커버리지 gate 둘이 나란히 있고, 하나는 발화할 수 없다 두 사례 모두 검증이 있는 것처럼 보이지만 그 코드가 실행되지 않는다.
문제
존재 이유는 접근자 자바독에 한 줄로 적혀 있다. 동시 대여 바이트의 정점이며 유계 메모리 회귀 시험이 이 값을 단언한다는 것이다.
원본 분석의 판정은 그 결합이 없다는 것이었다. 그 이름이 구현 파일 세 줄에만 나타나고 지목된 시험에는 없다는 것이 근거다.
결론
결합은 실재한다. 그 이름은 다섯 줄에 나오고 그중 하나가 시험의 단언이다. 그 시험의 클래스 주석이 자기를 유계 메모리 회귀라고 부르므로, 자바독이 가리킨 대상도 분명하다.
원본의 계수는 두 군데에서 어긋난다. 구현 파일은 세 줄이 아니라 네 줄이고, 시험 한 줄이 통째로 빠졌다.
빠진 이유는 검색 범위가 아니다. 원본이 근거로 댄 증거 파일의 해당 절이 구현 파일과 시험 파일을 함께 인자로 넘겨 검색했고, 다섯 줄을 전부 출력했다. 출력된 줄이 요약 단계에서 없는 것으로 적혔다.
시험은 실제로 돈다. 격리 태그 없이 야간 워크플로가 이름을 적어 돌린다. 풀 리퀘스트 쪽 경계 메모리 잡이 고르는 것은 두 번째 시험 하나다.
여기까지가 원본 판정의 정정이다. 그 뒤에 남는 것은 그 단언이 무엇을 변별하느냐다.
대여 계수가 실제 버퍼 용량이 아니라 고정 버퍼 크기 단위로 누적하므로, 최대 대여 바이트는 언제나 버퍼 크기의 배수다. 그리고 이 경로에서 대여는 한 번뿐이다. 오프셋이 0 이면 접두 재해시가 빌리기 전에 반환하고, 복사와 다이제스트가 한 번 빌려 종료 블록에서 반납한다.
실행으로 확인했다. 페이로드를 1메가, 16메가, 256메가로 바꿔도 최대 대여 바이트는 131072 로 고정된다. 이름은 최대 관측 버퍼가 페이로드를 따라 늘지 않는다고 말하는데, 실제로는 페이로드를 바꿔도 값이 그대로다.
그 단언이 잡는 것은 반납 없는 반복 대여다. 같은 풀에서 반납 없이 두 번 빌리면 값이 두 배가 되고 단언이 깨진다. 풀을 거치지 않는 할당은 세지 못한다.
그 성질을 실제로 재는 것은 두 번째 시험이다. 생성기 채널이 저장소가 채운 가장 큰 단일 버퍼를 세고, 전송 비용이 파일 크기를 따라 늘지 않는다는 것을 그 수로 보인다. 정작 그 시험은 접근자를 건드리지 않는다.
검증 환경
OpenJDK : 21.0.12 확인 방식 : src 자바 트리 식별자 전수 검색, 원본 증거 파일 대조, 실행 탐침 소스 수정 : x
재현 조건
- 접근자의 자바독을 읽는다.
- 그 이름을 src 아래 자바 파일에서 시험 트리를 포함해 검색하고 줄을 센다.
- 원본 절이 근거로 댄 증거 파일의 해당 절을 열어 무엇이 출력됐는지 읽는다.
- 그 시험에 격리 태그가 있는지, 어느 워크플로가 이름으로 지목하는지 확인한다.
- 대여와 반납이 어떤 단위로 누적하는지 읽는다.
- 같은 추가 경로를 페이로드 크기를 바꿔 가며 돌리고 최대 대여 바이트를 읽는다.
- 같은 풀에서 반납 없이 두 번 빌려 그 값을 읽는다.
- 같은 성질을 재는 두 번째 시험이 이 접근자를 부르는지 확인한다.
본문
접근자의 자바독이 존재 이유를 한 줄로 적는다.
자바독이 적은 결합
:::evidence key="a08-f005-transferbufferpool-maxborrowedbytes" alt="버퍼 풀 접근자의 자바독과 구현. 그 이름이 src 아래 자바 파일에 나오는 곳 전수. 원본 절이 근거로 댄 증거 파일의 해당 절이 실행한 검색 명령과 그 출력. 그리고 그 시험의 애너테이션과 두 시험을 이름으로 지목하는 워크플로 줄을 출력한 터미널 기록." caption="자바독은 회귀 시험이 이 값을 단언한다고 적음 · 그 이름은 다섯 줄에 나오고 그중 하나가 시험 · 원본 증거는 구현과 시험 두 파일을 함께 검색해 다섯 줄을 전부 출력함 · 시험에 격리 태그 없음, 야간 워크플로가 이름으로 지목 — 28줄 · exit 0" zoom="true" :::
/** Peak simultaneously-borrowed bytes; the bounded-memory regression asserts on this. */
long maxBorrowedBytes() {
return maxBorrowedBytes.get();
}
원본 분석은 그 결합이 없다고 판정했다. 그 이름이 구현 파일 세 줄에만 나타난다는 것이 근거다.
구현 네 줄과 시험 한 줄
test/.../LocalAppendMemoryTest.java:54: assertThat(bufferPool.maxBorrowedBytes()).isLessThanOrEqualTo(BUFFER_BYTES);
main/.../TransferBufferPool.java:20: private final AtomicLong maxBorrowedBytes = new AtomicLong();
main/.../TransferBufferPool.java:38: maxBorrowedBytes.accumulateAndGet(outstanding, Math::max);
main/.../TransferBufferPool.java:56: long maxBorrowedBytes() {
main/.../TransferBufferPool.java:57: return maxBorrowedBytes.get();
경로 앞부분을 줄여 옮겼다. 구현 파일도 세 줄이 아니라 네 줄이고, 그 위에 시험 한 줄이 있다.
원본 증거는 그 줄을 출력했다
=== 8.4 doc/behaviour: bounded memory claim and its regression test ===
$ grep -n 'maxBorrowedBytes' …/TransferBufferPool.java …/LocalAppendMemoryTest.java
…/TransferBufferPool.java:20: private final AtomicLong maxBorrowedBytes = new AtomicLong();
…/TransferBufferPool.java:38: maxBorrowedBytes.accumulateAndGet(outstanding, Math::max);
…/TransferBufferPool.java:56: long maxBorrowedBytes() {
…/TransferBufferPool.java:57: return maxBorrowedBytes.get();
…/LocalAppendMemoryTest.java:54: assertThat(bufferPool.maxBorrowedBytes()).isLessThanOrEqualTo(BUFFER_BYTES);
검색 명령이 구현 파일과 시험 파일을 함께 인자로 받았고, 다섯 줄을 전부 찍었다. 범위 밖이어서 못 본 것이 아니라, 출력된 줄이 요약 단계에서 없는 것으로 적혔다.
시험은 실제로 돈다.
31: @Test
.github/workflows/fileserver-nightly.yml:103: … --tests '*LocalAppendMemoryTest'
.github/workflows/fileserver-pr.yml:161: … --tests '*LargeFileBoundedMemoryTest'
격리 태그가 없고 야간 워크플로가 이름으로 지목한다. 다만 풀 리퀘스트 쪽 경계 메모리 잡은 두 번째 시험만 돌린다.
그 단언이 변별하는 것
:::evidence key="a08-f005-transferbufferpool-maxborrowedbytes-peak" alt="자바독이 지목한 시험과 같은 추가 경로를 페이로드 1메가·16메가·256메가로 각각 돌려 최대 대여 바이트와 그것이 버퍼 크기 이하인지, 버퍼 크기의 몇 배인지 읽은 결과. 그리고 같은 풀에서 반납 없이 두 번 빌렸을 때의 값과 그 단언의 성립 여부를 출력한 터미널 기록." caption="페이로드를 256배로 늘려도 최대 대여 바이트는 131072 로 고정, 버퍼 크기의 1배 · 반납 없이 두 번 빌리면 262144 가 되어 단언이 깨짐 — 9줄 · exit 0" zoom="true" :::
대여 계수는 실제 버퍼 용량이 아니라 고정 버퍼 크기 단위로 누적한다.
long outstanding = borrowedNow.addAndGet(bufferSize);
maxBorrowedBytes.accumulateAndGet(outstanding, Math::max);
그래서 이 값은 언제나 버퍼 크기의 배수다. 그리고 이 경로에서 대여는 한 번뿐이다 — 오프셋이 0 이면 접두 재해시가 빌리기 전에 반환하고, 복사와 다이제스트가 한 번 빌려 종료 블록에서 반납한다.
같은 추가 경로를 페이로드만 바꿔 돌렸다.
payload maxBorrowedBytes BUFFER_BYTES 이하 버퍼 크기의 배수
1MiB 131072 예 1
16MiB 131072 예 1
256MiB 131072 예 1
페이로드를 256배로 늘려도 값이 움직이지 않는다. 시험 메서드의 이름은 최대 관측 버퍼가 페이로드를 따라 늘지 않는다는 것인데, 그 값은 페이로드에 대해 상수다.
자명한 단언은 아니다. 반납 없이 두 번 빌리면 깨진다.
[대조] 반납 없이 두 번 빌리면 그 단언이 깨진다
maxBorrowedBytes = 262144 BUFFER_BYTES 이하 = false
잡는 것은 정점 동시 대여가 버퍼 하나를 넘는 경우다. 잡지 못하는 것은 풀을 우회한 페이로드 비례 할당이다.
그 성질을 재는 것은 두 번째 시험이다
* Proves that transfer cost does not scale with file size.
*
* <p>The property is measured, not asserted by inspection: a generator channel counts the largest
* single buffer the store ever asked it to fill.
생성기 채널이 실제로 채운 단일 버퍼의 최댓값을 기록한다. 이쪽은 접근자를 부르지 않는다.
정정 범위
자바독이 서술한 결합은 실재하고, 그 계측은 시험에 연결돼 있다. 정정할 것은 원본 판정이다. 그 단언의 변별 범위가 좁다는 것은 별개의 관찰이고, 원본 절은 그것을 다루지 않았다.
확인하지 못한 것
원본 절이 왜 자기 증거가 출력한 줄을 부재로 요약했는지, 그 경위는 확인하지 못했다.