From d5107e9e61d1083f945edb64ec619c333024a43f Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 19 Oct 2026 14:16:33 +0100 Subject: 046, 029: the taken-over store sent a message too (opened() works on a copy: show, add, show; 20 more kill -9s: all open and take it as owners; 667 prefixes again with it: all pass); the price measured again without the fold that inflated it (entries.aup's summed view folded every entry each message): 48.5 to 232 us a message on tmpfs, 146 us of the 183 waiting for acks; the shim never stopped across the runs --- docs/design/029-past-one-node.md | 15 ++++++----- .../046-commit-replica/2026-10-19-prefixes.jsonl | 1 + .../046-commit-replica/2026-10-19-price.jsonl | 4 +++ .../046-commit-replica/2026-10-19-takeover.jsonl | 20 ++++++++++++++ .../046-commit-replica/entries-price.aup | 11 ++++++++ .../experiments/046-commit-replica/prefixes.py | 6 +++-- research/experiments/046-commit-replica/run.py | 31 +++++++++++++--------- 7 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 research/experiments/046-commit-replica/entries-price.aup diff --git a/docs/design/029-past-one-node.md b/docs/design/029-past-one-node.md index 287fa64..668471c 100644 --- a/docs/design/029-past-one-node.md +++ b/docs/design/029-past-one-node.md @@ -244,20 +244,23 @@ C의 속도로 컴파일하기 쉬운 쪽**이어야 한다. 61–183배의 절 두 저장소는 /dev/shm에 있다. 시험하는 것은 같음과 이어받기이지 매체가 아니다. - **같음.** 메시지 10만 개(컷 200,081개, 압축 34번, 이미지 다시 쓰기 1번)와 20만 개(컷 400,149개, 압축 67번, 두 번째 로그 조각)에서, 1,999컷과 3,001컷마다 주인을 멈추고 두 저장소를 이름과 바이트까지 견주었다. 표본 233번과 끝에서 다른 바이트는 0이다. -- **이어받기.** kill -9를 70번 했다. 주인만 죽인 것, 기계째(shipper도) 죽인 것, 기계째에 컷을 512 B와 64 B 레코드로 쪼갠 것이다. - 따르는 노드의 저장소는 70번 모두 주인으로 열린다. 주인이 끝났다고 한 메시지를 모두 담고, 보내지 않은 것은 없고, 항목은 차례대로다. - 70번 모두 죽은 주인의 제 저장소와 같은 수를 담았다. +- **이어받기.** kill -9를 90번 했다. 주인만 죽인 것, 기계째(shipper도) 죽인 것, 기계째에 컷을 512 B와 64 B 레코드로 쪼갠 것이다. + 따르는 노드의 저장소는 90번 모두 주인으로 열린다. 주인이 끝났다고 한 메시지를 모두 담고, 보내지 않은 것은 없고, 항목은 차례대로다. + 모두 죽은 주인의 제 저장소와 같은 수를 담았다. 나중의 20번은 연 저장소에 메시지 하나를 더 보내, 주인으로서 받는 것까지(total이 + 하나 늘고 그 항목이 들어감) 확인했다. - **찢긴 꼬리.** 컷의 레코드는 한 묶음으로 건너가서, kill이 컷의 중간을 남긴 일은 한 번도 없었다. 그래서 따르는 노드가 가질 수 있는 상태를 직접 만들었다(`prefixes.py`). 메시지 10만 개의 연산 흐름(507,150개)에서 연산 경계 867곳까지 적용한 저장소를 주인으로 열었다. 컷 안에서 끝나는 것이 568곳, 압축과 이미지 설치 둘레가 266곳이다. 모두 오류 없이 열리고, 담은 항목이 정확히 처음 메시지들의 - 것이며, 짧은 접두가 담은 것을 긴 접두가 잃지 않는다. + 것이며, 짧은 접두가 담은 것을 긴 접두가 잃지 않는다. 다시 돌린 667곳(컷 안 447곳)은 메시지 하나를 더 받는 것까지 확인했다. +- 실행 내내 shim의 멈춤은 한 번도 일어나지 않았다. 30만 개가 넘는 메시지에서 보낸 연산 밖의 길로 파일이 바뀐 적이 없다는 증거다. - **원리의 문구와 어긋난 것.** "저장 한 번이 쓰는 것은 모두 스스로 경계를 갖고 스스로 검증하는 구간"은 문구대로는 틀렸다. 저장소는 구간 말고 파일의 연산도 한다. 꼬리에 0을 미리 쓰고, 압축한 새 트리를 프로세스 번호가 든 임시 이름으로 써서 rename으로 설치하고, 이미지도 그렇게 설치하며, 디렉터리를 fsync하고, 로그 조각을 8 MB씩 잡는다. 그래서 구간이 아니라 연산 여덟 가지를 실었다. 029가 "첫 실증이 그것을 드러낸다"고 적은 것이 그것이다. 그래도 복제 계층은 없다. 실은 것은 저장소가 제 sync에서 끊은 제 연산이고, 확인은 heard다. -- **값.** /dev/shm에서 메시지 하나에 204 µs → 400 µs(두 번 재어 같다)다. 그 가운데 155 µs가 확인을 기다린 시간이다(메시지 하나에 - 컷 둘). 보낸 바이트는 메시지 하나에 903 B다. 압축의 새 파일 371, 트리의 커밋 365, 로그 71, 이미지 7이다. 그 42%(3,800만 B)가 +- **값.** /dev/shm에서 메시지 하나에 48.5 µs → 232 µs(두 번 재어 같다)다. 늘어난 183 µs 가운데 146 µs가 확인을 기다린 시간이다 + (메시지 하나에 컷 둘, 루프백). /dev/shm의 fsync는 거의 공짜라서 기준이 낮다. 처음 적은 204 → 400 µs는 기준이 부풀었다. 그 앱의 보기 + `summed`가 메시지마다 모든 항목을 접었다(`--views`가 메시지마다 보기를 보인다). 보기 하나인 `entries-price.aup`로 다시 쟀다. 보낸 바이트는 메시지 하나에 903 B다. 압축의 새 파일 371, 트리의 커밋 365, 로그 71, 이미지 7이다. 그 42%(3,800만 B)가 미리 쓴 0이다. 0은 따르는 노드가 스스로 만들 수 있으니, 연산 하나("여기서부터 이만큼 0")로 보내면 반으로 준다. 재지 않았다. - **시험하지 않은 것.** - 따르는 노드를 다시 시작하는 것. heard는 메모리에 있다. 계층을 지우는 다음 답은 heard를 따르는 노드의 파일(트리의 마지막 커밋)에서 diff --git a/research/experiments/046-commit-replica/2026-10-19-prefixes.jsonl b/research/experiments/046-commit-replica/2026-10-19-prefixes.jsonl index d552f5b..6a22156 100644 --- a/research/experiments/046-commit-replica/2026-10-19-prefixes.jsonl +++ b/research/experiments/046-commit-replica/2026-10-19-prefixes.jsonl @@ -1,2 +1,3 @@ {"run": "prefixes", "events": 20000, "ops": 101464, "journal_bytes": 18144281, "samples": 301, "within_cuts": 195, "failed": 0, "failures": [], "seconds": 3.1} {"run": "prefixes", "events": 100000, "ops": 507150, "journal_bytes": 90258606, "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}, "samples": 867, "near_renames": 266, "within_cuts": 568, "failed": 0, "failures": [], "seconds": 22.8} +{"run": "prefixes", "events": 100000, "ops": 507150, "journal_bytes": 90258606, "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}, "samples": 667, "near_renames": 266, "within_cuts": 447, "failed": 0, "failures": [], "seconds": 21.8} diff --git a/research/experiments/046-commit-replica/2026-10-19-price.jsonl b/research/experiments/046-commit-replica/2026-10-19-price.jsonl index 385b3cb..85cac49 100644 --- a/research/experiments/046-commit-replica/2026-10-19-price.jsonl +++ b/research/experiments/046-commit-replica/2026-10-19-price.jsonl @@ -1,2 +1,6 @@ +{"what": "the first two runs: entries.aup, whose summed view folds every entry each message (--views shows the views after each): the base inflated, kept as the record of it"} {"run": "price", "events": 100000, "without": {"seconds": 20.453, "us_per_event": 204.5, "done": 100000}, "with_shim": {"seconds": 40.164, "us_per_event": 401.6, "done": 100000}, "shim": {"cuts": 200081, "shipped_bytes": 90258606, "waited_ms": 15494.9, "create": [40, 1149], "write": [306989, 88255228], "truncate": [0, 0], "allocate": [1, 24], "rename": [38, 1237], "unlink": [0, 0], "mkdir": [1, 7], "sync": [200081, 2000961], "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}}, "shipper": {"cuts": 200081, "records": 200114, "record_bytes": 92059632, "waited_ms": 12284.0, "packets": 228164, "resent": 0}} {"run": "price", "events": 100000, "without": {"seconds": 20.414, "us_per_event": 204.1, "done": 100000}, "with_shim": {"seconds": 39.992, "us_per_event": 399.9, "done": 100000}, "shim": {"cuts": 200081, "shipped_bytes": 90258606, "waited_ms": 15418.9, "create": [40, 1149], "write": [306989, 88255228], "truncate": [0, 0], "allocate": [1, 24], "rename": [38, 1237], "unlink": [0, 0], "mkdir": [1, 7], "sync": [200081, 2000961], "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}}, "shipper": {"cuts": 200081, "records": 200114, "record_bytes": 92059632, "waited_ms": 12271.7, "packets": 228164, "resent": 0}} +{"what": "again with entries-price.aup (one view, total, no fold): the price as it is"} +{"run": "price", "events": 100000, "without": {"seconds": 4.848, "us_per_event": 48.5, "done": 100000}, "with_shim": {"seconds": 23.389, "us_per_event": 233.9, "done": 100000}, "shim": {"cuts": 200081, "shipped_bytes": 90258606, "waited_ms": 14699.9, "create": [40, 1149], "write": [306989, 88255228], "truncate": [0, 0], "allocate": [1, 24], "rename": [38, 1237], "unlink": [0, 0], "mkdir": [1, 7], "sync": [200081, 2000961], "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}}, "shipper": {"cuts": 200081, "records": 200114, "record_bytes": 92059632, "waited_ms": 11684.9, "packets": 228164, "resent": 0}} +{"run": "price", "events": 100000, "without": {"seconds": 4.874, "us_per_event": 48.7, "done": 100000}, "with_shim": {"seconds": 22.949, "us_per_event": 229.5, "done": 100000}, "shim": {"cuts": 200081, "shipped_bytes": 90258606, "waited_ms": 14495.4, "create": [40, 1149], "write": [306989, 88255228], "truncate": [0, 0], "allocate": [1, 24], "rename": [38, 1237], "unlink": [0, 0], "mkdir": [1, 7], "sync": [200081, 2000961], "renamed_to": {"pure.tree": 34, "image-entries": 2, "image-0heard": 1, "image-0sent": 1}}, "shipper": {"cuts": 200081, "records": 200114, "record_bytes": 92059632, "waited_ms": 11588.7, "packets": 228164, "resent": 0}} diff --git a/research/experiments/046-commit-replica/2026-10-19-takeover.jsonl b/research/experiments/046-commit-replica/2026-10-19-takeover.jsonl index d800b69..17f3c99 100644 --- a/research/experiments/046-commit-replica/2026-10-19-takeover.jsonl +++ b/research/experiments/046-commit-replica/2026-10-19-takeover.jsonl @@ -68,3 +68,23 @@ {"run": "takeover", "k": 27, "whole_node": true, "record": "64", "sent": 8584, "owner_said_done": 4453, "follower_took": {"opened": true, "fault": "none", "total": 4456, "summed": 2102854}, "follower": {"within_cut": false, "heard": 22641, "cuts": 8928, "ops": 22649, "op_bytes": 4630160, "received": 10648, "deliveries": 8947, "stored": 22641}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 4456, "summed": 2102854}} {"run": "takeover", "k": 28, "whole_node": true, "record": "64", "sent": 14294, "owner_said_done": 7254, "follower_took": {"opened": true, "fault": "none", "total": 7313, "summed": 3547156.25}, "follower": {"within_cut": false, "heard": 37127, "cuts": 14643, "ops": 37136, "op_bytes": 7199136, "received": 17173, "deliveries": 14675, "stored": 37127}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 7313, "summed": 3547156.25}} {"run": "takeover", "k": 29, "whole_node": true, "record": "64", "sent": 3055, "owner_said_done": 1720, "follower_took": {"opened": true, "fault": "none", "total": 1736, "summed": 770414}, "follower": {"within_cut": false, "heard": 8838, "cuts": 3485, "ops": 8845, "op_bytes": 1737193, "received": 4111, "deliveries": 3492, "stored": 8838}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 1736, "summed": 770414}} +{"run": "takeover", "k": 0, "whole_node": false, "record": null, "sent": 18150, "owner_said_done": 9495, "follower_took": {"opened": true, "fault": "none", "total": 9509, "summed": 4627163.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 19040, "cuts": 19037, "ops": 48278, "op_bytes": 9431981, "received": 22375, "deliveries": 19040, "stored": 19040}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 9509, "summed": 4627163.25, "takes_a_message": true}} +{"run": "takeover", "k": 1, "whole_node": true, "record": null, "sent": 12101, "owner_said_done": 6204, "follower_took": {"opened": true, "fault": "none", "total": 6205, "summed": 3019461.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 12430, "cuts": 12428, "ops": 31528, "op_bytes": 6635696, "received": 14957, "deliveries": 12430, "stored": 12430}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 6205, "summed": 3019461.25, "takes_a_message": true}} +{"run": "takeover", "k": 2, "whole_node": false, "record": null, "sent": 16709, "owner_said_done": 8444, "follower_took": {"opened": true, "fault": "none", "total": 8481, "summed": 4113560.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 16982, "cuts": 16980, "ops": 43051, "op_bytes": 7793156, "received": 19509, "deliveries": 16982, "stored": 16982}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 8481, "summed": 4113560.25, "takes_a_message": true}} +{"run": "takeover", "k": 3, "whole_node": true, "record": null, "sent": 13756, "owner_said_done": 6974, "follower_took": {"opened": true, "fault": "none", "total": 7017, "summed": 3498390.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 14053, "cuts": 14051, "ops": 35637, "op_bytes": 7048544, "received": 16580, "deliveries": 14053, "stored": 14053}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 7017, "summed": 3498390.25, "takes_a_message": true}} +{"run": "takeover", "k": 4, "whole_node": false, "record": null, "sent": 297, "owner_said_done": 222, "follower_took": {"opened": true, "fault": "none", "total": 257, "summed": 32960.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 528, "cuts": 528, "ops": 1348, "op_bytes": 394849, "received": 725, "deliveries": 528, "stored": 528}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 257, "summed": 32960.25, "takes_a_message": true}} +{"run": "takeover", "k": 5, "whole_node": true, "record": null, "sent": 1911, "owner_said_done": 1155, "follower_took": {"opened": true, "fault": "none", "total": 1201, "summed": 519900.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 2415, "cuts": 2415, "ops": 6133, "op_bytes": 1268367, "received": 2897, "deliveries": 2415, "stored": 2415}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 1201, "summed": 519900.25, "takes_a_message": true}} +{"run": "takeover", "k": 6, "whole_node": false, "record": null, "sent": 13148, "owner_said_done": 6764, "follower_took": {"opened": true, "fault": "none", "total": 6808, "summed": 3324730, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 13635, "cuts": 13633, "ops": 34579, "op_bytes": 6942277, "received": 16162, "deliveries": 13635, "stored": 13635}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 6808, "summed": 3324730, "takes_a_message": true}} +{"run": "takeover", "k": 7, "whole_node": true, "record": null, "sent": 8181, "owner_said_done": 4103, "follower_took": {"opened": true, "fault": "none", "total": 4114, "summed": 2005469.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 8245, "cuts": 8244, "ops": 20918, "op_bytes": 4456310, "received": 9964, "deliveries": 8245, "stored": 8245}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 4115, "summed": 2005583.75, "takes_a_message": true}} +{"run": "takeover", "k": 8, "whole_node": false, "record": null, "sent": 12853, "owner_said_done": 6484, "follower_took": {"opened": true, "fault": "none", "total": 6509, "summed": 3127913.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 13037, "cuts": 13035, "ops": 33065, "op_bytes": 6790188, "received": 15564, "deliveries": 13037, "stored": 13037}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 6509, "summed": 3127913.25, "takes_a_message": true}} +{"run": "takeover", "k": 9, "whole_node": true, "record": null, "sent": 18820, "owner_said_done": 9985, "follower_took": {"opened": true, "fault": "none", "total": 9986, "summed": 4983601.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 19994, "cuts": 19991, "ops": 50693, "op_bytes": 9674564, "received": 23329, "deliveries": 19994, "stored": 19994}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 9986, "summed": 4983601.5, "takes_a_message": true}} +{"run": "takeover", "k": 10, "whole_node": false, "record": null, "sent": 17703, "owner_said_done": 8864, "follower_took": {"opened": true, "fault": "none", "total": 8927, "summed": 4427432.75, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 17873, "cuts": 17871, "ops": 45307, "op_bytes": 8019874, "received": 20400, "deliveries": 17873, "stored": 17873}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 8927, "summed": 4427432.75, "takes_a_message": true}} +{"run": "takeover", "k": 11, "whole_node": true, "record": null, "sent": 15741, "owner_said_done": 8024, "follower_took": {"opened": true, "fault": "none", "total": 8038, "summed": 3998712.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 16096, "cuts": 16094, "ops": 40808, "op_bytes": 7567843, "received": 18623, "deliveries": 16096, "stored": 16096}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 8038, "summed": 3998712.5, "takes_a_message": true}} +{"run": "takeover", "k": 12, "whole_node": false, "record": null, "sent": 2055, "owner_said_done": 1155, "follower_took": {"opened": true, "fault": "none", "total": 1162, "summed": 512831.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 2337, "cuts": 2337, "ops": 5935, "op_bytes": 1248450, "received": 2819, "deliveries": 2337, "stored": 2337}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 1162, "summed": 512831.5, "takes_a_message": true}} +{"run": "takeover", "k": 13, "whole_node": true, "record": null, "sent": 8347, "owner_said_done": 4243, "follower_took": {"opened": true, "fault": "none", "total": 4292, "summed": 2041559, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 8600, "cuts": 8599, "ops": 21817, "op_bytes": 4546712, "received": 10319, "deliveries": 8600, "stored": 8600}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 4292, "summed": 2041559, "takes_a_message": true}} +{"run": "takeover", "k": 14, "whole_node": false, "record": null, "sent": 6399, "owner_said_done": 3333, "follower_took": {"opened": true, "fault": "none", "total": 3374, "summed": 1569094.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 6764, "cuts": 6763, "ops": 17170, "op_bytes": 4079966, "received": 8483, "deliveries": 6764, "stored": 6764}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 3374, "summed": 1569094.5, "takes_a_message": true}} +{"run": "takeover", "k": 15, "whole_node": true, "record": null, "sent": 18833, "owner_said_done": 9915, "follower_took": {"opened": true, "fault": "none", "total": 9946, "summed": 4944971.5, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 19914, "cuts": 19911, "ops": 50490, "op_bytes": 9654148, "received": 23249, "deliveries": 19914, "stored": 19914}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 9946, "summed": 4944971.5, "takes_a_message": true}} +{"run": "takeover", "k": 16, "whole_node": false, "record": null, "sent": 5946, "owner_said_done": 3053, "follower_took": {"opened": true, "fault": "none", "total": 3057, "summed": 1500860.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 6130, "cuts": 6129, "ops": 15565, "op_bytes": 3918743, "received": 7849, "deliveries": 6130, "stored": 6130}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 3057, "summed": 1500860.25, "takes_a_message": true}} +{"run": "takeover", "k": 17, "whole_node": true, "record": null, "sent": 2487, "owner_said_done": 1296, "follower_took": {"opened": true, "fault": "none", "total": 1316, "summed": 549599, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 2645, "cuts": 2645, "ops": 6715, "op_bytes": 1326816, "received": 3127, "deliveries": 2645, "stored": 2645}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 1316, "summed": 549599, "takes_a_message": true}} +{"run": "takeover", "k": 18, "whole_node": false, "record": null, "sent": 5568, "owner_said_done": 2983, "follower_took": {"opened": true, "fault": "none", "total": 2988, "summed": 1487325, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 5989, "cuts": 5989, "ops": 15191, "op_bytes": 2767487, "received": 6900, "deliveries": 5989, "stored": 5989}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 2988, "summed": 1487325, "takes_a_message": true}} +{"run": "takeover", "k": 19, "whole_node": true, "record": null, "sent": 19750, "owner_said_done": 11018, "follower_took": {"opened": true, "fault": "none", "total": 11045, "summed": 5498251.25, "takes_a_message": true}, "follower": {"within_cut": false, "heard": 22112, "cuts": 22109, "ops": 56054, "op_bytes": 10213037, "received": 25447, "deliveries": 22112, "stored": 22112}, "passed": true, "owner_opened": {"opened": true, "fault": "none", "total": 11045, "summed": 5498251.25, "takes_a_message": true}} diff --git a/research/experiments/046-commit-replica/entries-price.aup b/research/experiments/046-commit-replica/entries-price.aup new file mode 100644 index 0000000..450b2bb --- /dev/null +++ b/research/experiments/046-commit-replica/entries-price.aup @@ -0,0 +1,11 @@ +record Entry { + n = 0 +} +state entries: list of Entry +state count = 0 +input add = message { n: number } +on add { + entries.append(Entry { n: add.n }) + count = count + 1 +} +view total = count diff --git a/research/experiments/046-commit-replica/prefixes.py b/research/experiments/046-commit-replica/prefixes.py index ab228aa..5d56c7b 100644 --- a/research/experiments/046-commit-replica/prefixes.py +++ b/research/experiments/046-commit-replica/prefixes.py @@ -3,7 +3,8 @@ part of a cut: a cut's records travel together). The owner takes EVENTS messages with the shim keeping every op it shipped (SHIM_JOURNAL); then the ops are done again in order into a fresh directory, and at SAMPLES points (op boundaries drawn at random, within cuts and at their ends, and the whole stream) a copy of what is there is opened by -pure-run as the owner (and around every rename: a compaction's or an image's install). Each must open without a fault, hold the first `total` messages' entries exactly (summed), hold +pure-run as the owner (and around every rename: a compaction's or an image's install). Each must open without a fault, take +a message as an owner does, hold the first `total` messages' entries exactly (summed), hold no fewer than at the sample before (a prefix never loses what a shorter one held), and the whole stream every message. prefixes.py EVENTS SAMPLES one JSON line a sample, then one of the totals""" @@ -98,7 +99,8 @@ def main(): shutil.copytree(root, copy) took = harness.opened(copy) total = int(took.get('total', -1)) if took.get('opened') else -1 - good = (took.get('opened') and took.get('fault') == 'none' and took.get('summed') == harness.summed(total) and + good = (took.get('opened') and took.get('fault') == 'none' and took.get('takes_a_message') and + took.get('summed') == harness.summed(total) and total >= last_total and (pick < len(ops) or total == events)) if not good: failures.append({'ops': pick, 'cut': ops[pick - 1][3], 'within_cut': mid, 'took': took, 'before': last_total}) diff --git a/research/experiments/046-commit-replica/run.py b/research/experiments/046-commit-replica/run.py index 1e4f4b8..e31ff50 100644 --- a/research/experiments/046-commit-replica/run.py +++ b/research/experiments/046-commit-replica/run.py @@ -46,7 +46,8 @@ def build(): for name in ('shipper', 'follower'): subprocess.run(cc + [f'-I{PURE / "link"}', str(HERE / f'{name}.c'), str(PURE / 'build' / 'libpure-link.a'), '-lm', '-pthread', '-ldl', '-o', str(WORK / name)], check=True) - subprocess.run([str(AUP), 'build', str(HERE / 'entries.aup'), '-o', str(WORK / 'entries.pmod')], check=True) + for name in ('entries', 'entries-price'): # the price's: no view that folds the list (each message shows the views) + subprocess.run([str(AUP), 'build', str(HERE / f'{name}.aup'), '-o', str(WORK / f'{name}.pmod')], check=True) keys = json.loads(subprocess.run([str(WORK / 'follower'), 'keys', str(WORK)], capture_output=True, text=True, check=True, env=ENV).stdout) return keys @@ -85,7 +86,7 @@ def stores_differ(a, b): class Run: """A follower, a shipper and an owner, started in that order on fresh stores.""" - def __init__(self, keys, every=0, shim=True): + def __init__(self, keys, every=0, shim=True, module='entries'): self.owner_dir, self.follower_dir = WORK / 'owner-store', WORK / 'follower-store' for d in (self.owner_dir, self.follower_dir): shutil.rmtree(d, ignore_errors=True) @@ -111,7 +112,7 @@ class Run: self.paused = os.open(WORK / 'paused', os.O_RDWR) # held open both ways: no open waits for the other end self.resume = os.open(WORK / 'resume', os.O_RDWR) env.update(SHIM_PAUSE_EVERY=str(every), SHIM_PAUSE_DIR=str(WORK)) - self.owner = subprocess.Popen([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(self.owner_dir)], + self.owner = subprocess.Popen([str(RUN), str(WORK / f'{module}.pmod'), '--views', '--store', str(self.owner_dir)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env, bufsize=1) self.done = 0 # messages the owner said done (each line comes after its save, so after the follower's ack) @@ -144,14 +145,19 @@ class Run: def opened(store): - """The store opened by pure-run as its owner: the views (total, summed) it shows, or why it did not open.""" - r = subprocess.run([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(store)], input='show\n', - capture_output=True, text=True, env=ENV, timeout=120) - lines = [l for l in r.stdout.splitlines() if l.startswith('{')] - if r.returncode or not lines: + """The store opened by pure-run as its owner: the views (total, summed) it shows, and whether it then takes a message + as an owner does (total one more, the entry its own; on a copy: the store looked at is left as it was).""" + shutil.rmtree(WORK / 'opened', ignore_errors=True) + shutil.copytree(store, WORK / 'opened') + r = subprocess.run([str(RUN), str(WORK / 'entries.pmod'), '--views', '--store', str(WORK / 'opened')], + input='show\n' + message(7) + 'show\n', capture_output=True, text=True, env=ENV, timeout=120) + lines = [json.loads(l) for l in r.stdout.splitlines() if l.startswith('{')] + if r.returncode or len(lines) < 3: return {'opened': False, 'exit': r.returncode, 'stderr': r.stderr[-300:]} - shown = json.loads(lines[-1]) - return {'opened': True, 'fault': shown.get('fault'), **shown['views']} + shown, after = lines[0], lines[-1] + took = (after['views']['total'] == shown['views']['total'] + 1 and after['fault'] == 'none' and + after['views']['summed'] == shown['views']['summed'] + 7.25) + return {'opened': True, 'fault': shown.get('fault'), **shown['views'], 'takes_a_message': took} def summed(n): # every partial sum a multiple of 0.25 below 2^50: exact as a binary64 @@ -212,7 +218,8 @@ def takeover(keys, runs, events, torn=False): time.sleep(1.0) # what was on the way reaches the follower follower = run.stop_follower() took = opened(run.follower_dir) - good = (took.get('opened') and took.get('fault') == 'none' and done <= took.get('total', -1) <= sent and + good = (took.get('opened') and took.get('fault') == 'none' and took.get('takes_a_message') and + done <= took.get('total', -1) <= sent and took.get('summed') == summed(int(took.get('total', 0)))) print(json.dumps({'run': 'takeover', 'k': k, 'whole_node': whole_node, 'record': os.environ.get('SHIPPER_RECORD'), 'sent': sent, 'owner_said_done': done, 'follower_took': took, 'follower': follower, 'passed': bool(good), @@ -222,7 +229,7 @@ def takeover(keys, runs, events, torn=False): def price(keys, events): out = {} for shim in (False, True): - run = Run(keys, shim=shim) + run = Run(keys, shim=shim, module='entries-price') start = time.perf_counter() run.feed(events) run.owner.wait() -- cgit v1.2.3