Skip to content

fix(execution): use jemalloc as the global allocator so server memory stays bounded under sustained load - #379

Merged
jsam merged 2 commits into
mainfrom
fm/fix-mem-growth
Oct 5, 2026
Merged

jsam merged 2 commits into
mainfrom
fm/fix-mem-growth

Conversation

@jsam

@jsam jsam commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Intent

I want you to really hyper focus on making the symbolic engine, you know, crisp and really truly production ready. (Context: implement #376: the 30-minute soak showed server RSS growing 251 -> 1,012 MiB from glibc arena retention; capping arenas costs ~40% throughput.)

What Changed

  • MeteredAllocator (src/execution/memory.rs) now forwards to jemalloc (tikv-jemallocator) instead of System on every non-MSVC target. glibc's per-thread arenas held on to freed memory, so RSS kept growing under sustained load (Server memory grows under sustained load: RSS 251 -> 1,012 MiB in a 30-minute soak (glibc arena retention) #376). release_freed_memory used to call glibc's malloc_trim. It now runs jemalloc's arena.<all>.purge through mallctl, and a new unit test checks that the purge returns success.
  • Cargo.toml adds tikv-jemallocator/tikv-jemalloc-sys 0.6 as non-MSVC target dependencies. The Dockerfile sets JEMALLOC_SYS_WITH_LG_PAGE=16 for arm64 builds, so the image starts on kernels with 64 KiB pages as well as 4 KiB ones.
  • In the differential-oracle soak test, a slow or stalled consumer that gets disconnected while subscribing is now counted as an allowed disconnect, as it already was after subscribing. Previously it failed the run.

Risk Assessment

⚠️ Medium: Replacing the process-wide global allocator, and its build-time page-size handling for arm64 Docker images, is a small diff with a wide blast radius. The forwarding, metering, purge mallctl (arena.4096.purge, i.e. MALLCTL_ARENAS_ALL), the msvc fallback and the soak test relaxation all look correct.

Testing

Release builds of the change and of base efa87aa were each run as a real inputlayer-server, under a systemd user scope (MemoryMax=16G, no swap), and driven with the real inputlayer-client. On the change, an unbounded closure query peaked at about 1 GiB and resident memory was back to 72 MiB within about 2 s; a small query still worked afterwards. With a 32 MiB query limit, both builds refused the runaway query and the same connection kept answering. The repo's /ws memory_limit_tests also passed on the jemalloc build, confirming the resource_exhausted code. As the operator decided, the sustained-memory and slow-consumer-harness scenarios use the 30-minute soak on the benchmark host, which passed: RSS stayed flat between 95 and 124 MiB, against the glibc baseline's growth from 251 to 1,012 MiB. That run had 829 slow-subscriber disconnects and no failures. These are CLI transcripts and RSS logs; there is no UI, so there are no screenshots. All scratch servers and builds under /tmp were removed.

  • Live validation: ✅ go - 4 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Under a sustained soak, server resident memory stays bounded on the change, unlike the glibc base that grew from 251 to 1,012 MiB ✅ pass live Operator-provided benchmark-host run (sam-dev-benchmarks, built from e2a0882e, whose engine is the same as this branch): 30-minute sustained soak passed with 0 failures, 574,594 commits at 319/s, RSS…
After a runaway closure query peaks above 64 MiB, resident memory falls back within seconds and small queries still work on the same server ✅ pass live check-a-runaway-closure.txt and rss-summary.txt: on the change, a peak of 1,003 MiB fell below 25% of the peak in 1.99 s and ended at 72 MiB, and ?edge(0, Y) returned 2 rows. Base: 1,121 MiB to 96 M…
With max_query_memory_bytes = 32 MiB, a runaway query is refused with resource_exhausted and the connection stays usable under jemalloc ✅ pass live check-b-query-memory-limit.txt: both builds answered 'Request exceeded the per-query memory limit ... nothing was applied', then .session clear and ?edge(0, Y) returned 2 rows on the same connecti…
A slow or stalled soak consumer that is closed while it subscribes counts as an allowed disconnect, not a soak failure ✅ pass live Operator-provided benchmark-host soak: ws_slow_subscriber_disconnected 829 and slow consumers closed 807 times, with 0 soak failures
Evidence: RSS summary for checks (a) and (b), change vs base

a2-head: peak_rss=1003 MiB, final_rss=72 MiB, time from peak to <25% of peak=1.99s a2-base: peak_rss=1121 MiB, final_rss=96 MiB, time from peak to <25% of peak=3.04s b2-head: peak_rss=75 MiB (query refused at 32 MiB limit) b2-base: peak_rss=62 MiB (query refused at 32 MiB limit)

Dev box, each server under systemd-run --user --scope -p MemoryMax=16G -p MemorySwapMax=0; release builds (head=ac4be1ee jemalloc, base=efa87aa5 glibc).
a2-head: peak_rss=1003 MiB, final_rss=72 MiB, time from peak to <25% of peak=1.99s
a2-base: peak_rss=1121 MiB, final_rss=96 MiB, time from peak to <25% of peak=3.04s
b2-head: peak_rss=75 MiB, final_rss=75 MiB, time from peak to <25% of peak=n/a
b2-base: peak_rss=62 MiB, final_rss=62 MiB, time from peak to <25% of peak=n/a
  • Evidence: Check (a) runaway closure transcript (both builds) (local file: ~/.no-mistakes/evidence/01M471W8JV2JZ8MZPH16CM73JC/check-a-runaway-closure.txt)
  • Evidence: Check (b) 32 MiB query limit refusal transcript (both builds) (local file: ~/.no-mistakes/evidence/01M471W8JV2JZ8MZPH16CM73JC/check-b-query-memory-limit.txt)
Evidence: RSS samples at 50 ms, change
1791238843.137723991 23604
1791238843.192969631 30044
1791238843.247693776 33884
1791238843.302380846 46684
1791238843.357139273 62300
1791238843.411785500 70236
1791238843.466539441 77404
1791238843.521626679 97628
1791238843.576633145 114012
1791238843.631588763 125276
1791238843.686658975 125276
1791238843.742096607 131164
1791238843.797578115 137564
1791238843.853010950 144732
1791238843.908553311 153692
1791238843.964119338 189276
1791238844.019606996 197468
1791238844.074778632 218204
1791238844.130114119 219484
1791238844.185497387 235356
1791238844.240449099 249692
1791238844.295041084 257372
1791238844.349551835 257372
1791238844.403917703 257372
1791238844.458434700 257372
1791238844.513252245 257372
1791238844.567870297 269660
1791238844.622574099 270940
1791238844.677193312 273244
1791238844.731761939 280412
1791238844.787095890 284764
1791238844.841805972 295004
1791238844.896462772 299612
1791238844.951168377 301352
1791238845.005954454 311160
1791238845.060681812 331248
1791238845.115879076 372208
1791238845.171391909 372208
1791238845.226493066 372208
1791238845.281974402 384612
1791238845.337794404 402276
1791238845.392953829 409700
1791238845.448075808 412004
1791238845.503036782 412004
1791238845.558107582 435300
1791238845.613128918 447588
1791238845.668273311 459620
1791238845.723065067 459620
1791238845.778121005 459620
1791238845.833303626 459620
1791238845.888588412 459620
1791238845.943965189 459620
1791238845.999326743 459620
1791238846.054710880 463716
1791238846.109966833 461932
1791238846.165400456 461932
1791238846.220806668 461932
1791238846.275942568 461932
1791238846.331424064 461932
1791238846.386779768 475500
1791238846.442248174 486508
1791238846.497570568 485284
1791238846.552952112 487844
1791238846.608099219 489892
1791238846.663575757 493220
1791238846.719007918 497060
1791238846.774511538 506532
1791238846.829596791 507040
1791238846.884882238 508064
1791238846.940041394 509344
1791238846.995380143 510624
1791238847.050647192 511540
1791238847.105864566 512820
1791238847.160590983 518196
1791238847.215556553 527924
1791238847.270316501 512404
1791238847.325395534 510796
1791238847.380858902 565580
1791238847.436154776 599628
1791238847.490698925 599628
1791238847.545544383 599628
1791238847.600620491 599628
1791238847.655424887 599628
1791238847.710268582 622156
1791238847.765528310 644280
1791238847.820279695 644280
1791238847.875534696 650548
1791238847.930417651 656948
1791238847.985589015 654616
1791238848.040738275 654616
1791238848.095842967 654616
1791238848.151148856 654616
1791238848.206102969 654616
1791238848.261269185 654616
1791238848.316336070 654616
1791238848.371573515 654616
1791238848.426552996 654616
1791238848.481261075 654616
1791238848.536390235 654616
1791238848.591117773 677656
1791238848.646781296 705048
1791238848.701912378 726296
1791238848.756707570 711868
1791238848.812053680 711868
1791238848.867466772 711868
1791238848.922792861 711868
1791238848.977941971 711868
1791238849.033202941 711868
1791238849.088250156 711868
1791238849.143281016 711868
1791238849.198316583 711868
1791238849.253149512 711868
1791238849.308119770 711868
1791238849.363138812 716732
1791238849.418088208 731324
1791238849.472734582 744380
1791238849.527620452 747552
1791238849.582227256 747552
1791238849.637376676 749344
1791238849.692378963 750112
1791238849.747308669 753952
1791238849.802233568 754720
1791238849.856596190 755488
1791238849.911136283 756256
1791238849.965953388 757024
1791238850.020705183 757792
1791238850.075537280 758560
1791238850.130556813 759072
1791238850.185322389 759840
1791238850.240298005 760608
1791238850.295277066 761376
1791238850.350343811 762144
1791238850.405356653 764960
1791238850.460303085 765984
1791238850.514919984 774944
1791238850.569700754 785184
1791238850.624505299 808480
1791238850.679233518 835616
1791238850.733742915 838944
1791238850.788577906 820428
1791238850.843532270 810016
1791238850.898502357 825888
1791238850.953456010 838688
1791238851.008660554 838688
1791238851.063913683 838688
1791238851.119326584 838688
1791238851.174502966 878368
1791238851.229697805 878368
1791238851.285144589 883080
1791238851.340666126 885332
1791238851.395935689 881488
1791238851.451503276 881488
1791238851.506683994 881488
1791238851.562252292 881488
1791238851.617187988 881488
1791238851.671750224 881488
1791238851.727235957 881488
1791238851.782810054 881488
1791238851.838018674 881488
1791238851.893355159 881488
1791238851.948566234 881488
1791238852.003497552 881488
1791238852.058614403 898896
1791238852.114085583 887848
1791238852.169097845 888104
1791238852.223979678 886308
1791238852.278735219 886308
1791238852.333801333 884260
1791238852.388779402 883492
1791238852.443544948 882468
1791238852.498359059 877860
1791238852.553260572 877860
1791238852.608378134 873640
1791238852.663276582 887976
1791238852.718282905 899460
1791238852.773610326 900988
1791238852.828470536 900988
1791238852.883383417 901756
1791238852.938294344 900728
1791238852.993567964 900984
1791238853.048858339 901752
1791238853.104066008 902008
1791238853.159238193 901744
1791238853.214678566 901476
1791238853.270276289 901732
1791238853.325706668 901988
1791238853.380810048 902244
1791238853.436263191 902500
1791238853.491492453 902756
1791238853.546905965 903268
1791238853.602742582 903524
1791238853.657789947 903780
1791238853.712522714 902084
1791238853.767696361 912068
1791238853.822785910 922308
1791238853.877717149 932292
1791238853.932381721 953284
1791238853.987911100 977348
1791238854.043440609 993220
1791238854.098865709 989252
1791238854.153894646 895788
1791238854.209100052 895788
1791238854.264313159 895788
1791238854.319117815 901456
1791238854.373830030 901196
1791238854.428766396 901196
1791238854.483876477 901196
1791238854.538996382 901196
1791238854.593702007 899660
1791238854.648992092 899660
1791238854.704428920 896536
1791238854.759726546 895480
1791238854.815050943 892188
1791238854.870571869 895004
1791238854.925990309 904732
1791238854.981277139 903224
1791238855.036318495 903224
1791238855.091230083 902184
1791238855.146414376 902184
1791238855.201624139 901656
1791238855.257017581 900884
1791238855.312499497 900884
1791238855.367255439 899348
1791238855.422579946 898832
1791238855.477352663 898832
1791238855.532517858 910864
1791238855.587195960 923920
1791238855.642422979 942608
1791238855.697513330 971024
1791238855.752176600 999696
1791238855.807233329 1019408
1791238855.862260824 985484
1791238855.917343453 930468
1791238855.972262473 930468
1791238856.027427848 930468
1791238856.082725659 930468
1791238856.137989599 925344
1791238856.193068627 866244
1791238856.248001814 643356
1791238856.303058839 599396
1791238856.357809428 599396
1791238856.412563742 599396
1791238856.467770895 599396
1791238856.523151473 599396
1791238856.578326407 599396
1791238856.633998298 599396
1791238856.689327698 599396
1791238856.744488581 599396
1791238856.799458884 599396
1791238856.854632807 599396
1791238856.909418069 599396
1791238856.964620825 625252
1791238857.019776050 660580
1791238857.075288249 668516
1791238857.130538121 676964
1791238857.185763005 683876
1791238857.241217359 694884
1791238857.296311023 702052
1791238857.351457448 708964
1791238857.407132998 716388
1791238857.462434880 740452
1791238857.517734398 725244
1791238857.572790605 733180
1791238857.628474087 777468
1791238857.683981282 780284
1791238857.739349434 659912
1791238857.794616432 456024
1791238857.849805953 53596
1791238857.905174185 73564
1791238857.960330144 73564
1791238858.015223804 73564
1791238858.070280212 73564
1791238858.125440959 78684
1791238858.180559131 94812
1791238858.235521876 99932
1791238858.290642291 108124
1791238858.345720452 136284
1791238858.400869390 144220
1791238858.455984187 152668
1791238858.510994114 152668
1791238858.566252960 159068
1791238858.621330380 164188
1791238858.676503535 171356
1791238858.731661518 182876
1791238858.786966454 222812
1791238858.842213552 222812
1791238858.897161404 243548
1791238858.951780236 243804
1791238859.007139445 258908
1791238859.062123993 273244
1791238859.117262185 280412
1791238859.172404644 280412
1791238859.227647405 280412
1791238859.282943298 280412
1791238859.338299872 280412
1791238859.393635275 291164
1791238859.448759035 295260
1791238859.504042999 297820
1791238859.558897450 304988
1791238859.614688195 309340
1791238859.670377557 319836
1791238859.725593067 324188
1791238859.780860556 330844
1791238859.836478489 343860
1791238859.891852950 367180
1791238859.947332613 401228
1791238860.002845736 401228
1791238860.058370546 401228
1791238860.114022531 419404
1791238860.169383512 430516
1791238860.225036789 437684
1791238860.280558084 440500
1791238860.335881328 445364
1791238860.391370575 471220
1791238860.446600086 484276
1791238860.501661421 494516
1791238860.556943773 494516
1791238860.612346018 494516
1791238860.667774091 494516
1791238860.723075692 494516
1791238860.778654776 494516
1791238860.834105394 494516
1791238860.889438082 494516
1791238860.944627843 487812
1791238860.999847629 487812
1791238861.055454244 487812
1791238861.110811881 487812
1791238861.166129496 487812
1791238861.221509797 498564
1791238861.276928356 512132
1791238861.332361898 512388
1791238861.388010948 514948
1791238861.443455767 519300
1791238861.498302526 520324
1791238861.553683137 521604
1791238861.609094275 524932
1791238861.664516269 528516
1791238861.719885383 532100
1791238861.775480090 535684
1791238861.830898539 539268
1791238861.886401877 544624
1791238861.941683568 548208
1791238861.996880500 561520
1791238862.052249984 587120
1791238862.107670486 604272
1791238862.163122867 608716
1791238862.218607356 613248
1791238862.273719819 622976
1791238862.329104597 622976
1791238862.384489164 622976
1791238862.440439253 622976
1791238862.495903361 622976
1791238862.550978117 657024
1791238862.605856624 667372
1791238862.661096431 668396
1791238862.716428158 677100
1791238862.772093362 682220
1791238862.827746048 682220
1791238862.882942559 682220
1791238862.937967729 689644
1791238862.993117198 689644
1791238863.047810113 689644
1791238863.103275984 689644
1791238863.158606269 689644
1791238863.213924365 689644
1791238863.268975514 689644
1791238863.323847031 689644
1791238863.379537704 695532
1791238863.435129317 722412
1791238863.490735161 749036
1791238863.545841815 748140
1791238863.601294076 748140
1791238863.656604600 746092
1791238863.712014606 746092
1791238863.767714413 740972
1791238863.823289681 738412
1791238863.878979553 738412
1791238863.934468349 732624
1791238863.989988783 728680
1791238864.045554186 726364
1791238864.101047249 724160
1791238864.156305093 724160
1791238864.211583329 731532
1791238864.267025864 737752
1791238864.322459096 741036
1791238864.378307239 739500
1791238864.433631644 739500
1791238864.489086669 739500
1791238864.544136226 739500
1791238864.599278044 739500
1791238864.654671916 739500
1791238864.710090545 739500
1791238864.765333406 745388
1791238864.820267848 746156
1791238864.875066834 746924
1791238864.929869746 747692
1791238864.985603004 748460
1791238865.040881851 749228
1791238865.096207679 749996
1791238865.151050371 750764
1791238865.206366013 756652
1791238865.261608545 752256
1791238865.316917948 760448
1791238865.372292640 785280
1791238865.427960048 810624
1791238865.483591912 838528
1791238865.538743194 849280
1791238865.593811470 822144
1791238865.649895662 834940
1791238865.705542098 843204
1791238865.760808335 870852
1791238865.816309510 870852
1791238865.871570690 870852
1791238865.926982829 870852
1791238865.982533359 882884
1791238866.038111531 909764
1791238866.093751657 911140
1791238866.149117536 919844
1791238866.204249850 914952
1791238866.259878809 914952
1791238866.315359343 914952
1791238866.370718922 914952
1791238866.426125463 914952
1791238866.481622451 914952
1791238866.536989862 914952
1791238866.591886026 914952
1791238866.647288481 914952
1791238866.702329435 914952
1791238866.757591005 914952
1791238866.812728196 914952
1791238866.867794649 916488
1791238866.923285718 935688
1791238866.978156814 922660
1791238867.033776429 922660
1791238867.089259807 922660
1791238867.144936679 922660
1791238867.200581503 922660
1791238867.255810113 922660
1791238867.311434034 922660
1791238867.367337301 918364
1791238867.422729310 918364
1791238867.477979984 926044
1791238867.532890970 938412
1791238867.587505425 941096
1791238867.642392445 941096
1791238867.697477036 941096
1791238867.752647307 941096
1791238867.808049270 941096
1791238867.863510965 942632
1791238867.919233116 943144
1791238867.974663403 943400
1791238868.030055272 943912
1791238868.085662007 947240
1791238868.141076010 947496
1791238868.196241764 948008
1791238868.251433057 948264
1791238868.306668998 948520
1791238868.362622582 949032
1791238868.417795326 949288
1791238868.473562747 949032
1791238868.528960855 956968
1791238868.584349668 968744
1791238868.639608635 980520
1791238868.695178824 992040
1791238868.750781674 1003816
1791238868.806418806 1009192
1791238868.861796172 938048
1791238868.917364309 921564
1791238868.972994040 921564
1791238869.028575036 926924
1791238869.084367134 926924
1791238869.139968031 926924
1791238869.195224172 927436
1791238869.250598915 927436
1791238869.305993918 927436
1791238869.361856112 927436
1791238869.417493345 927436
1791238869.472856229 927436
1791238869.528286957 927436
1791238869.583848053 933068
1791238869.638988288 936036
1791238869.694201174 936036
1791238869.749297953 934492
1791238869.804734530 933464
1791238869.860180320 933464
1791238869.915354507 931884
1791238869.970687556 930828
1791238870.025833450 929796
1791238870.081305030 927492
1791238870.136263599 927492
1791238870.191207045 933124
1791238870.246613656 946692
1791238870.302004362 960004
1791238870.357844764 973572
1791238870.413347150 1000452
1791238870.468190544 1026820
1791238870.523449039 1000452
1791238870.578507871 945964
1791238870.633258102 943656
1791238870.688536137 943656
1791238870.743564793 940316
1791238870.798966226 940316
1791238870.854035043 917340
1791238870.909391938 786172
1791238870.964624564 730724
1791238871.019742715 730724
1791238871.074805142 730724
1791238871.130302902 730724
1791238871.185598203 730724
1791238871.240695984 730724
1791238871.296011236 730724
1791238871.351457948 730724
1791238871.407245208 730724
1791238871.462317060 722364
1791238871.517843343 722364
1791238871.573117202 725180
1791238871.628839493 778428
1791238871.684151820 783804
1791238871.739383575 795324
1791238871.794810777 800548
1791238871.850133451 806948
1791238871.905633103 815392
1791238871.961043510 822560
1791238872.016729756 829728
1791238872.072293316 836896
1791238872.127676632 879136
1791238872.182886102 845352
1791238872.238220313 845352
1791238872.293604240 845352
1791238872.349145515 745188
1791238872.404745331 627552
1791238872.460415373 103052
1791238872.515705105 74116
1791238872.571214653 74116
1791238872.626344012 74116
1791238872.681234357 74116
1791238872.736545112 74116
1791238872.791876909 74116
1791238872.847142986 74116
1791238872.902029094 74116
1791238872.957279608 74116
1791238873.012459894 74116
1791238873.067982311 74116
1791238873.122805043 74116
1791238873.177952780 74116
1791238873.232903197 74116
1791238873.287855336 74116
1791238873.343210568 74116
1791238873.398810504 74116
1791238873.453869756 74116
1791238873.508881115 74116
1791238873.564492227 74116
1791238873.619357754 74116
1791238873.674924860 74116
1791238873.730240242 74116
1791238873.785248416 74116
1791238873.840447701 74116
1791238873.895110340 74116
1791238873.950643012 74116
1791238874.006043033 74116
1791238874.061154375 74116
1791238874.116771797 74116
1791238874.171798730 74116
1791238874.226761164 74116
1791238874.281590837 74116
1791238874.336513221 74116
1791238874.391873050 74116
1791238874.447265810 74116
1791238874.502785703 74116
1791238874.558254409 74116
1791238874.613394704 74116
1791238874.668770068 74116
1791238874.723648545 74116
  • Evidence: RSS samples at 50 ms, base (local file: ~/.no-mistakes/evidence/01M471W8JV2JZ8MZPH16CM73JC/rss-a-base.log)
Evidence: memory_limit_tests on jemalloc build
test a_conditional_delete_after_the_commit_began_is_refused_as_resource_exhausted ... ok
test a_cross_product_in_a_session_rule_is_refused_with_a_code ... ok
test a_cross_product_is_estimated_with_the_rows_its_filters_keep ... ok
test a_cross_product_past_its_deadline_is_stopped_while_others_answer ... ok
test a_cross_product_past_the_memory_limit_is_stopped_while_it_forms_pairs ... ok
test a_large_cross_product_is_refused_before_it_runs_on_shipped_defaults ... ok
test a_proof_after_a_commit_is_refused_as_resource_exhausted ... ok
test a_query_under_the_limit_is_unaffected ... ok
test a_runaway_query_after_a_commit_in_the_same_program_is_still_refused ... ok
test a_runaway_query_is_refused_instead_of_growing_the_server ... ok
test a_write_past_the_graph_budget_is_refused_and_deletes_still_work ... ok
test recursion_without_a_bound_stops_at_the_iteration_ceiling ... ok

test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.59s
Evidence: Driver script and IQL programs
#!/usr/bin/env bash
# usage: run.sh <target-dir> <label> <port> <limit-bytes>
T=$1; L=$2; P=$3; LIM=$4
D=/tmp/nm-01M471/mem/$L; rm -rf $D; mkdir -p $D
cat > $D/engine.toml <<TOML
[storage]
data_dir = "$D/data"
[storage.performance]
max_query_memory_bytes = $LIM
query_timeout_ms = 0
[http]
enabled = true
host = "127.0.0.1"
port = $P
[http.auth]
bootstrap_admin_password = "pw-test-123456"
credentials_file = "$D/credentials.toml"
[http.rate_limit]
ws_max_messages_per_sec = 0
per_ip_max_rps = 0
[logging]
level = "warn"
TOML
systemd-run --user --scope -p MemoryMax=16G -p MemorySwapMax=0 --unit=nm-$L $T/release/inputlayer-server --config $D/engine.toml > $D/server.log 2>&1 &
sleep 0.5; PID=$(pgrep -f "^$T/release/inputlayer-server --config $D/engine.toml")
for i in $(seq 100); do [ -s $D/credentials.toml ] && curl -sf http://127.0.0.1:$P/live >/dev/null && break; sleep 0.2; done
KEY=$(sed -n 's/^api_key *= *"\(.*\)"/\1/p' $D/credentials.toml)
rss(){ awk '/VmRSS/{print $2}' /proc/$PID/status; }
peak=0
( while kill -0 $PID 2>/dev/null; do r=$(awk '/VmRSS/{print $2}' /proc/$PID/status); echo "$(date +%s.%N) $r"; sleep 0.05; done ) > $D/rss.log &
SAMP=$!
C="$T/release/inputlayer-client --server http://127.0.0.1:$P --api-key $KEY"
$C --script /tmp/nm-01M471/mem/setup.iql > $D/setup.out 2>&1
echo "rss_after_setup_kb $(rss)"
start=$(date +%s.%N)
$C --script /tmp/nm-01M471/mem/${SCRIPT:-closure.iql} > $D/closure.out 2>&1
end=$(date +%s.%N)
echo "closure_secs $(echo "$end - $start" | bc)"
echo "rss_right_after_closure_kb $(rss)"
sleep 2
echo "rss_2s_after_closure_kb $(rss)"
$C --script /tmp/nm-01M471/mem/small.iql > $D/small.out 2>&1
kill $SAMP; kill $PID; wait $PID 2>/dev/null
echo "peak_rss_kb $(awk '{print $2}' $D/rss.log | sort -n | tail -1)"
echo "--- closure reply (head) ---"; head -c 600 $D/closure.out; echo
echo "--- small reply (head) ---"; head -c 400 $D/small.out; echo
- Outcome: 🔧 2 issues found → no changes applied ✅ across 2 runs (20m48s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ℹ️ src/execution/memory.rs:56 - The new doc comment says jemalloc returns freed memory 'after about ten seconds unused'. Without background_thread (not enabled here: there is no malloc_conf/_rjem_malloc_conf), jemalloc only applies decay when the same arena allocates or frees again. If a burst of threads goes quiet, their arenas can keep dirty pages until the next release_freed_memory() purge, which only runs after a query with a peak above 64 MiB. RSS stays bounded, so this does not undo the Server memory grows under sustained load: RSS 251 -> 1,012 MiB in a 30-minute soak (glibc arena retention) #376 fix, but the comment overstates how promptly memory is returned. If idle-RSS return matters, set background_thread:true in the malloc conf, or reword the comment.
🔧 **Test** - 2 issues found → no changes applied ✅
  • ⚠️ No live evidence yet for Server memory grows under sustained load: RSS 251 -> 1,012 MiB in a 30-minute soak (glibc arena retention) #376. The fix claims resident memory stays bounded under sustained load. No soak and no runaway-query test ran against a running server, because the result was required while the release builds were still compiling. To get the evidence, re-run this step and allow the builds to finish. Then run scripts/soak.sh --secs 600 --set MAX_RSS_GROWTH_PCT=25 on the change and on base efa87aa, and run /tmp/nm-01M471/mem/run.sh on both builds.
  • ⚠️ live validation verdict: inconclusive (0 of 4 scenarios were driven live against the product); untested: Under a shortened sustained soak, the server's resident memory grows less than 25% over the second half of the run on the change, compared with the glibc-based base, After a runaway closure query peaks above 64 MiB, resident memory drops back within seconds (jemalloc arena purge) and small queries still work on the same server, With max_query_memory_bytes = 32 MiB, a runaway query is refused with resource_exhausted and the connection stays usable when jemalloc is the allocator, A slow or stalled soak consumer that is disconnected while it subscribes is counted as an allowed disconnect, not reported as a soak failure
  • Live validation: ⚠️ inconclusive - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Under a shortened sustained soak, the server's resident memory grows less than 25% over the second half of the run on the change, compared with the glibc-based base ⏸️ untested no The release builds of the change and base (cargo test --release --all-features --test differential_oracle --no-run, in /tmp target dirs) were still compiling when the step was forced to return. Nothin…
After a runaway closure query peaks above 64 MiB, resident memory drops back within seconds (jemalloc arena purge) and small queries still work on the same server ⏸️ untested no The run needs the inputlayer-server and inputlayer-client release binaries, which were still being built when the result was required.
With max_query_memory_bytes = 32 MiB, a runaway query is refused with resource_exhausted and the connection stays usable when jemalloc is the allocator ⏸️ untested no Same blocker: the release build had not finished.
A slow or stalled soak consumer that is disconnected while it subscribes is counted as an allowed disconnect, not reported as a soak failure ⏸️ untested no The soak test binary was still compiling when the result was required.
  • CARGO_TARGET_DIR=/tmp/nm-01M471/target-head cargo test --release --all-features --test differential_oracle --no-run (release build of the change; still compiling when the result was required)
  • CARGO_TARGET_DIR=/tmp/nm-01M471/target-base cargo test --release --all-features --test differential_oracle --no-run on a copy of base commit efa87aa5 (still compiling)
  • Prepared /tmp/nm-01M471/mem/run.sh: starts the real inputlayer-server with an isolated config, data directory and credentials; runs the 1500-node runaway closure through inputlayer-client; samples VmRSS every 50 ms (never executed)

🔧 No changes applied.
✅ Re-checked - no issues remain.

  • Live validation: ✅ go - 4 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Under a sustained soak, server resident memory stays bounded on the change, unlike the glibc base that grew from 251 to 1,012 MiB ✅ pass live Operator-provided benchmark-host run (sam-dev-benchmarks, built from e2a0882e, whose engine is the same as this branch): 30-minute sustained soak passed with 0 failures, 574,594 commits at 319/s, RSS…
After a runaway closure query peaks above 64 MiB, resident memory falls back within seconds and small queries still work on the same server ✅ pass live check-a-runaway-closure.txt and rss-summary.txt: on the change, a peak of 1,003 MiB fell below 25% of the peak in 1.99 s and ended at 72 MiB, and ?edge(0, Y) returned 2 rows. Base: 1,121 MiB to 96 M…
With max_query_memory_bytes = 32 MiB, a runaway query is refused with resource_exhausted and the connection stays usable under jemalloc ✅ pass live check-b-query-memory-limit.txt: both builds answered 'Request exceeded the per-query memory limit ... nothing was applied', then .session clear and ?edge(0, Y) returned 2 rows on the same connecti…
A slow or stalled soak consumer that is closed while it subscribes counts as an allowed disconnect, not a soak failure ✅ pass live Operator-provided benchmark-host soak: ws_slow_subscriber_disconnected 829 and slow consumers closed 807 times, with 0 soak failures
  • Checked that the base scratch source (src, Cargo.toml) is identical to git archive efa87aa5 and that the change's source is clean at ac4be1ee; the change's server binary links jemalloc and base does not (strings | grep jemalloc)
  • SCRIPT=closure.iql run2.sh target-head a2-head 18861 0 and the same for target-base: each server under systemd-run --user --scope -p MemoryMax=16G -p MemorySwapMax=0, a runaway transitive-closure query over the loaded edge graph, VmRSS sampled every 50 ms, then a small ?edge(0, Y) query on the same server
  • SCRIPT=closure_then_small.iql run2.sh target-{head,base} b2-* 1887x 33554432: with max_query_memory_bytes = 32 MiB, the runaway rule and query are refused, then .session clear and ?edge(0, Y) run on the same CLI connection
  • CARGO_BUILD_JOBS=4 cargo test --release --all-features --test memory_limit_tests (the change, jemalloc global allocator): /ws end-to-end checks of code == resource_exhausted and that the connection stays usable
  • Cited the operator-provided 30-minute sustained soak on sam-dev-benchmarks (built from e2a0882e) for the soak and slow-consumer harness scenarios, as the operator decided
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

jsam added 2 commits October 5, 2026 22:10
… as it may be once subscribed

A slow or stalled consumer reads one frame at a time, also while it opens
its session: deltas for its first queries can queue ahead of the reply to
the next subscribe, and the engine's send timeout then closes it. The soak
allowed that close once subscribed but failed on it during the open; on
the benchmark host the sustained soak against the jemalloc server (#376)
failed on it 48 s in, with 40 send timeouts logged.
@jsam
jsam force-pushed the fm/fix-mem-growth branch from b13d663 to ac4be1e Compare October 5, 2026 22:35
@jsam jsam changed the title fix(server): use jemalloc as the global allocator so resident memory stays bounded under sustained load (#376) fix(execution): use jemalloc as the global allocator so server memory stays bounded under sustained load Oct 5, 2026
@jsam
jsam marked this pull request as ready for review October 5, 2026 22:39
@jsam
jsam merged commit a649cd9 into main Oct 5, 2026
24 checks passed
@jsam
jsam deleted the fm/fix-mem-growth branch October 5, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant