diff options
| author | eunhhu <[email protected]> | 2026-09-27 13:14:38 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 13:14:38 +0100 |
| commit | 37d3a1e152707d2da587440c4cea8601b9ef0fd2 (patch) | |
| tree | 1a4cbea9d8ca636deabd8fc24b0d73cdae2bdaef | |
| parent | 5372d03b5968796515966e2cfc89628d6448f0c1 (diff) | |
| download | pure-37d3a1e152707d2da587440c4cea8601b9ef0fd2.tar.gz pure-37d3a1e152707d2da587440c4cea8601b9ef0fd2.zip | |
Lay Pure out as a core with the parts selected around it
The app model, the tree store and the HTTP host lived in
prototypes/connections among the earlier document runtime, the store was
known only by its format's name, and Vega compiled six Pure sources by path.
Now, as the README's principle has it:
core/ runtime, flow and the app model (module*.c), with what the core
asks of storage (state.h, store.h)
store/ the tree store (PURETRE3, PUREREC1)
serve/ pure-serve: HTTP host, outbound delivery, JSON in place
cli/ pure-run, pure-edit-module
A top-level make builds libpure.a (app model and store, for hosts to link)
and the hosts; make check runs the store's and the app model's tests. The
earlier runtime still builds from prototypes/connections against core/ and
store/ (check, check-tree and check-core pass). Design 009 records the rule:
parts by role behind libraries; git repositories split by coupling, so the
store stays here while its contract moves with the core, and Vega stays apart.
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 58 | ||||
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | benchmarks/http/README.md | 2 | ||||
| -rw-r--r-- | benchmarks/http/run.py | 5 | ||||
| -rw-r--r-- | cli/edit-module.c (renamed from prototypes/connections/edit-module.c) | 0 | ||||
| -rw-r--r-- | cli/pure-run.c (renamed from prototypes/connections/pure-run.c) | 0 | ||||
| -rw-r--r-- | core/flow.c (renamed from prototypes/connections/flow.c) | 0 | ||||
| -rw-r--r-- | core/flow.h (renamed from prototypes/connections/flow.h) | 0 | ||||
| -rw-r--r-- | core/module-list.c (renamed from prototypes/connections/module-list.c) | 0 | ||||
| -rw-r--r-- | core/module-list.h (renamed from prototypes/connections/module-list.h) | 0 | ||||
| -rw-r--r-- | core/module-save.c (renamed from prototypes/connections/module-save.c) | 0 | ||||
| -rw-r--r-- | core/module-save.h (renamed from prototypes/connections/module-save.h) | 0 | ||||
| -rw-r--r-- | core/module-store.c (renamed from prototypes/connections/module-store.c) | 0 | ||||
| -rw-r--r-- | core/module-store.h (renamed from prototypes/connections/module-store.h) | 0 | ||||
| -rw-r--r-- | core/module-text.c (renamed from prototypes/connections/module-text.c) | 0 | ||||
| -rw-r--r-- | core/module-text.h (renamed from prototypes/connections/module-text.h) | 0 | ||||
| -rw-r--r-- | core/module.c (renamed from prototypes/connections/module.c) | 0 | ||||
| -rw-r--r-- | core/module.h (renamed from prototypes/connections/module.h) | 0 | ||||
| -rw-r--r-- | core/result.h (renamed from prototypes/connections/result.h) | 0 | ||||
| -rw-r--r-- | core/runtime.c (renamed from prototypes/connections/runtime.c) | 0 | ||||
| -rw-r--r-- | core/runtime.h (renamed from prototypes/connections/runtime.h) | 0 | ||||
| -rw-r--r-- | core/state.h (renamed from prototypes/connections/state.h) | 0 | ||||
| -rw-r--r-- | core/store.h (renamed from prototypes/connections/store.h) | 0 | ||||
| -rw-r--r-- | core/test-module.c (renamed from prototypes/connections/test-module.c) | 0 | ||||
| -rw-r--r-- | docs/design/008-module-format.md | 4 | ||||
| -rw-r--r-- | docs/design/009-layout.md | 60 | ||||
| -rw-r--r-- | docs/research/018-native-connections.md | 2 | ||||
| -rw-r--r-- | docs/research/019-byte-storage.md | 2 | ||||
| -rw-r--r-- | docs/research/030-authenticated-document-peer.md | 2 | ||||
| -rw-r--r-- | docs/research/064-release-callback-reentrancy.md | 2 | ||||
| -rw-r--r-- | docs/research/066-application-boundary.md | 2 | ||||
| -rw-r--r-- | docs/research/073-single-file-persistent-tree.md | 2 | ||||
| -rw-r--r-- | docs/research/074-runtime-owned-drafts.md | 4 | ||||
| -rw-r--r-- | docs/research/075-http-host-against-axum.md | 2 | ||||
| -rw-r--r-- | docs/research/076-one-sync-commit.md | 2 | ||||
| -rw-r--r-- | prototypes/connections/Makefile | 80 | ||||
| -rw-r--r-- | prototypes/connections/README.md | 5 | ||||
| -rw-r--r-- | prototypes/connections/check.py | 8 | ||||
| -rw-r--r-- | prototypes/connections/package_source.py | 2 | ||||
| -rwxr-xr-x | research/experiments/009-runtime-drafts/run.py | 8 | ||||
| -rw-r--r-- | research/experiments/010-one-sync-commit/run.py | 15 | ||||
| -rwxr-xr-x | research/experiments/012-tail-records/run.py | 15 | ||||
| -rw-r--r-- | serve/deliver.c (renamed from prototypes/connections/deliver.c) | 0 | ||||
| -rw-r--r-- | serve/deliver.h (renamed from prototypes/connections/deliver.h) | 0 | ||||
| -rw-r--r-- | serve/message-json.c (renamed from prototypes/connections/message-json.c) | 0 | ||||
| -rw-r--r-- | serve/message-json.h (renamed from prototypes/connections/message-json.h) | 0 | ||||
| -rw-r--r-- | serve/serve.c (renamed from prototypes/connections/serve.c) | 0 | ||||
| -rw-r--r-- | store/store-tree.c (renamed from prototypes/connections/store-tree.c) | 0 | ||||
| -rw-r--r-- | store/test-tree-store.c (renamed from prototypes/connections/test-tree-store.c) | 0 |
50 files changed, 222 insertions, 79 deletions
@@ -8,3 +8,4 @@ __pycache__/ /benchmarks/http/axum-baseline/target/ /benchmarks/http/load /benchmarks/http/*.pmod +/build/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..50448da --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +CC ?= cc +AR ?= ar +CFLAGS ?= -O2 -g +CFLAGS += -std=c17 -Wall -Wextra -Wpedantic -Werror +BUILD ?= build + +# Pure is a small core with the rest selected around it: +# core/ execution, ownership, limits and completion (runtime), and the app +# model: modules verified before they run, events as transactions, +# states as drafts; state.h and store.h are what it asks of storage. +# store/ the tree store (one file; commits are one contiguous write and one +# sync; formats PURETRE3 and PUREREC1). +# serve/ pure-serve: the HTTP host, outbound delivery, JSON in place. +# cli/ command-line hosts. +# libpure.a is the app model with the tree store: what a host embeds (Vega's +# surfaces link it). prototypes/ keeps the earlier document runtime (000-077). +INCLUDES = -Icore +MODEL = core/module.c core/module-list.c core/module-save.c core/module-text.c core/module-store.c core/flow.c +STORE = store/store-tree.c +SERVE = serve/serve.c serve/deliver.c serve/message-json.c +HEADERS = $(wildcard core/*.h) $(wildcard serve/*.h) +OBJECTS = $(patsubst %.c,$(BUILD)/obj/%.o,$(MODEL) $(STORE)) + +.PHONY: all check +all: $(BUILD)/libpure.a $(BUILD)/pure-serve $(BUILD)/pure-run $(BUILD)/pure-edit-module + +$(BUILD)/obj/%.o: %.c $(HEADERS) + @mkdir -p $(dir $@) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(BUILD)/libpure.a: $(OBJECTS) + rm -f $@ + $(AR) rcs $@ $^ + +# The runtime's tickets and budgets, with effects completed off the owner thread. +$(BUILD)/pure-serve: $(SERVE) core/runtime.c $(BUILD)/libpure.a $(HEADERS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -Iserve -DPURE_ASYNC_EFFECTS $(SERVE) core/runtime.c $(BUILD)/libpure.a \ + $(LDFLAGS) -lssl -lcrypto -lm -pthread $(LDLIBS) -o $@ + +$(BUILD)/pure-run: cli/pure-run.c $(BUILD)/libpure.a $(HEADERS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) cli/pure-run.c $(BUILD)/libpure.a $(LDFLAGS) -lm $(LDLIBS) -o $@ + +# The document CLI contract, driven by a module on the tree store. +$(BUILD)/pure-edit-module: cli/edit-module.c $(BUILD)/libpure.a $(HEADERS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) cli/edit-module.c $(BUILD)/libpure.a $(LDFLAGS) -lm $(LDLIBS) -o $@ + +# Tests build their own copies: the store's fault hooks exist only under PURE_STORE_TEST. +$(BUILD)/test-module: core/test-module.c $(MODEL) $(STORE) $(HEADERS) + @mkdir -p $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -DPURE_STORE_TEST core/test-module.c $(MODEL) $(STORE) $(LDFLAGS) -pthread -lm $(LDLIBS) -o $@ + +$(BUILD)/test-tree-store: store/test-tree-store.c $(STORE) $(HEADERS) + @mkdir -p $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -DPURE_STORE_TEST store/test-tree-store.c $(STORE) $(LDFLAGS) $(LDLIBS) -o $@ + +check: all $(BUILD)/test-module $(BUILD)/test-tree-store + $(BUILD)/test-tree-store + $(BUILD)/test-module @@ -11,8 +11,22 @@ batches, and a receiving app applies each message once. Measurements against axu are in [075](docs/research/075-http-host-against-axum.md), [077](docs/research/077-apps-as-http-services.md), [080](docs/research/080-snapshot-reads.md), [081](docs/research/081-tail-records.md), [082](docs/research/082-json-in-place.md) and [083](docs/research/083-delivery-over-http.md); the status table is -[CHECKPOINT.md](CHECKPOINT.md). The text below -records the earlier document runtime this grew from. +[CHECKPOINT.md](CHECKPOINT.md). + +The source follows the principle below, a small core with the rest selected around it +([layout](docs/design/009-layout.md)): + +| Directory | What | Built as | +|---|---|---| +| `core/` | execution, ownership, limits and completion (`runtime.c`); the app model: modules verified before they run, events as transactions, states as drafts (`module*.c`); what the core asks of storage (`state.h`, `store.h`) | `build/libpure.a` (with the store) | +| `store/` | the tree store: one file, a commit is one contiguous write and one sync (formats `PURETRE3`, `PUREREC1`) | in `libpure.a` | +| `serve/` | `pure-serve`: the HTTP host, outbound delivery, JSON read in place | `build/pure-serve` | +| `cli/` | command-line hosts | `build/pure-run`, `build/pure-edit-module` | +| `prototypes/` | the earlier document runtime (000-077), built against `core/` and `store/` | `make -C prototypes/connections` | + +`make` builds the library and the hosts, `make check` runs the store's and the app model's tests. Interfaces for +people are [Vega](/srv/git/vega.git), which links `libpure.a`. The text below records the earlier document runtime +this grew from. A standalone native micro runtime being designed as a small operating system. Pure owns the application model for execution, memory, protection, diff --git a/benchmarks/http/README.md b/benchmarks/http/README.md index af9f62d..22fc6d3 100644 --- a/benchmarks/http/README.md +++ b/benchmarks/http/README.md @@ -7,7 +7,7 @@ Pure의 문서 서버들과 같은 계약의 axum(Rust)·drogon(C++) 서비스� cc -O2 -std=c17 -o load load.c (cd axum-baseline && cargo build --release) drogon-baseline/build.sh # Debian의 drogon 패키지를 설치하지 않고 .deps에 풀어 빌드한다 -make -C ../../prototypes/connections build/pure-serve +make -C ../.. build/pure-serve make -C ../../prototypes/connections BUILD=build/tree STORE=store-tree.c build/tree/pure-connections aup build ../../../aup/examples/editor.aup -o editor.pmod python3 run.py --module editor.pmod --directory /var/tmp # 저장소를 둘 장치에서 diff --git a/benchmarks/http/run.py b/benchmarks/http/run.py index bad9cc4..4605226 100644 --- a/benchmarks/http/run.py +++ b/benchmarks/http/run.py @@ -38,7 +38,8 @@ import http.client from pathlib import Path HERE = Path(__file__).resolve().parent -PURE = HERE.parent.parent / 'prototypes' / 'connections' +PURE = HERE.parent.parent # build/pure-serve; the earlier document server stays in prototypes/connections +PROTOTYPES = PURE / "prototypes" / "connections" def start(args): @@ -145,7 +146,7 @@ def main(): drogon = HERE / 'drogon-baseline/drogon-baseline' base = Path(tempfile.mkdtemp(dir=args.directory, prefix='pure-http-bench-')) servers = { - 'pure-program': lambda d: [PURE / 'build/tree/pure-connections', '--program', PURE / 'examples/editor.pure', + 'pure-program': lambda d: [PROTOTYPES / 'build/tree/pure-connections', '--program', PROTOTYPES / 'examples/editor.pure', '--store', d, '--port', '0', '--budget', str(args.budget)], 'pure-serve': lambda d: [PURE / 'build/pure-serve', '--module', args.module, '--store', d, '--port', '0', '--budget', str(args.budget)], diff --git a/prototypes/connections/edit-module.c b/cli/edit-module.c index 3ce272e..3ce272e 100644 --- a/prototypes/connections/edit-module.c +++ b/cli/edit-module.c diff --git a/prototypes/connections/pure-run.c b/cli/pure-run.c index cfc3b5c..cfc3b5c 100644 --- a/prototypes/connections/pure-run.c +++ b/cli/pure-run.c diff --git a/prototypes/connections/flow.c b/core/flow.c index 1070c70..1070c70 100644 --- a/prototypes/connections/flow.c +++ b/core/flow.c diff --git a/prototypes/connections/flow.h b/core/flow.h index 6e27c58..6e27c58 100644 --- a/prototypes/connections/flow.h +++ b/core/flow.h diff --git a/prototypes/connections/module-list.c b/core/module-list.c index 2cd2b1c..2cd2b1c 100644 --- a/prototypes/connections/module-list.c +++ b/core/module-list.c diff --git a/prototypes/connections/module-list.h b/core/module-list.h index a721ff0..a721ff0 100644 --- a/prototypes/connections/module-list.h +++ b/core/module-list.h diff --git a/prototypes/connections/module-save.c b/core/module-save.c index 4149316..4149316 100644 --- a/prototypes/connections/module-save.c +++ b/core/module-save.c diff --git a/prototypes/connections/module-save.h b/core/module-save.h index bc7adcc..bc7adcc 100644 --- a/prototypes/connections/module-save.h +++ b/core/module-save.h diff --git a/prototypes/connections/module-store.c b/core/module-store.c index 7e759fd..7e759fd 100644 --- a/prototypes/connections/module-store.c +++ b/core/module-store.c diff --git a/prototypes/connections/module-store.h b/core/module-store.h index d14ab3d..d14ab3d 100644 --- a/prototypes/connections/module-store.h +++ b/core/module-store.h diff --git a/prototypes/connections/module-text.c b/core/module-text.c index 68c03b0..68c03b0 100644 --- a/prototypes/connections/module-text.c +++ b/core/module-text.c diff --git a/prototypes/connections/module-text.h b/core/module-text.h index 4843928..4843928 100644 --- a/prototypes/connections/module-text.h +++ b/core/module-text.h diff --git a/prototypes/connections/module.c b/core/module.c index 697e918..697e918 100644 --- a/prototypes/connections/module.c +++ b/core/module.c diff --git a/prototypes/connections/module.h b/core/module.h index f62326b..f62326b 100644 --- a/prototypes/connections/module.h +++ b/core/module.h diff --git a/prototypes/connections/result.h b/core/result.h index 8abb0f2..8abb0f2 100644 --- a/prototypes/connections/result.h +++ b/core/result.h diff --git a/prototypes/connections/runtime.c b/core/runtime.c index 4a857c7..4a857c7 100644 --- a/prototypes/connections/runtime.c +++ b/core/runtime.c diff --git a/prototypes/connections/runtime.h b/core/runtime.h index 70f5d08..70f5d08 100644 --- a/prototypes/connections/runtime.h +++ b/core/runtime.h diff --git a/prototypes/connections/state.h b/core/state.h index 2bf78b0..2bf78b0 100644 --- a/prototypes/connections/state.h +++ b/core/state.h diff --git a/prototypes/connections/store.h b/core/store.h index dbfa8f8..dbfa8f8 100644 --- a/prototypes/connections/store.h +++ b/core/store.h diff --git a/prototypes/connections/test-module.c b/core/test-module.c index ccb3371..ccb3371 100644 --- a/prototypes/connections/test-module.c +++ b/core/test-module.c diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md index 3fd4d52..84aa97b 100644 --- a/docs/design/008-module-format.md +++ b/docs/design/008-module-format.md @@ -1,7 +1,7 @@ # Pure 모듈 형식 v5 -2026-09-25. 구현 `prototypes/connections/module.{h,c}`, `module-text.c`, `module-list.c`, 상태 저장 `module-save.c`, -트리 저장소 연결 `module-store.c`. +2026-09-25. 구현 `core/module.{h,c}`, `module-text.c`, `module-list.c`, 상태 저장 `module-save.c`, +모듈 파일 읽기 `module-store.c`, 트리 저장소 `store/store-tree.c`, HTTP 호스트 `serve/`. Pure가 실행하는 앱 정의의 형식이다. JVM이 class 파일 형식을 소유하듯 Pure가 이 형식과 검증 규칙을 소유한다. 생산자는 [aup](/srv/git/aup.git) 같은 툴체인이다. Pure는 소스·문법을 모르며, diff --git a/docs/design/009-layout.md b/docs/design/009-layout.md new file mode 100644 index 0000000..8cb9a78 --- /dev/null +++ b/docs/design/009-layout.md @@ -0,0 +1,60 @@ +# 009 — 배치: 코어와 고르는 부품 + +2026-09-27. 저장소 경계와 범위가 일관되지 않다는 지적에서 정한 것. + +## 문제 + +- README의 원칙은 "항상 있는 코어는 실행, 소유권, 자원 한도, 완료 규칙만 다룬다. 프로토콜, 저장소 구현, UI, 코덱은 앱에 + 맞게 고른다"였다. 그런데 소스는 원칙과 다르게 놓여 있었다. +- 지금 세대의 코어(모듈 검증·실행 `module*.c`), 트리 저장소(`store-tree.c`), HTTP 호스트(`serve.c`, `deliver.c`, + `message-json.c`)가 모두 `prototypes/connections/` 한 디렉터리에 이전 세대(000–077의 문서 런타임: `program.c`, + `store.c`, `server.c`, 편집기들)와 섞여 있었다. 이름만 보면 저장소는 형식 매직(`PURETRE2`)으로만 드러났고, 코어가 + 어디서 끝나는지 알 수 없었다. +- 소비자는 소스 파일 목록으로 연결했다. Vega는 Pure의 `.c` 여섯 개를 경로로 나열해 컴파일했다. Pure에 파일이 하나 + 늘면 Vega가 깨진다. +- 반면 사람을 위한 인터페이스(Vega)는 따로 된 저장소였다. 저장소와 네트워크는 "호스트 안"처럼 보이고 UI만 부품처럼 + 보였다. + +## 규칙 + +1. **역할로 나누고 역할로 부른다.** 코어, 저장소, HTTP 호스트, 명령행 호스트. 형식 이름(`PURETRE3`, `PUREREC1`)은 + 형식의 이름일 뿐 부품의 이름이 아니다. +2. **부품은 라이브러리와 헤더로 쓴다.** 소비자는 파일 목록이 아니라 `libpure.a`와 `core/`의 헤더로 연결한다. +3. **저장소(git) 경계는 결합도로 정한다.** 함께 바뀌는 것은 한 저장소에 두고 디렉터리로 나누며, 따로 바뀌는 것은 저장소를 + 나눈다. 부품이 된 디렉터리는 나중에 `git subtree split`으로 그대로 떼어 낼 수 있다. + +## 배치 + +| 디렉터리 | 역할 | 만드는 것 | +|---|---|---| +| `core/` | 실행·소유권·한도·완료(`runtime.c`, `flow.c`), 앱 모델(`module*.c`: 실행 전에 검증한 모듈, 트랜잭션인 이벤트, draft인 상태), 코어가 저장소에 요구하는 것(`state.h`, `store.h`) | `build/libpure.a`(저장소와 함께) | +| `store/` | 트리 저장소. 한 파일, 커밋은 한 연속 쓰기와 동기화 한 번 | `libpure.a` 안 | +| `serve/` | `pure-serve`: HTTP 호스트, 나가는 전달, 제자리 JSON | `build/pure-serve` | +| `cli/` | 명령행 호스트 | `build/pure-run`, `build/pure-edit-module` | +| `prototypes/` | 이전 문서 런타임. `core/`와 `store/`를 가져다 빌드한다 | `make -C prototypes/connections` | + +저장소 계약(`state.h`, `store.h`)은 코어 쪽에 둔다. 코어가 필요한 것을 정하고 저장소 구현이 그것을 채운다. 트리 +저장소는 그 계약의 한 구현이다(이전 세대의 `store.c`, `store-paged.c`도 `store.h`의 구현이다). + +## 왜 저장소를 따로 된 git 저장소로 떼지 않았나 + +트리 저장소를 바꾼 최근 커밋 12개 중 9개가 계약(`state.h`, `store.h`)을 바꿨고, 그중 5개는 같은 커밋에서 코어나 호스트도 +바꿨다. 스냅숏(`571824a`: 저장소 동결 + 모듈 리스트 공유 + 모듈 스냅숏), 대여(`1a3586d`: 저장소 익스텐트 + serve), 그룹 +커밋(`d4b01a7`), 샤딩(`694b60f`), 매핑을 나누는 핸들(`89d1777`: + 모듈 파일 읽기). 계약이 아직 코어와 함께 움직이고 +소비자가 Pure 하나뿐이다. 따로 된 저장소면 이런 +변경마다 두 저장소의 버전을 맞춰야 한다. 두 번째 소비자(예: 메신저의 메시지 저장)가 생기거나 계약이 멈추면 `store/`를 +그대로 떼어 낸다. + +## 왜 Vega는 따로이고 이름이 pure-ui가 아닌가 + +Vega는 두 가지다. aup 라이브러리(`use vega`: 목록·표·포커스·톤 같은 인터페이스 어휘)와 그 어휘를 사람에게 보이는 +표면들(TUI, CLI, NUI, 웹, 심볼과 GPU)이다. 어휘는 aup의 언어 기능과 함께 바뀌고, 표면은 Pure의 모듈 API(`libpure.a`) +위에 있다. Vega의 최근 커밋은 모두 Vega 안에서 끝났다. `pure-serve`가 Pure 안에 있는 것은 프로그램을 위한 표면(보기가 +GET, 입력이 POST)에는 어휘가 필요 없기 때문이다. 모듈 형식만으로 정해진다. 사람을 위한 표면은 어휘가 필요하다. JDK가 +`java.net`과 HTTP 서버를 담고 JavaFX를 따로 두는 것과 같은 선이다. `pure-ui`라는 이름은 UI가 런타임의 일부라는 뜻이 +되어, 런타임이 화면을 모른다는 분리와 어긋난다. + +## 확인 + +최상위 `make check`(저장소와 앱 모델의 검사), `prototypes/connections`의 `make check`·`check-tree`·`check-core`, aup +`make check`, Vega `make check`가 새 배치에서 통과한다. Vega는 이제 `libpure.a`를 링크한다. diff --git a/docs/research/018-native-connections.md b/docs/research/018-native-connections.md index f2c26bc..6747dd8 100644 --- a/docs/research/018-native-connections.md +++ b/docs/research/018-native-connections.md @@ -66,7 +66,7 @@ DB 호출은 아직 동기식이므로 디스크 작업 중 다른 연결 처리 동적 링크한 SQLite 자체를 sanitizer로 다시 빌드한 것은 아니다. [원자료·재현](../../prototypes/connections/results/2026-09-23-native-connections/README.md), -[전송 수명](../../prototypes/connections/flow.c), +[전송 수명](../../core/flow.c), [DB 연결](../../prototypes/connections/store.c), [호스트](../../prototypes/connections/server.c), [기존 CLI 연결](../../prototypes/workbench/remote.mjs). diff --git a/docs/research/019-byte-storage.md b/docs/research/019-byte-storage.md index faefecf..b58adcd 100644 --- a/docs/research/019-byte-storage.md +++ b/docs/research/019-byte-storage.md @@ -72,7 +72,7 @@ Linux AArch64에서 일반 빌드와 ASan·UBSan 빌드가 모두 통과했다. [원자료와 재현](../../prototypes/connections/results/2026-09-23-byte-storage/README.md), [직접 저장 구현](../../prototypes/connections/store.c), -[구간·수명 API](../../prototypes/connections/store.h). +[구간·수명 API](../../core/store.h). 018의 원자료는 당시 SQLite 구현의 기록으로 별도 보존한다. ## 다음 결정 diff --git a/docs/research/030-authenticated-document-peer.md b/docs/research/030-authenticated-document-peer.md index 1ff569d..6e1fa23 100644 --- a/docs/research/030-authenticated-document-peer.md +++ b/docs/research/030-authenticated-document-peer.md @@ -9,7 +9,7 @@ `pure-document-peer`는 TLS 1.3/TCP의 상호 인증, 인증서 SAN 이름 확인, `pure-doc/1` ALPN 뒤에 자체 이진 메시지를 사용한다. 이미 구현한 scalar 피어의 소켓·TLS 부분을 [`tls-link.c`](../../prototypes/common/tls-link.c)로 분리해 두 피어가 재사용한다. -코어의 [`runtime.c`](../../prototypes/connections/runtime.c), 저장소, `editor.pure`는 +코어의 [`runtime.c`](../../core/runtime.c), 저장소, `editor.pure`는 문서 CLI와 같다. 전송 코드는 선택 빌드의 호스트에만 있다. 서버가 보내는 40 B hello는 `PDOC`, 버전 1, 예약 3 B, **원본 .pure 소스** SHA-256이다. diff --git a/docs/research/064-release-callback-reentrancy.md b/docs/research/064-release-callback-reentrancy.md index 68ce819..f35f6ec 100644 --- a/docs/research/064-release-callback-reentrancy.md +++ b/docs/research/064-release-callback-reentrancy.md @@ -5,7 +5,7 @@ `running`이 꺼져 있었다. 콜백이 같은 영역의 티켓을 해제하거나 새 작업을 받아들이면, 바깥쪽 회수 코드가 작업 슬롯과 예산 장부를 계속 수정할 수 있었다. -[`runtime.c`](../../prototypes/connections/runtime.c)는 자원 해제 콜백 동안 해당 +[`runtime.c`](../../core/runtime.c)는 자원 해제 콜백 동안 해당 영역을 실행 중으로 표시하고 이전 상태를 복원한다. 새 상태 필드나 작업별 할당은 없다. [`test-runtime.c`](../../prototypes/connections/test-runtime.c)는 취소, 대기 작업 해제, 유효하지 않은 호스트 할당 반환에서 콜백이 같은 티켓을 diff --git a/docs/research/066-application-boundary.md b/docs/research/066-application-boundary.md index 44e6d86..bb96bed 100644 --- a/docs/research/066-application-boundary.md +++ b/docs/research/066-application-boundary.md @@ -5,7 +5,7 @@ ## 현재 코드가 증명하는 것과 못 하는 것 -`prototypes/connections/runtime.c`는 입력 접수, 바이트 예산, 작업 슬롯, 완료, +`core/runtime.c`는 입력 접수, 바이트 예산, 작업 슬롯, 완료, 대여와 다른 영역으로의 무복사 전달을 소유한다. 하지만 실행 단계에서 `PureProgram`의 저장 전용 `read`/`write`/`splice`를 직접 해석하고 `PureHost.read`/`write`/`splice`를 호출한다. 따라서 현재 5,980 B 코어는 diff --git a/docs/research/073-single-file-persistent-tree.md b/docs/research/073-single-file-persistent-tree.md index 13884e3..4386e93 100644 --- a/docs/research/073-single-file-persistent-tree.md +++ b/docs/research/073-single-file-persistent-tree.md @@ -74,7 +74,7 @@ Ctrl+S부터 저장 완료 프레임까지 잰다. 1 MiB 문서, 저장소별 3� ## 검증 -[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c)는 ASan·UBSan에서도 통과했다. +[`test-tree-store.c`](../../store/test-tree-store.c)는 ASan·UBSan에서도 통과했다. - 4개 키에 6,000회 무작위 편집을 평면 배열 오라클과 매번 비교했다(최대 333,510 B, 높이 2). 매 편집 뒤 저장된 모든 비루트 노드가 기준 이상으로 채워졌는지 확인했다. diff --git a/docs/research/074-runtime-owned-drafts.md b/docs/research/074-runtime-owned-drafts.md index 71ac8c9..42fd417 100644 --- a/docs/research/074-runtime-owned-drafts.md +++ b/docs/research/074-runtime-owned-drafts.md @@ -1,7 +1,7 @@ # 074 — 작업 중인 값을 런타임이 소유한다 2026-09-25. [073](073-single-file-persistent-tree.md)의 선택형 트리 저장소 위에 런타임 API -[`state.h`](../../prototypes/connections/state.h)를 추가했다. 기본 빌드와 기본 저장 형식은 바뀌지 않았다. +[`state.h`](../../core/state.h)를 추가했다. 기본 빌드와 기본 저장 형식은 바뀌지 않았다. Pure는 JVM과 같은 위치의 런타임이다. 앱 기능은 별도 저장소에서 만들고, 이 저장소의 CLI·TUI· HTTP 호스트는 런타임을 검사하는 호스트다. 따라서 이번 단계는 편집기 기능이 아니라 모든 앱이 쓰는 @@ -61,7 +61,7 @@ draft가 가진 옛 매핑에서 필요한 노드를 새 파일로 복사한다( ## 검증 -[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c) 추가 검사는 ASan·UBSan을 포함해 통과했다. +[`test-tree-store.c`](../../store/test-tree-store.c) 추가 검사는 ASan·UBSan을 포함해 통과했다. - 20,000회 무작위 편집을 draft에서 평면 오라클과 비교하고 1,000회마다 커밋했다(최종 419,324 B, 커밋 20회). 커밋 뒤에는 저장본 일치, revision 증가, 빈 arena를 확인했다. diff --git a/docs/research/075-http-host-against-axum.md b/docs/research/075-http-host-against-axum.md index 17cfe39..77be305 100644 --- a/docs/research/075-http-host-against-axum.md +++ b/docs/research/075-http-host-against-axum.md @@ -55,7 +55,7 @@ PUT은 연결마다 자기 키 앞에 16 B를 넣고 받은 ETag로 다음 `If-M ## 1단계 결과: `pure-serve` (소유 스레드 하나) -새 호스트 [`serve.c`](../../prototypes/connections/serve.c): 지속 연결·파이프라이닝, edge-triggered epoll, 연결 +새 호스트 [`serve.c`](../../serve/serve.c): 지속 연결·파이프라이닝, edge-triggered epoll, 연결 최대 1,024(받을 때 할당), `writev` 응답, 같은 런타임 코어와 묶음 커밋. 같은 조건에서 다시 쟀다. `strace -c`로 보니 GET 하나마다 저장소 draft를 여닫느라 시스템 호출이 9번(파일·디렉터리 열기, `fstat` 두 번, diff --git a/docs/research/076-one-sync-commit.md b/docs/research/076-one-sync-commit.md index 9f010e7..4b9afa6 100644 --- a/docs/research/076-one-sync-commit.md +++ b/docs/research/076-one-sync-commit.md @@ -94,7 +94,7 @@ p99는 장치 쪽 잡음이 지배한다. 꼬리를 늘리는 단위를 64 KiB, ## 검증 -[`test-tree-store.c`](../../prototypes/connections/test-tree-store.c)는 ASan·UBSan에서도 통과했다. 새로 넣은 검사: +[`test-tree-store.c`](../../store/test-tree-store.c)는 ASan·UBSan에서도 통과했다. 새로 넣은 검사: - **잃어버린 커밋**: 최신 커밋의 바이트 하나를 바꾸고 프로세스의 기억을 지우면(재부팅 뒤의 새 프로세스와 같다) 읽기, 핸들, writer가 모두 이전 커밋을 쓴다. 다음 커밋은 잃어버린 커밋이 있던 자리부터 쓴다. diff --git a/prototypes/connections/Makefile b/prototypes/connections/Makefile index 2dd85c7..9c9f485 100644 --- a/prototypes/connections/Makefile +++ b/prototypes/connections/Makefile @@ -2,19 +2,23 @@ CC ?= cc CFLAGS ?= -O2 -g CFLAGS += -std=c17 -Wall -Wextra -Wpedantic -Werror BUILD ?= build - -.PHONY: all core async-core editor fixed-editor fixed-server fixed-tui source-tui compiler mirror window server async-server document-peer document-server check check-policy check-policy-peer check-portable check-portable-tui check-paged-portable check-tree check-module check-portable-peer check-native-checkpoint check-mirror check-core check-async check-async-server check-async-service-scale check-profile check-fixed-profile check-fixed-server check-service-scale check-tui-profile check-source-tui-profile check-tui check-source-tui check-release check-micro-memory check-hybrid check-flat-export check-copy-range check-peer-profile check-document-server-profile check-window-profile check-document-peer check-document-server FORCE -CORE = runtime.c +# The core (runtime, flow, the storage contracts) and the tree store now live +# in ../../core and ../../store; this earlier document runtime builds on them. +PURE_ROOT = ../.. +CFLAGS += -I$(PURE_ROOT)/core +FLOW = $(PURE_ROOT)/core/flow.c + +.PHONY: all core async-core editor fixed-editor fixed-server fixed-tui source-tui compiler mirror window server async-server document-peer document-server check check-policy check-policy-peer check-portable check-portable-tui check-paged-portable check-tree check-portable-peer check-native-checkpoint check-mirror check-core check-async check-async-server check-async-service-scale check-profile check-fixed-profile check-fixed-server check-service-scale check-tui-profile check-source-tui-profile check-tui check-source-tui check-release check-micro-memory check-hybrid check-flat-export check-copy-range check-peer-profile check-document-server-profile check-window-profile check-document-peer check-document-server FORCE +CORE = $(PURE_ROOT)/core/runtime.c STORE ?= store.c FIXED_PROGRAM ?= examples/editor.pure -HOST = $(STORE) store-port.c evaluate.c +STORE_FILE = $(if $(filter store-tree.c,$(STORE)),$(PURE_ROOT)/store/store-tree.c,$(STORE)) +HOST = $(STORE_FILE) store-port.c evaluate.c # Document browsers list keys through the store. The tree store keeps its own # catalog; per-object file stores share a directory listing. KEYS = $(if $(filter store-tree.c,$(STORE)),,store-keys.c) -HEADERS = runtime.h program.h store.h store-port.h state.h flow.h result.h -# Defined before any rule names them: prerequisites expand when a rule is read. -MODULE = module.c module-list.c module-save.c module-text.c store-tree.c -MODULE_HEADERS = module.h module-list.h module-save.h module-text.h $(HEADERS) +CORE_HEADERS = $(addprefix $(PURE_ROOT)/core/,runtime.h store.h state.h flow.h result.h) +HEADERS = $(CORE_HEADERS) program.h store-port.h all: core fixed-editor core: $(BUILD)/libpure-execution.a async-core: $(BUILD)/libpure-execution-async.a @@ -34,21 +38,17 @@ document-server: $(BUILD)/pure-document-server $(BUILD): mkdir -p $@ -$(BUILD)/pure-connections: server.c $(HOST) flow.c program.c $(CORE) $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS server.c $(HOST) flow.c program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@ - -$(BUILD)/pure-connections-async: server.c $(HOST) flow.c program.c $(CORE) $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC server.c $(HOST) flow.c program.c $(CORE) $(LDFLAGS) -pthread $(LDLIBS) -o $@ +$(BUILD)/pure-connections: server.c $(HOST) $(FLOW) program.c $(CORE) $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS server.c $(HOST) $(FLOW) program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@ -$(BUILD)/pure-connections-async-gated: server.c $(HOST) flow.c program.c $(CORE) test-async-server-gate.c $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC -DPURE_STORE_TEST server.c $(HOST) flow.c program.c $(CORE) test-async-server-gate.c $(LDFLAGS) -pthread $(LDLIBS) -o $@ +$(BUILD)/pure-connections-async: server.c $(HOST) $(FLOW) program.c $(CORE) $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC server.c $(HOST) $(FLOW) program.c $(CORE) $(LDFLAGS) -pthread $(LDLIBS) -o $@ -# The HTTP host for aup modules: persistent connections, epoll, group commits. -$(BUILD)/pure-serve: serve.c deliver.c message-json.c flow.c module-store.c $(MODULE) $(CORE) deliver.h message-json.h module-store.h $(MODULE_HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS serve.c deliver.c message-json.c flow.c module-store.c $(MODULE) $(CORE) $(LDFLAGS) -lssl -lcrypto -lm $(LDLIBS) -o $@ +$(BUILD)/pure-connections-async-gated: server.c $(HOST) $(FLOW) program.c $(CORE) test-async-server-gate.c $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_ASYNC_EFFECTS -DPURE_HTTP_ASYNC -DPURE_STORE_TEST server.c $(HOST) $(FLOW) program.c $(CORE) test-async-server-gate.c $(LDFLAGS) -pthread $(LDLIBS) -o $@ -$(BUILD)/pure-connections-fixed: server.c $(HOST) flow.c $(CORE) $(HEADERS) $(BUILD)/embedded-plan.h | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_EMBEDDED_PROGRAM -I$(BUILD) server.c $(HOST) flow.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@ +$(BUILD)/pure-connections-fixed: server.c $(HOST) $(FLOW) $(CORE) $(HEADERS) $(BUILD)/embedded-plan.h | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_EMBEDDED_PROGRAM -I$(BUILD) server.c $(HOST) $(FLOW) $(CORE) $(LDFLAGS) $(LDLIBS) -o $@ $(BUILD)/pure-edit: edit.c $(HOST) program.c $(CORE) $(HEADERS) | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) edit.c $(HOST) program.c $(CORE) $(LDFLAGS) $(LDLIBS) -o $@ @@ -87,13 +87,13 @@ $(BUILD)/pure-edit-window: edit-window.c $(HOST) program.c $(CORE) $(HEADERS) | pkg-config --atleast-version=4.10 gtk4 $(CC) $(CPPFLAGS) $(CFLAGS) $$(pkg-config --cflags gtk4) edit-window.c $(HOST) program.c $(CORE) $(LDFLAGS) $$(pkg-config --libs gtk4) $(LDLIBS) -o $@ -$(BUILD)/runtime.o: runtime.c $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -c runtime.c -o $@ +$(BUILD)/runtime.o: $(CORE) $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -c $(CORE) -o $@ -$(BUILD)/runtime-async.o: runtime.c $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS -c runtime.c -o $@ +$(BUILD)/runtime-async.o: $(CORE) $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_ASYNC_EFFECTS -c $(CORE) -o $@ -$(BUILD)/evaluate.o: evaluate.c program.h flow.h | $(BUILD) +$(BUILD)/evaluate.o: evaluate.c program.h $(PURE_ROOT)/core/flow.h | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) -c evaluate.c -o $@ $(BUILD)/libpure-execution.a: $(BUILD)/runtime.o @@ -104,13 +104,13 @@ $(BUILD)/libpure-execution-async.a: $(BUILD)/runtime-async.o rm -f $@ $(AR) rcs $@ $^ -$(BUILD)/test-flow: test-flow.c store.c flow.c store.h flow.h result.h | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-flow.c store.c flow.c $(LDFLAGS) $(LDLIBS) -o $@ +$(BUILD)/test-flow: test-flow.c store.c $(FLOW) $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-flow.c store.c $(FLOW) $(LDFLAGS) $(LDLIBS) -o $@ -$(BUILD)/test-program: test-program.c program.c evaluate.c program.h store.h flow.h result.h | $(BUILD) +$(BUILD)/test-program: test-program.c program.c evaluate.c program.h $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) test-program.c program.c evaluate.c $(LDFLAGS) $(LDLIBS) -o $@ -$(BUILD)/test-fields: test-fields.c program.c evaluate.c program.h store.h flow.h result.h | $(BUILD) +$(BUILD)/test-fields: test-fields.c program.c evaluate.c program.h $(PURE_ROOT)/core/store.h $(PURE_ROOT)/core/flow.h $(PURE_ROOT)/core/result.h | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) test-fields.c program.c evaluate.c $(LDFLAGS) $(LDLIBS) -o $@ $(BUILD)/test-runtime: test-runtime.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD) @@ -122,24 +122,8 @@ $(BUILD)/test-async: test-async.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD $(BUILD)/test-splice: test-splice.c program.c $(CORE) $(HOST) $(HEADERS) | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_RUNTIME_METRICS -DPURE_STORE_TEST test-splice.c program.c $(CORE) $(HOST) $(LDFLAGS) $(LDLIBS) -o $@ -# Pure modules: loader/verifier/executor, its tests and a test host. -# Text states are runtime-owned drafts, so the executor links the tree engine. - -$(BUILD)/test-module: test-module.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-module.c module-store.c $(MODULE) $(LDFLAGS) -pthread -lm $(LDLIBS) -o $@ - -$(BUILD)/pure-run: pure-run.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) pure-run.c module-store.c $(MODULE) $(LDFLAGS) -lm $(LDLIBS) -o $@ - -# The document CLI contract driven by a module on the tree store. -$(BUILD)/pure-edit-module: edit-module.c module-store.c $(MODULE) module-store.h $(MODULE_HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) edit-module.c module-store.c $(MODULE) $(LDFLAGS) -lm $(LDLIBS) -o $@ - -check-module: $(BUILD)/test-module $(BUILD)/pure-run $(BUILD)/pure-edit-module $(BUILD)/pure-serve - $(BUILD)/test-module - -$(BUILD)/test-tree-store: test-tree-store.c store-tree.c $(HEADERS) | $(BUILD) - $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-tree-store.c store-tree.c $(LDFLAGS) $(LDLIBS) -o $@ +$(BUILD)/test-tree-store: $(PURE_ROOT)/store/test-tree-store.c $(PURE_ROOT)/store/store-tree.c $(HEADERS) | $(BUILD) + $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST $(PURE_ROOT)/store/test-tree-store.c $(PURE_ROOT)/store/store-tree.c $(LDFLAGS) $(LDLIBS) -o $@ $(BUILD)/test-paged-store: test-paged-store.c store-paged.c $(HEADERS) | $(BUILD) $(CC) $(CPPFLAGS) $(CFLAGS) -DPURE_STORE_TEST test-paged-store.c store-paged.c $(LDFLAGS) $(LDLIBS) -o $@ @@ -248,7 +232,7 @@ check: $(BUILD)/test-flow $(BUILD)/test-program $(BUILD)/test-fields $(BUILD)/te $(BUILD)/test-flow $(BUILD)/test-program $(BUILD)/test-fields - python3 check.py --server $(BUILD)/pure-connections --runtime-test $(BUILD)/test-runtime --splice-test $(BUILD)/test-splice --editor $(BUILD)/pure-edit --store-source $(STORE) $(if $(EVIDENCE),--output "$(EVIDENCE)") + python3 check.py --server $(BUILD)/pure-connections --runtime-test $(BUILD)/test-runtime --splice-test $(BUILD)/test-splice --editor $(BUILD)/pure-edit --store-source $(STORE_FILE) $(if $(EVIDENCE),--output "$(EVIDENCE)") check-policy: editor server source-tui $(MAKE) BUILD=$(BUILD)/policy FIXED_PROGRAM=examples/bounded-editor.pure fixed-editor fixed-server fixed-tui diff --git a/prototypes/connections/README.md b/prototypes/connections/README.md index 94d05f0..569fe41 100644 --- a/prototypes/connections/README.md +++ b/prototypes/connections/README.md @@ -1,5 +1,10 @@ # Pure: 작성한 연결을 준비해 실행하는 네이티브 경로 +2026-09-27부터 실행 코어(`runtime.c`, `flow.c`, 저장소 계약 `store.h`·`state.h`)와 트리 저장소는 저장소 최상위의 +[`core/`](../../core)와 [`store/`](../../store)에 있다. 여기의 이전 문서 런타임(000–077)은 그것들을 가져다 빌드한다 +(`make -C prototypes/connections check`, `check-tree`). 모듈 앱의 호스트(`pure-serve`, `pure-run`)는 최상위 `make`가 +만든다. [배치](../../docs/design/009-layout.md). + 기존 Workbench에서 만든 코드·배치를 실제 TCP 요청으로 저장하고 새 실행기에서 복원한다. 서버는 C17 네이티브 실행 파일이다. SQL·SQLite 의존성을 제거했고, 호출자의 바이트를 그대로 파일에 기록한다. 저장할 구간과 응답할 구간은 `.pure` 파일로 작성하며 서버 시작 때 diff --git a/prototypes/connections/check.py b/prototypes/connections/check.py index 7719537..8a51858 100644 --- a/prototypes/connections/check.py +++ b/prototypes/connections/check.py @@ -500,6 +500,12 @@ def rpc_bytes(path): return json.dumps(json.loads(path.read_text()), ensure_ascii=False, separators=(',', ':')).encode() +def source(name): + """A source file of this document runtime; the core's live in ../../core.""" + here = ROOT / name + return here if here.exists() else ROOT.parent.parent / 'core' / name + + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--server', type=Path, default=ROOT / 'build/pure-connections') @@ -532,7 +538,7 @@ def main(): result['environment'] = {'platform': platform.platform(), 'machine': platform.machine(), 'python': platform.python_version(), 'node': subprocess.check_output(['node', '--version'], text=True).strip()} result['source_sha256'] = {str(path.relative_to(ROOT.parent.parent)): hashlib.sha256(path.read_bytes()).hexdigest() - for path in [args.store_source.resolve(), *(ROOT / name for name in ('flow.c', 'flow.h', 'store.h', 'program.c', 'program.h', + for path in [args.store_source.resolve(), *(source(name) for name in ('flow.c', 'flow.h', 'store.h', 'program.c', 'program.h', 'runtime.c', 'runtime.h', 'result.h', 'evaluate.c', 'store-port.c', 'store-port.h', 'test-runtime.c', 'server.c', 'check.py', 'check_edits.py', 'edit.c', 'test-splice.c', 'test-flow.c', 'test-program.c', 'test-fields.c', 'Makefile', diff --git a/prototypes/connections/package_source.py b/prototypes/connections/package_source.py index 4a2487c..fa0fb4a 100644 --- a/prototypes/connections/package_source.py +++ b/prototypes/connections/package_source.py @@ -10,7 +10,7 @@ import tarfile ROOT = Path(__file__).resolve().parents[2] PREFIX = 'pure-source-preview' -SOURCE_ROOTS = ('prototypes/connections', 'prototypes/workbench', 'prototypes/common') +SOURCE_ROOTS = ('core', 'store', 'serve', 'cli', 'prototypes/connections', 'prototypes/workbench', 'prototypes/common') SKIP_DIRS = {'build', 'results', '__pycache__', 'node_modules', '.git', '.playwright-cli'} SUFFIXES = {'.c', '.h', '.py', '.mjs', '.js', '.zig', '.json', '.pure', '.html', '.css', '.svg', '.wasm', '.md', '.txt'} diff --git a/research/experiments/009-runtime-drafts/run.py b/research/experiments/009-runtime-drafts/run.py index 08ed55d..eb87a25 100755 --- a/research/experiments/009-runtime-drafts/run.py +++ b/research/experiments/009-runtime-drafts/run.py @@ -8,12 +8,12 @@ import subprocess from pathlib import Path HERE = Path(__file__).resolve().parent -CONNECTIONS = HERE.parents[2] / 'prototypes' / 'connections' +ROOT = HERE.parents[2] def main(): parser = argparse.ArgumentParser() - parser.add_argument('--work', type=Path, default=CONNECTIONS / 'build' / 'bench-drafts') + parser.add_argument('--work', type=Path, default=ROOT / 'build' / 'bench-drafts') parser.add_argument('--size', type=int, default=1048576) parser.add_argument('--saves', type=int, default=24) parser.add_argument('--rounds', type=int, default=3) @@ -24,8 +24,8 @@ def main(): device = subprocess.check_output(['findmnt', '-n', '-T', str(args.work), '-o', 'SOURCE,FSTYPE'], text=True).split() assert device[1] != 'tmpfs', 'fsync is free on tmpfs' binary = args.work / 'bench' - subprocess.run(['cc', '-std=c17', '-O2', '-Wall', '-Wextra', '-Werror', f'-I{CONNECTIONS}', - str(HERE / 'bench.c'), str(CONNECTIONS / 'store-tree.c'), '-o', str(binary)], check=True) + subprocess.run(['cc', '-std=c17', '-O2', '-Wall', '-Wextra', '-Werror', f'-I{ROOT / "core"}', + str(HERE / 'bench.c'), str(ROOT / 'store' / 'store-tree.c'), '-o', str(binary)], check=True) runs = [] for round_number in range(args.rounds): for mode in (('copy', 'draft') if round_number % 2 == 0 else ('draft', 'copy')): diff --git a/research/experiments/010-one-sync-commit/run.py b/research/experiments/010-one-sync-commit/run.py index 9a01c07..c729358 100644 --- a/research/experiments/010-one-sync-commit/run.py +++ b/research/experiments/010-one-sync-commit/run.py @@ -16,11 +16,18 @@ from pathlib import Path HERE = Path(__file__).resolve().parent ROOT = HERE.parents[2] -PURE = ROOT / 'prototypes' / 'connections' +CORE = ROOT / 'core' # the store's headers +STORE = ROOT / 'store' / 'store-tree.c' + + +def stored_at(revision): + """Where the tree store was at a revision: store/ now, prototypes/connections/ before.""" + moved = subprocess.run(['git', '-C', str(ROOT), 'cat-file', '-e', f'{revision}:store/store-tree.c'], capture_output=True) + return 'store/store-tree.c' if moved.returncode == 0 else 'prototypes/connections/store-tree.c' def build(output, sources): - subprocess.run(['cc', '-O2', '-std=c17', f'-I{PURE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'], + subprocess.run(['cc', '-O2', '-std=c17', f'-I{CORE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'], check=True) @@ -34,12 +41,12 @@ def main(): with tempfile.TemporaryDirectory() as work: work = Path(work) before = work / 'store-tree-before.c' - before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:prototypes/connections/store-tree.c'], + before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:{stored_at(args.before)}'], capture_output=True, text=True, check=True).stdout) build(work / 'probe', [HERE / 'probe.c']) builds = {'two syncs': work / 'commits-before', 'one sync': work / 'commits-after'} build(builds['two syncs'], [HERE / 'commits.c', before]) - build(builds['one sync'], [HERE / 'commits.c', PURE / 'store-tree.c']) + build(builds['one sync'], [HERE / 'commits.c', STORE]) results = {'rounds': []} for round_ in range(args.rounds): probe = subprocess.run([str(work / 'probe'), str(args.directory)], capture_output=True, text=True, check=True) diff --git a/research/experiments/012-tail-records/run.py b/research/experiments/012-tail-records/run.py index 7fc342e..ed8630b 100755 --- a/research/experiments/012-tail-records/run.py +++ b/research/experiments/012-tail-records/run.py @@ -18,12 +18,19 @@ from pathlib import Path HERE = Path(__file__).resolve().parent ROOT = HERE.parents[2] -PURE = ROOT / 'prototypes' / 'connections' +CORE = ROOT / 'core' # the store's headers +STORE = ROOT / 'store' / 'store-tree.c' COMMITS = HERE.parent / '010-one-sync-commit' / 'commits.c' +def stored_at(revision): + """Where the tree store was at a revision: store/ now, prototypes/connections/ before.""" + moved = subprocess.run(['git', '-C', str(ROOT), 'cat-file', '-e', f'{revision}:store/store-tree.c'], capture_output=True) + return 'store/store-tree.c' if moved.returncode == 0 else 'prototypes/connections/store-tree.c' + + def build(output, sources): - subprocess.run(['cc', '-O2', '-std=c17', f'-I{PURE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'], + subprocess.run(['cc', '-O2', '-std=c17', f'-I{CORE}', '-o', str(output)] + [str(s) for s in sources] + ['-lpthread'], check=True) @@ -37,12 +44,12 @@ def main(): with tempfile.TemporaryDirectory() as work: work = Path(work) before = work / 'store-tree-before.c' - before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:prototypes/connections/store-tree.c'], + before.write_text(subprocess.run(['git', '-C', str(ROOT), 'show', f'{args.before}:{stored_at(args.before)}'], capture_output=True, text=True, check=True).stdout) build(work / 'probe', [HERE / 'probe.c']) builds = {'heads in slots': work / 'commits-before', 'heads as records': work / 'commits-after'} build(builds['heads in slots'], [COMMITS, before]) - build(builds['heads as records'], [COMMITS, PURE / 'store-tree.c']) + build(builds['heads as records'], [COMMITS, STORE]) results = {'rounds': []} for round_ in range(args.rounds): measured = {'probe': [], 'commits': {}} diff --git a/prototypes/connections/deliver.c b/serve/deliver.c index 0d3da64..0d3da64 100644 --- a/prototypes/connections/deliver.c +++ b/serve/deliver.c diff --git a/prototypes/connections/deliver.h b/serve/deliver.h index 2d1da29..2d1da29 100644 --- a/prototypes/connections/deliver.h +++ b/serve/deliver.h diff --git a/prototypes/connections/message-json.c b/serve/message-json.c index 66c812d..66c812d 100644 --- a/prototypes/connections/message-json.c +++ b/serve/message-json.c diff --git a/prototypes/connections/message-json.h b/serve/message-json.h index 61211d6..61211d6 100644 --- a/prototypes/connections/message-json.h +++ b/serve/message-json.h diff --git a/prototypes/connections/serve.c b/serve/serve.c index 2ea7adb..2ea7adb 100644 --- a/prototypes/connections/serve.c +++ b/serve/serve.c diff --git a/prototypes/connections/store-tree.c b/store/store-tree.c index 146e919..146e919 100644 --- a/prototypes/connections/store-tree.c +++ b/store/store-tree.c diff --git a/prototypes/connections/test-tree-store.c b/store/test-tree-store.c index 1130acd..1130acd 100644 --- a/prototypes/connections/test-tree-store.c +++ b/store/test-tree-store.c |
