aboutsummaryrefslogtreecommitdiffstats
path: root/docs/design
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-30 03:03:52 +0100
committereunhhu <[email protected]>2026-09-30 03:03:52 +0100
commitc9c0edf5a8fc9f79fff42064db09bc297e117a88 (patch)
treee8ca03f9f8af2c04726e78389559887b9d3cee4e /docs/design
parentd1e8f38f100571d55aaa98527ae2873e6d247f80 (diff)
downloadpure-c9c0edf5a8fc9f79fff42064db09bc297e117a88.tar.gz
pure-c9c0edf5a8fc9f79fff42064db09bc297e117a88.zip
Let a receiver whose app is full keep what came, and say so
A link's delivery the app had no room for was handed over again at the next turn: a receiver over its memory budget would refuse the same records as fast as the owner could apply them. And its sender, seeing records received but not stored for a second, sent the whole window again every second. Now a host says a delivery found it full (PureLinkDone.full). The receiver keeps the records and hands them over again after a pause, 100 ms doubling to 500 ms, and meanwhile its STORED frames carry flag 2: the app is full and what came is kept. A sender hearing it starts its one-second wait for the save again, and sends none of it again. The spec (012) says both sides; the pause is a local choice that must stay under the sender's wait. pure_link_done takes the PureLinkDone itself. test-link's new case keeps the app full for 5 s: 12 hand-overs meanwhile, taken within 0.5 s of having room, and no record sent again (21,640 without the flag).
Diffstat (limited to 'docs/design')
-rw-r--r--docs/design/012-link-protocol.md11
1 files changed, 8 insertions, 3 deletions
diff --git a/docs/design/012-link-protocol.md b/docs/design/012-link-protocol.md
index 558ff7f..f2e9820 100644
--- a/docs/design/012-link-protocol.md
+++ b/docs/design/012-link-protocol.md
@@ -102,7 +102,7 @@ PADDING도 그렇게 끝을 채운다. 이름은 u8 길이(1–64)와 그 바이
| 0x01 | STREAM | 보냄 | names, u32 shape |
| 0x02 | RECORD | 보냄 | u64 번호, u32 기록 크기, u32 오프셋, u16 길이, 바이트[길이] |
| 0x03 | ACK | 답 | u64 가장 큰 번호, u32 지연(µs), u8 구간 수, 구간마다 u64 처음과 u64 끝(새것부터) |
-| 0x04 | STORED | 답 | names, u64 들은 번호, u8 깃발(1: 틈 뒤의 기록을 받지 않았다), u32 허가 |
+| 0x04 | STORED | 답 | names, u64 들은 번호, u8 깃발(1: 틈 뒤의 기록을 받지 않았다, 2: 앱이 가득 차 받은 것을 쥐고 있다), u32 허가 |
| 0x05 | PING | 보냄 | 없음 |
| 0x06 | RECORDS | 보냄 | u64 첫 번호, u8 개수, 기록마다 크기(LEB128)와 바이트 |
| 0x07 | CHALLENGE | 답 | u64 |
@@ -143,7 +143,8 @@ PADDING도 그렇게 끝을 채운다. 이름은 u8 길이(1–64)와 그 바이
**다시 보내기.** 패킷을 다시 보내지는 않는다. 그 패킷이 나른 기록 조각을 새 패킷에 싣는다. 다음 경우에 다시 보낸다.
- 패킷을 잃었다고 판단할 때. 판단은 RFC 9002를 따른다(지역 선택).
-- ACK로 받았다고 들은 조각이 1초 안에 저장되지 않을 때. 받는 쪽이 다시 시작했을 수 있다.
+- ACK로 받았다고 들은 조각이 1초 안에 저장되지 않을 때. 받는 쪽이 다시 시작했을 수 있다. 깃발 2가 붙은 STORED를 들으면 이
+ 1초를 그때부터 다시 센다. 받는 쪽이 살아 있고, 받은 것을 쥔 채 앱에 자리가 나기를 기다린다는 뜻이다.
- STORED에 틈 깃발이 올 때.
STORED의 들은 번호 이하인 기록은 덜어 낸다. 보내는 앱은 그때 그 보내기를 outbox에서 지운다.
@@ -230,6 +231,9 @@ STORED의 들은 번호 이하인 기록은 덜어 낸다. 보내는 앱은 그�
- 들은 번호 이하의 기록이 다시 오면 STORED를 다시 보낸다.
- 받는 쪽은 들은 번호 다음부터 번호 순서로 온전한 기록을 앱에 넘긴다. 앱이 적용하고 저장한 뒤에만 STORED의 들은 번호를 올린다.
틈에서 멈추고, 틈 뒤의 기록을 버렸으면 깃발 1을 세운다.
+- 앱이 가득 차 더 받지 못하면(앱의 메모리 예산, [013](013-memory-budget.md)) 받는 쪽은 받지 못한 기록을 쥔 채 잠시 뒤 다시
+ 넘긴다. 그동안 보내는 STORED에 깃발 2를 세운다. 다시 넘기는 간격은 지역 선택이지만, 보내는 쪽이 저장을 기다리는 1초보다
+ 짧아야 한다. 그래야 보내는 쪽이 쥐고 있는 기록을 다시 보내지 않는다.
**OFFER를 받아들임.** 다음 둘 가운데 하나일 때만 받아들인다.
@@ -290,6 +294,7 @@ LOST는 그 패킷의 번호를 담아 에폭 0의 키로 봉인한다. 답 run�
| 거절 뒤 기다림 | 1초부터 두 배, 64초까지 | 지역 선택 |
| 에폭을 잃었다고 볼 때 | 2초와 PTO 4번 | 지역 선택 |
| 받은 뒤 저장을 기다리는 시간 | 1초 | 지역 선택 |
+| 가득 찬 앱에 다시 넘기는 간격 | 100 ms부터 두 배, 500 ms까지 | 지역 선택(저장 기다림보다 짧게) |
| ACK 지연 상한(받는 쪽이 지킨다) | 25 ms | 명세 |
| RTT 첫값, PTO 상한 | 100 ms, 1초 | 지역 선택 |
| 혼잡 제어 | CUBIC(RFC 9438, C 0.4, β 0.7), 첫 창 10 데이터그램, 페이싱, 잘못 본 손실은 되돌림 | 지역 선택(표준 알고리즘만) |
@@ -333,7 +338,7 @@ LOST는 그 패킷의 번호를 담아 에폭 0의 키로 봉인한다. 답 run�
## 이 명세와 구현
- 구현은 `link/link-protocol.c`(상태, 소켓 없음)와 `link/link.c`(UDP, GSO/GRO, 스레드)다.
-- 전송 코드는 C 3,146줄이다(프로토콜 2,559, UDP 587). 011의 한도는 5,000줄이다.
+- 전송 코드는 C 3,161줄이다(프로토콜 2,574, UDP 587). 011의 한도는 5,000줄이다.
- 이 명세를 쓰면서 구현의 구멍 셋을 찾아 고쳤다. 셋 다 `link/test-link.c`에 검사가 있다. 메모의 곁 자리와 허가의 크기까지
[102](../research/102-adoption-and-spec.md)에 있다.
- 받는 쪽이 스트림을 받지 않을 때 보내는 쪽이 아무 말도 듣지 못해 매초 기록을 다시 보냈다. REFUSED를 더했다.