aboutsummaryrefslogtreecommitdiffstats
path: root/docs/research/019-byte-storage.md
blob: faefecf7aaa06f30a83e0a355bf30dd7136aed92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 019 — SQL을 제거한 바이트 접근·저장 경로

> 후속 [020](020-prepared-connections.md)에서 저장·응답 구간을 작성 파일로 정의하도록
> 확장했다. 아래는 그 이전 구현의 기록이며 현재 실행에는 `--program FILE`도 필요하다.

2026-09-23. **RAM·storage를 SQL에 맞추지 않는다는 요구에 따라 활성 구현의 SQLite를
제거했다.** 기존 CLI의 저장·복원 흐름은 유지하고 서버를 호출자의 바이트를 직접 기록하는
C17/POSIX 어댑터로 교체했다. 새 저장 기술의 성능을 입증한 연구 결과가 아니라, 잘못
도입한 내부 모델을 제거하고 연결의 의미를 확인한 구현 결과다.

사용자는 이전처럼 작업물을 만들고 `push`·`pull`로 저장·복원한다. 서버 실행 옵션은
`--db FILE`에서 `--store DIRECTORY`로 바뀌었다. 기존 파일은 자동 변환하거나 덮어쓰지 않는다.
실행 예는 [구현 README](../../prototypes/connections/README.md)에 있다.

## 내부 모델의 기준

필요한 데이터의 범위·접근·갱신·수명에서 배치와 실행 경로를 결정한다. 테이블·행·질의
실행기에 맞춘 뒤 다시 소비자의 표현으로 바꾸는 단계를 필수로 두지 않는다. DB는 데이터
접근·일관성·영속성을 다룬다는 범위 이름이며 SQL 엔진 채택을 뜻하지 않는다.

이번 경로는 RAM에 수신한 본문과 저장 파일의 읽기 범위를 같은 `PureSpan`으로 전달한다.
소비자는 포인터와 길이를 사용하며, 소유자는 소비 종료까지 데이터를 유지한다. 저장소의
주소를 영속 포인터로 기록하거나 RAM과 저장 매체의 물리적 성질이 같다고 가정하지 않는다.
타입·의미 검증, 표현 변환이 필요한 경계, 공개·영속화·전송 완료의 차이는 남는다.

현재 Workbench는 JSON 전체를 저장·복원한다. 이 경로에서 직렬화를 제거했다고 주장하지
않으며, JSON이나 `PureSpan`만으로 전체 애플리케이션의 데이터 표현을 완성한 것도 아니다.
파일별 전체 교체는 지금 작업의 어댑터 선택이다. Pure 전체를 키-값 저장소로 고정하지 않는다.

## 구현한 경로

쓰기: 수신 구간 → 새 파일에 원본 바이트 기록 → 파일 fsync → 원자적 이름 교체 →
디렉터리 fsync → 성공 응답. 버전 비교와 공개는 디렉터리별 쓰기 잠금 안에서 수행한다.
파일의 24 B 헤더는 식별자·버전·본문 길이만 담는다. 본문은 변환하지 않는다.

읽기: 파일·길이 검사 → 필요한 범위의 읽기 전용 매핑 → 부분 전송 → 매핑 해제.
저장 API는 오프셋·길이 접근을 지원하며 현재 HTTP 경로는 전체 본문을 요청한다.
페이지 정렬에 필요한 접두부도 매핑하므로 요청한 바이트 수가 실제 매핑/RSS와 같지는 않다.
파일 디스크립터는 매핑 후 닫을 수 있다. [mmap 계약](https://man7.org/linux/man-pages/man2/mmap.2.html).

저장 버전을 제자리에서 수정하지 않고 새 파일로 교체해, 읽고 있는 이전 버전과 새 요청이
보는 버전을 분리한다. 이는 불변 파일과 이름 교체의 조합이며 `MAP_PRIVATE`만으로 외부
파일 변경까지 격리되는 것은 아니다. [rename 계약](https://man7.org/linux/man-pages/man2/rename.2.html).

| 쓰기 결과 | 의미 |
|---|---|
| 예상 버전 불일치 | 충돌, 기존 바이트 유지 |
| 공개 전 실패 | 기존 바이트 유지, 이 호출의 임시 파일 제거 시도 |
| 공개 후 디렉터리 fsync 실패 | 새 바이트는 보이지만 영속화 확인 불가; `PURE_UNCERTAIN` / `durability_unknown` |
| 모든 동기화 성공 | 어댑터의 저장 성공; 상대 앱의 응답 수신 완료와는 별개 |

파일 fsync만으로 디렉터리 항목의 동기화를 대신할 수 없어 두 시점을 구분했다.
[fsync 계약](https://man7.org/linux/man-pages/man2/fsync.2.html). 이 순서를 구현했다는 사실과
실제 전원 장애에서 파일시스템·장치의 내구성을 검증했다는 주장은 별개다.

## 확인한 것과 남은 비용

Linux AArch64에서 일반 빌드와 ASan·UBSan 빌드가 모두 통과했다. SQL 라이브러리 링크는 없다.

- 저장 단위 검사: 범위·페이지 경계·예산, 갱신 중 이전 참조, 충돌·빈 본문·버전 소진,
  잘못된 저장 파일, 공개 전후 실패 주입, 공개 전 프로세스 종료와 재개.
- 실제 TCP 통합 16개 시나리오: 기존 작성물 복원, 두 프로세스의 쓰기 경쟁, 부분 송수신,
  읽는 중 다른 저장, 연결 종료, 자원 포화와 회수, 응답 미수신, 재시작 등.
- 검사 종료 후 활성 연결과 참조 본문 길이는 0이다. 현재 기록은 지정한 자원의 정확성
  검사이며 지연·처리량·전체 RAM 비교가 아니다.

현재 경로는 별도 응답 본문 사본을 만들지 않고 SQL 엔진도 경유하지 않는다. 커널 복사·
페이지 폴트·파일 동기화·클라이언트 직렬화는 남는다. 동기 파일 작업은 다른 연결의 처리를 지연시킬 수 있다.
이전 매핑은 이전 파일의 디스크 수명도 연장한다. 공개 전 종료로 남은 임시 파일을 자동으로
정리하지 않으므로 장기 디스크 사용량의 상한도 아직 보장하지 않는다. 본문 체크섬·부분 쓰기·
다중 객체 트랜잭션은 없고, macOS·전원 장애·디스크 고장도 검사하지 않았다.

[원자료와 재현](../../prototypes/connections/results/2026-09-23-byte-storage/README.md),
[직접 저장 구현](../../prototypes/connections/store.c),
[구간·수명 API](../../prototypes/connections/store.h).
018의 원자료는 당시 SQLite 구현의 기록으로 별도 보존한다.

## 다음 결정

현재 연결 순서는 여전히 C에 고정돼 있다. 다음은 **필요한 데이터 범위·연산·외부 효과·
소비 완료의 관계를 실행 가능한 Pure 정의로 표현하는 것**이다. 이미 있는 작업의 저장과
응답 경로에서 시작하고, 공개됐지만 영속화가 불확실한 결과를 단순 실패나 롤백으로
합치지 않는다. 데이터의 배치는 실제 소비·갱신 패턴에서 결정하며, 새 쿼리 엔진이나
SQL 대체 제품 개발을 다음 목표로 추가하지 않는다.