aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/design/008-module-format.md37
-rw-r--r--docs/research/075-http-host-against-axum.md23
2 files changed, 42 insertions, 18 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md
index 2d30003..2407980 100644
--- a/docs/design/008-module-format.md
+++ b/docs/design/008-module-format.md
@@ -197,24 +197,25 @@ text·리스트가 남을 때만 위치를 유지한다.
실패하면 묶음 전체가 되돌려지고, 저장 중 프로세스가 죽으면 묶음 전체가 남거나 전혀 남지 않는다. 비용(Pi 5, SD의 ext4): 저장하는 이벤트 하나에 약 10.6 ms가
더 든다. 대부분 두 번의 `fsync`다. 300항목 리스트에서 인덱스 이동 한 번은 파일을 약 220 B 키운다(압축 전).
-## 런타임 코어 위의 HTTP 서버
-
-`pure-connections-module --module 앱.pmod --store 경로`는 기존 문서 서버(`server.c`)와 같은 HTTP 계약을 모듈로
-제공한다. `GET /objects/키`는 모듈의 `show` 메시지, `PUT`(`If-Match`/`If-None-Match`)은 `edit` 메시지다. 요청은
-런타임 코어(`runtime.c`)를 그대로 거친다. 작업 슬롯 8개, 입력 바이트 예산, 코어가 소유한 ingress, 입력에서 빌린
-PUT 응답이 모두 기존과 같다. 효과는 비동기 인터페이스(`pure_runtime_take`/`pure_runtime_complete`)로 소유 스레드에서
-처리한다.
-
-- **poll 한 바퀴가 묶음 하나다.** 준비된 요청을 모두 꺼내 지연 저장 모드의 앱에 차례로 적용하고, `pure_app_save`
- 한 번으로 저장한 **뒤에** 티켓을 완료하고 응답한다. 저장이 실패하면 그 묶음의 읽기까지 모두 실패한다. 저장되지
- 않은 상태를 본 응답은 나가지 않는다. 같은 키가 다시 오면 묶음을 먼저 끝낸다. 모듈 서버는 기다리는 연결을 한 번에
- 모두 받아 동시 요청이 같은 묶음에 들어가게 한다.
-- GET 응답은 코어 예산에 계상되는 자원으로 복사한다. PUT 응답은 코어 계약대로 요청 본문에서 빌려야 하므로 `edit`
- 핸들러는 메시지 필드만 응답할 수 있다(`reply edit.insert`). 시작할 때 확인한다.
-- 검증(aup `make check`): `editor.aup`를 실행하는 모듈 서버와 `editor.pure`를 실행하는 기존 서버가 무작위 요청
- (새 키, 오래된 리비전, 범위 밖, 짧은 본문, 5,000 B 삽입)에 상태 코드·ETag·오류·본문까지 같게 답한다. 동시 편집 중
- `kill -9`로 죽여도 확인 응답을 받은 편집은 다시 시작한 서버에 모두 있다. Pi 5 SD(ext4)에서 동시 클라이언트 8개의
- PUT 240건: 기존 서버 2.14 s, 모듈 서버 0.59 s(묶음 61개).
+## HTTP 호스트 (`pure-serve`)
+
+`pure-serve --module 앱.pmod --store 경로`는 기존 문서 서버(`server.c`)와 같은 HTTP 계약을 모듈로 제공한다.
+`GET /objects/키`는 모듈의 `show` 메시지, `PUT`(`If-Match`/`If-None-Match`)은 `edit` 메시지다.
+
+- **연결.** HTTP/1.1 지속 연결과 파이프라이닝(응답은 순서대로), edge-triggered epoll 소유 스레드 하나, 기다리는
+ 연결을 한 번에 받는다. 연결 구조체는 받을 때 할당하고 닫으면 재사용하므로 메모리는 설정한 최대치가 아니라
+ 열린 연결 수를 따른다(기본 최대 1,024). 응답은 머리말과 본문을 `writev` 한 번으로 보낸다.
+- **런타임 코어.** 요청은 `runtime.c`를 그대로 거친다(연결마다 작업 슬롯, 입력 바이트 예산, 코어가 소유한
+ ingress, 요청에서 빌린 PUT 응답). 효과는 비동기 인터페이스(`pure_runtime_take`/`complete`)로 소유 스레드에서 처리한다.
+- **이벤트 한 바퀴가 묶음 하나다.** 준비된 요청을 모두 지연 저장 모드의 앱에 차례로 적용하고, 저장 한 번 **뒤에**
+ 응답한다. 저장이 실패하면 묶음의 읽기까지 모두 실패한다. 같은 키가 다시 오거나 문서 수가 한 저장의 한도를 넘으려
+ 하면 묶음을 먼저 끝낸다. 그래서 묶음 안의 모든 요청은 자기 묶음의 저장으로 저장되거나 그것과 함께 실패한다.
+- **저장소 핸들.** 문서와 상태를 저장소 핸들(`pure_store_data`)로 열어 파일 매핑 하나를 공유한다.
+- GET 응답은 예산에 계상되는 자원으로 복사한다. PUT 응답은 요청 본문에서 빌려야 하므로 `edit` 핸들러는 메시지
+ 필드만 응답할 수 있다(`reply edit.insert`). 시작할 때 확인한다.
+
+성능과 비교는 [연구 075](../research/075-http-host-against-axum.md). 검증(aup `make check`): 무작위 요청에 기존 서버와
+상태 코드·ETag·오류·본문이 같고, 동시 편집이 커밋을 나누어 쓰며, `kill -9` 뒤에도 확인 응답한 편집이 모두 남는다.
아직 모듈 앱을 런타임 코어의 효과 단위로 세분하지는 않았다(`runtime.c`의 `definition`은 앱 전체다). 호스트가 직접 호출한다. 실행기 코드는
`module.c` 33.1 KB, `module-text.c` 3.6 KB, `module-list.c` 5.7 KB, `module-save.c` 5.3 KB(`-O2` text)로 v1(7.4 KB)보다 크다. 줄이는 것이
diff --git a/docs/research/075-http-host-against-axum.md b/docs/research/075-http-host-against-axum.md
index 96814d3..308363e 100644
--- a/docs/research/075-http-host-against-axum.md
+++ b/docs/research/075-http-host-against-axum.md
@@ -52,3 +52,26 @@ PUT은 연결마다 자기 키 앞에 16 B를 넣고 받은 ETag로 다음 `If-M
4. 모듈 서버의 무복사 GET.
중단 기준: 어떤 단계든 메모리가 axum보다 커지거나, 저장 보장(확인 응답 = 저장됨, `kill -9` 검사)이 깨지면 그 방식은 버린다.
+
+## 1단계 결과: `pure-serve` (소유 스레드 하나)
+
+새 호스트 [`serve.c`](../../prototypes/connections/serve.c): 지속 연결·파이프라이닝, edge-triggered epoll, 연결
+최대 1,024(받을 때 할당), `writev` 응답, 같은 런타임 코어와 묶음 커밋. 같은 조건에서 다시 쟀다.
+
+`strace -c`로 보니 GET 하나마다 저장소 draft를 여닫느라 시스템 호출이 9번(파일·디렉터리 열기, `fstat` 두 번,
+전체 `mmap`/`munmap`, head 읽기)이었다. 저장소 핸들(`pure_store_open`)이 매핑을 공유하고 열 때 파일이 바뀌었는지만
+본다(2번).
+
+| 작업 | 이전 Pure | pure-serve, 핸들 전 | **pure-serve** | axum 메모리(3코어) | axum 충돌 안전 |
+|---|---:|---:|---:|---:|---:|
+| GET 64 B, keep-alive | 23,892 | 57,971 | **106,447** (p99 736) | 126,160 (p99 768) | 126,865 |
+| GET 64 B, 매번 새 연결 | 23,852 | 22,912 | 23,315 | 21,947 | 22,703 |
+| GET 1 MiB, keep-alive | 1,197 | 1,537 | **1,741** | 1,370 | 1,354 |
+| PUT 저장 보장, 연결 64 | 191 | 1,081 | **1,126** | – | 372 |
+| PUT 저장 보장, 연결 8 | 171 | 333 | **336** | – | 63 |
+
+최대 RSS: pure-serve 7.3 MiB, axum 17.4–19.6 MiB.
+
+- 코어 하나로 axum(코어 3개)의 84%(작은 keep-alive GET), p99는 같다. 큰 읽기는 27% 빠르다.
+- 저장 보장 쓰기는 충돌 안전 axum의 3.0–5.3배, 안전하지 않은 axum(429/s)보다도 빠르다.
+- 남은 차이는 코어 수다. 다음은 2단계(코어마다 소유 스레드)다.