mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
docs: consolidate cache guidance and keep generated reports local
This commit is contained in:
1 parent
dd668c1f4b
commit
0efa1590c9
16 files changed
+201
-18469
No files matched your search
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"measuredAt": "2026-11-02T11:05:58.163Z",
|
||||
"scope": "Synthetic metadata-only scale probe. Dummy blob rows have no payload files; excludes directory scanning and disk reads for those rows. Real reads use one verified blob. Eviction probe uses real 64 KiB files.",
|
||||
"node": "v24.14.1",
|
||||
"cardinality": [
|
||||
{
|
||||
"seedBlobs": 0,
|
||||
"seedAliases": 0,
|
||||
"seedDecisions": 0,
|
||||
"seedHistory": 0,
|
||||
"adminStats": {
|
||||
"p50Ms": 0.32291899999972884,
|
||||
"p95Ms": 0.47828900000013164,
|
||||
"maxMs": 0.49711900000011155
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 2.9400040000000445,
|
||||
"p95Ms": 4.2662209999998595,
|
||||
"maxMs": 4.463114000000132
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 0.4946559999998499,
|
||||
"p95Ms": 0.900854999999865,
|
||||
"maxMs": 16.506318000000192
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 43.615020000000186,
|
||||
"p95Ms": 83.75168699999995,
|
||||
"maxMs": 103.38539700000001
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 10000,
|
||||
"seedAliases": 20000,
|
||||
"seedDecisions": 10000,
|
||||
"seedHistory": 10000,
|
||||
"adminStats": {
|
||||
"p50Ms": 0.3126299999994444,
|
||||
"p95Ms": 0.4548949999998513,
|
||||
"maxMs": 0.6803079999999682
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 2.6403629999995246,
|
||||
"p95Ms": 14.954797000000326,
|
||||
"maxMs": 19.31438099999923
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 0.4195850000005521,
|
||||
"p95Ms": 0.5379259999999704,
|
||||
"maxMs": 0.6729980000000069
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 39.785445999999865,
|
||||
"p95Ms": 53.938020999999935,
|
||||
"maxMs": 58.02874900000006
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 100000,
|
||||
"seedAliases": 200000,
|
||||
"seedDecisions": 100000,
|
||||
"seedHistory": 100000,
|
||||
"adminStats": {
|
||||
"p50Ms": 0.3238130000027013,
|
||||
"p95Ms": 0.4950620000017807,
|
||||
"maxMs": 0.649769000003289
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 2.7466110000023036,
|
||||
"p95Ms": 6.374782999999297,
|
||||
"maxMs": 15.351889999998093
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 0.7600549999988289,
|
||||
"p95Ms": 1.1067369999946095,
|
||||
"maxMs": 1.1147449999989476
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 44.32314000000042,
|
||||
"p95Ms": 68.3110549999983,
|
||||
"maxMs": 91.21001899999828
|
||||
}
|
||||
}
|
||||
],
|
||||
"eviction": {
|
||||
"requests": 300,
|
||||
"distinctObjects": 100,
|
||||
"upstreamFills": 300,
|
||||
"hitRate": 0,
|
||||
"elapsedMs": 13436.223987999998,
|
||||
"p50Ms": 41.134181999994325,
|
||||
"p95Ms": 57.91661600000225,
|
||||
"peakAllocated": 3997696,
|
||||
"final": {
|
||||
"blobs": 60,
|
||||
"originalBytes": 3932160,
|
||||
"storedBytes": 3932160,
|
||||
"allocatedBytes": 3932160,
|
||||
"activeReaders": 0,
|
||||
"decisions": 0,
|
||||
"reservedBytes": 0,
|
||||
"budgetBytes": 4194304,
|
||||
"maxObjectBytes": 65536,
|
||||
"oldestAccess": 1793617555801
|
||||
}
|
||||
},
|
||||
"assertions": "passed"
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"measuredAt": "2026-11-02T10:42:36.314Z",
|
||||
"scope": "Synthetic metadata-only scale probe. Dummy blob rows have no payload files; excludes directory scanning and disk reads for those rows. Real reads use one verified blob. Eviction probe uses real 64 KiB files.",
|
||||
"node": "v24.14.1",
|
||||
"cardinality": [
|
||||
{
|
||||
"seedBlobs": 0,
|
||||
"seedAliases": 0,
|
||||
"seedDecisions": 0,
|
||||
"seedHistory": 0,
|
||||
"adminStats": {
|
||||
"p50Ms": 0.5495260000002418,
|
||||
"p95Ms": 0.8194220000000314,
|
||||
"maxMs": 0.8764419999997699
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 22.106009000000086,
|
||||
"p95Ms": 32.67359299999998,
|
||||
"maxMs": 38.92065599999978
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 6.600801999999931,
|
||||
"p95Ms": 12.472383000000264,
|
||||
"maxMs": 15.8033989999999
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 71.12627699999939,
|
||||
"p95Ms": 98.24754799999982,
|
||||
"maxMs": 100.35789100000011
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 10000,
|
||||
"seedAliases": 20000,
|
||||
"seedDecisions": 10000,
|
||||
"seedHistory": 10000,
|
||||
"adminStats": {
|
||||
"p50Ms": 6.904306000000361,
|
||||
"p95Ms": 9.677666999999929,
|
||||
"maxMs": 12.638716999999815
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 22.83701199999996,
|
||||
"p95Ms": 47.79449499999828,
|
||||
"maxMs": 102.36107600000014
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 8.062501999999768,
|
||||
"p95Ms": 13.995523999999932,
|
||||
"maxMs": 14.909832000001188
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 75.03789299999971,
|
||||
"p95Ms": 117.16210499999943,
|
||||
"maxMs": 143.80038499999955
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 100000,
|
||||
"seedAliases": 200000,
|
||||
"seedDecisions": 100000,
|
||||
"seedHistory": 100000,
|
||||
"adminStats": {
|
||||
"p50Ms": 66.83604900000137,
|
||||
"p95Ms": 78.69937500000015,
|
||||
"maxMs": 87.98320400000011
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 26.310491000000184,
|
||||
"p95Ms": 82.98941600000035,
|
||||
"maxMs": 112.1549300000006
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 22.948387000000366,
|
||||
"p95Ms": 45.47333599999911,
|
||||
"maxMs": 56.50094800000079
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 136.3280279999999,
|
||||
"p95Ms": 214.8330500000011,
|
||||
"maxMs": 312.4176129999978
|
||||
}
|
||||
}
|
||||
],
|
||||
"eviction": {
|
||||
"requests": 300,
|
||||
"distinctObjects": 100,
|
||||
"upstreamFills": 300,
|
||||
"hitRate": 0,
|
||||
"elapsedMs": 24658.882357999995,
|
||||
"p50Ms": 74.17433299999539,
|
||||
"p95Ms": 107.83662400000321,
|
||||
"peakAllocated": 3997696,
|
||||
"final": {
|
||||
"blobs": 60,
|
||||
"originalBytes": 3932160,
|
||||
"storedBytes": 3932160,
|
||||
"allocatedBytes": 3932160,
|
||||
"oldestAccess": 1793616151486,
|
||||
"budgetBytes": 4194304,
|
||||
"reservedBytes": 0,
|
||||
"maxObjectBytes": 65536,
|
||||
"activeReaders": 0,
|
||||
"decisions": 0
|
||||
}
|
||||
},
|
||||
"assertions": "passed"
|
||||
}
|
||||
@@ -1,497 +0,0 @@
|
||||
{
|
||||
"measuredAt": "2026-11-02T10:48:59.787Z",
|
||||
"environment": {
|
||||
"execution": "compiled JavaScript",
|
||||
"node": "v24.14.1",
|
||||
"platform": "linux",
|
||||
"arch": "x64",
|
||||
"cpu": "Intel Xeon E312xx (Sandy Bridge, IBRS update)",
|
||||
"logicalCpus": 12,
|
||||
"totalMemoryGiB": 35.22977066040039,
|
||||
"loadAverage": [
|
||||
4.84,
|
||||
4.64,
|
||||
4.01
|
||||
]
|
||||
},
|
||||
"methodology": {
|
||||
"scope": "Local loopback HTTP, deterministic synthetic content, isolated process per scenario; no production traffic",
|
||||
"upstreamDelayMs": 20,
|
||||
"rawSourceBaseline": "Raw local file; anonymization and gzip repeated every request; no transformed-result cache. Not a complete legacy deployment comparison.",
|
||||
"measurements": "Cold request then 3 warmups, 2 batches each at concurrency 1 (16 requests) and 8 (32 requests). CPU and RSS include server, loopback client, hashing and Node runtime; worker-thread CPU included. First cold request also includes worker startup when applicable.",
|
||||
"limitations": "Warm OS page cache; no TLS, proxy, GitHub bandwidth, database auth or real-world RTT. Small sample p95 is descriptive, not a capacity SLA. Fresh metadata indexes; not a full-size index test.",
|
||||
"legacyComparison": "Existing large-file transformedFile cache enabled, isolated TMPDIR, local source file, no Redis coordination or database authorization."
|
||||
},
|
||||
"scenarios": [
|
||||
{
|
||||
"size": 2097152,
|
||||
"changed": false,
|
||||
"mode": "legacy-transform",
|
||||
"encoding": "gzip",
|
||||
"binary": false,
|
||||
"cold": {
|
||||
"ms": 3637.6617370000004,
|
||||
"ttfb": 3425.310189,
|
||||
"bytes": 799931,
|
||||
"wallMs": 3672.4500099999996,
|
||||
"cpuMs": 4809.962
|
||||
},
|
||||
"batches": [
|
||||
{
|
||||
"concurrency": 1,
|
||||
"repeat": 0,
|
||||
"requests": 16,
|
||||
"elapsedMs": 4325.215086,
|
||||
"requestsPerSecond": 3.6992379990047968,
|
||||
"p50Ms": 259.56264199999896,
|
||||
"p95Ms": 326.0954209999991,
|
||||
"maxMs": 326.0954209999991,
|
||||
"ttfbP95Ms": 100.11303399999997,
|
||||
"cpuMs": 7363.262,
|
||||
"cpuMsPerRequest": 460.203875,
|
||||
"peakRssMiB": 269.8828125,
|
||||
"eventLoopP95Ms": 11.419647,
|
||||
"wireBytes": 12798896,
|
||||
"latenciesMs": [
|
||||
271.195162,
|
||||
326.0954209999991,
|
||||
325.21412000000055,
|
||||
268.0655480000005,
|
||||
254.55466100000012,
|
||||
262.5113799999999,
|
||||
254.16493199999968,
|
||||
256.40336600000046,
|
||||
270.1401279999991,
|
||||
254.43623800000023,
|
||||
300.7399460000015,
|
||||
260.95136600000114,
|
||||
253.6488389999995,
|
||||
259.56264199999896,
|
||||
254.29303199999958,
|
||||
246.70169999999962
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 1,
|
||||
"repeat": 1,
|
||||
"requests": 16,
|
||||
"elapsedMs": 4144.421229,
|
||||
"requestsPerSecond": 3.8606114378630894,
|
||||
"p50Ms": 257.6290540000009,
|
||||
"p95Ms": 284.40178000000014,
|
||||
"maxMs": 284.40178000000014,
|
||||
"ttfbP95Ms": 99.43109800000093,
|
||||
"cpuMs": 7050.23,
|
||||
"cpuMsPerRequest": 440.639375,
|
||||
"peakRssMiB": 270.28515625,
|
||||
"eventLoopP95Ms": 11.386879,
|
||||
"wireBytes": 12798896,
|
||||
"latenciesMs": [
|
||||
255.06874499999867,
|
||||
245.9648269999998,
|
||||
263.4925280000007,
|
||||
240.60825599999953,
|
||||
265.1590239999987,
|
||||
264.77967999999964,
|
||||
243.70354000000043,
|
||||
269.05731899999955,
|
||||
257.6290540000009,
|
||||
255.93209899999965,
|
||||
264.11589300000014,
|
||||
276.2427490000009,
|
||||
257.6929230000005,
|
||||
284.40178000000014,
|
||||
255.67801800000052,
|
||||
239.9359570000015
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 8,
|
||||
"repeat": 0,
|
||||
"requests": 32,
|
||||
"elapsedMs": 2457.372474,
|
||||
"requestsPerSecond": 13.022038921072411,
|
||||
"p50Ms": 627.6892860000007,
|
||||
"p95Ms": 675.1984000000011,
|
||||
"maxMs": 676.5109240000002,
|
||||
"ttfbP95Ms": 362.1158489999998,
|
||||
"cpuMs": 9279.507,
|
||||
"cpuMsPerRequest": 289.98459375,
|
||||
"peakRssMiB": 257.109375,
|
||||
"eventLoopP95Ms": 14.229503,
|
||||
"wireBytes": 25597792,
|
||||
"latenciesMs": [
|
||||
638.7337129999996,
|
||||
644.2589910000006,
|
||||
653.9658299999992,
|
||||
660.062434999998,
|
||||
653.491895000001,
|
||||
667.5545409999995,
|
||||
675.1984000000011,
|
||||
676.5109240000002,
|
||||
518.4652159999969,
|
||||
508.24069299999974,
|
||||
529.0743550000007,
|
||||
519.2867880000013,
|
||||
517.0170130000006,
|
||||
535.1560919999974,
|
||||
534.1093989999972,
|
||||
539.1497820000004,
|
||||
619.183696,
|
||||
632.2522540000027,
|
||||
627.6892860000007,
|
||||
645.0611839999983,
|
||||
651.0646340000021,
|
||||
634.4353510000001,
|
||||
625.0313089999981,
|
||||
635.0648269999983,
|
||||
653.2990800000007,
|
||||
641.2500100000034,
|
||||
620.1606979999997,
|
||||
619.6126290000029,
|
||||
621.0784349999994,
|
||||
635.4328630000018,
|
||||
609.3666200000007,
|
||||
604.615855
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 8,
|
||||
"repeat": 1,
|
||||
"requests": 32,
|
||||
"elapsedMs": 2332.6840220000013,
|
||||
"requestsPerSecond": 13.718103137073737,
|
||||
"p50Ms": 591.6440280000024,
|
||||
"p95Ms": 635.7273109999987,
|
||||
"maxMs": 641.7715180000014,
|
||||
"ttfbP95Ms": 325.4839319999992,
|
||||
"cpuMs": 8533.531,
|
||||
"cpuMsPerRequest": 266.67284375,
|
||||
"peakRssMiB": 274.7109375,
|
||||
"eventLoopP95Ms": 14.196735,
|
||||
"wireBytes": 25597792,
|
||||
"latenciesMs": [
|
||||
597.2558779999999,
|
||||
606.2361659999988,
|
||||
615.4332890000005,
|
||||
619.6175079999994,
|
||||
623.0158960000008,
|
||||
626.0080349999989,
|
||||
626.6588200000006,
|
||||
626.664377000001,
|
||||
502.19446700000117,
|
||||
489.31906900000104,
|
||||
500.0022510000017,
|
||||
517.2302520000012,
|
||||
523.0413550000012,
|
||||
527.0690040000009,
|
||||
527.3038940000006,
|
||||
531.9332829999985,
|
||||
578.1515760000002,
|
||||
617.7991489999986,
|
||||
576.213284999998,
|
||||
635.7273109999987,
|
||||
591.6440280000024,
|
||||
641.7715180000014,
|
||||
588.0470649999988,
|
||||
617.4792789999992,
|
||||
592.6901799999978,
|
||||
596.9206689999992,
|
||||
576.3831680000003,
|
||||
576.4393070000006,
|
||||
568.0410200000006,
|
||||
592.3916649999992,
|
||||
599.7627519999987,
|
||||
584.0048639999986
|
||||
]
|
||||
}
|
||||
],
|
||||
"upstreamFills": 1,
|
||||
"source": null,
|
||||
"results": null,
|
||||
"metrics": [
|
||||
{
|
||||
"name": "inspected_unchanged",
|
||||
"traffic": "background",
|
||||
"count": 100,
|
||||
"bytes": 209715200,
|
||||
"ms": 4554.967507000029,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 32,
|
||||
"b3": 67,
|
||||
"b4": 0,
|
||||
"b5": 1,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "legacy_result_hit",
|
||||
"traffic": "background",
|
||||
"count": 99,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 99,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "legacy_result_miss",
|
||||
"traffic": "background",
|
||||
"count": 1,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
}
|
||||
],
|
||||
"wireBytesPerResponse": 799931,
|
||||
"uncompressedBytes": 2097152,
|
||||
"verifiedResponses": 100
|
||||
},
|
||||
{
|
||||
"size": 2097152,
|
||||
"changed": true,
|
||||
"mode": "legacy-transform",
|
||||
"encoding": "gzip",
|
||||
"binary": false,
|
||||
"cold": {
|
||||
"ms": 2903.1252619999996,
|
||||
"ttfb": 2710.632705,
|
||||
"bytes": 799783,
|
||||
"wallMs": 2938.953792,
|
||||
"cpuMs": 3776.116
|
||||
},
|
||||
"batches": [
|
||||
{
|
||||
"concurrency": 1,
|
||||
"repeat": 0,
|
||||
"requests": 16,
|
||||
"elapsedMs": 4094.466308000001,
|
||||
"requestsPerSecond": 3.9077131905416564,
|
||||
"p50Ms": 250.63896699999987,
|
||||
"p95Ms": 328.3509729999996,
|
||||
"maxMs": 328.3509729999996,
|
||||
"ttfbP95Ms": 139.6392849999993,
|
||||
"cpuMs": 5652.677,
|
||||
"cpuMsPerRequest": 353.2923125,
|
||||
"peakRssMiB": 335.65234375,
|
||||
"eventLoopP95Ms": 11.599871,
|
||||
"wireBytes": 12796528,
|
||||
"latenciesMs": [
|
||||
274.80920400000014,
|
||||
250.63896699999987,
|
||||
328.3509729999996,
|
||||
261.9780500000006,
|
||||
224.44531199999983,
|
||||
288.4866490000004,
|
||||
260.0317410000007,
|
||||
265.3711569999996,
|
||||
220.20456599999852,
|
||||
236.22282199999972,
|
||||
256.1077639999985,
|
||||
283.01616699999977,
|
||||
235.04550499999823,
|
||||
246.0147109999998,
|
||||
221.8804140000011,
|
||||
237.00552799999969
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 1,
|
||||
"repeat": 1,
|
||||
"requests": 16,
|
||||
"elapsedMs": 3646.5368070000004,
|
||||
"requestsPerSecond": 4.387724804884987,
|
||||
"p50Ms": 218.23768400000154,
|
||||
"p95Ms": 286.0494230000004,
|
||||
"maxMs": 286.0494230000004,
|
||||
"ttfbP95Ms": 137.9453310000008,
|
||||
"cpuMs": 5961.413,
|
||||
"cpuMsPerRequest": 372.5883125,
|
||||
"peakRssMiB": 336.703125,
|
||||
"eventLoopP95Ms": 13.033471,
|
||||
"wireBytes": 12796528,
|
||||
"latenciesMs": [
|
||||
203.70693100000062,
|
||||
211.7173640000001,
|
||||
252.71899200000007,
|
||||
286.0494230000004,
|
||||
211.1080320000001,
|
||||
274.02094000000034,
|
||||
212.45707100000072,
|
||||
181.00006699999904,
|
||||
206.20519800000147,
|
||||
234.44334700000036,
|
||||
247.34129100000064,
|
||||
221.80664199999956,
|
||||
194.29920999999922,
|
||||
232.47182499999872,
|
||||
218.23768400000154,
|
||||
254.94733899999846
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 8,
|
||||
"repeat": 0,
|
||||
"requests": 32,
|
||||
"elapsedMs": 2860.0330489999997,
|
||||
"requestsPerSecond": 11.188681896941256,
|
||||
"p50Ms": 674.8104320000002,
|
||||
"p95Ms": 937.1299240000008,
|
||||
"maxMs": 956.4731780000002,
|
||||
"ttfbP95Ms": 349.0807139999997,
|
||||
"cpuMs": 8294.185,
|
||||
"cpuMsPerRequest": 259.19328125,
|
||||
"peakRssMiB": 306.8125,
|
||||
"eventLoopP95Ms": 17.088511,
|
||||
"wireBytes": 25593056,
|
||||
"latenciesMs": [
|
||||
838.9425090000004,
|
||||
836.6894339999999,
|
||||
840.9874359999994,
|
||||
914.8391210000009,
|
||||
929.2231830000001,
|
||||
932.435884999999,
|
||||
937.1299240000008,
|
||||
956.4731780000002,
|
||||
609.6644930000002,
|
||||
624.2318410000007,
|
||||
635.5053589999989,
|
||||
565.2249200000006,
|
||||
555.5831100000014,
|
||||
544.6693990000003,
|
||||
574.0213219999987,
|
||||
577.7646199999999,
|
||||
662.6372410000004,
|
||||
674.8104320000002,
|
||||
673.4079709999987,
|
||||
651.1047060000001,
|
||||
651.0912209999988,
|
||||
671.7599570000002,
|
||||
700.2244200000005,
|
||||
673.7866299999987,
|
||||
716.5474200000026,
|
||||
688.9938089999996,
|
||||
682.0821550000001,
|
||||
701.2659249999997,
|
||||
688.1068889999988,
|
||||
664.9055890000018,
|
||||
677.3972719999983,
|
||||
690.5366940000022
|
||||
]
|
||||
},
|
||||
{
|
||||
"concurrency": 8,
|
||||
"repeat": 1,
|
||||
"requests": 32,
|
||||
"elapsedMs": 2979.963332000003,
|
||||
"requestsPerSecond": 10.738387166167978,
|
||||
"p50Ms": 715.5634050000008,
|
||||
"p95Ms": 839.5880639999996,
|
||||
"maxMs": 839.9379399999998,
|
||||
"ttfbP95Ms": 469.71283799999946,
|
||||
"cpuMs": 7910.049,
|
||||
"cpuMsPerRequest": 247.18903125,
|
||||
"peakRssMiB": 308.02734375,
|
||||
"eventLoopP95Ms": 19.464191,
|
||||
"wireBytes": 25593056,
|
||||
"latenciesMs": [
|
||||
675.5995089999997,
|
||||
677.2758930000018,
|
||||
682.5500949999987,
|
||||
695.3682000000008,
|
||||
695.637243000001,
|
||||
707.3496059999998,
|
||||
708.2368339999994,
|
||||
715.5634050000008,
|
||||
622.8828360000007,
|
||||
622.234027999999,
|
||||
640.7814050000015,
|
||||
628.4150020000016,
|
||||
638.2158200000013,
|
||||
632.4952449999982,
|
||||
640.3528240000014,
|
||||
655.5803180000003,
|
||||
819.2730220000012,
|
||||
839.5432240000009,
|
||||
815.6718389999987,
|
||||
823.1129099999998,
|
||||
807.2870309999998,
|
||||
839.9379399999998,
|
||||
839.5880639999996,
|
||||
822.5235159999975,
|
||||
800.3038809999998,
|
||||
836.5671479999983,
|
||||
794.8266949999997,
|
||||
782.2958900000012,
|
||||
780.0966379999991,
|
||||
797.6877550000027,
|
||||
833.3983110000008,
|
||||
831.9884109999985
|
||||
]
|
||||
}
|
||||
],
|
||||
"upstreamFills": 1,
|
||||
"source": null,
|
||||
"results": null,
|
||||
"metrics": [
|
||||
{
|
||||
"name": "inspected_changed",
|
||||
"traffic": "background",
|
||||
"count": 100,
|
||||
"bytes": 209715200,
|
||||
"ms": 4202.822877000019,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 34,
|
||||
"b3": 65,
|
||||
"b4": 0,
|
||||
"b5": 1,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "legacy_result_hit",
|
||||
"traffic": "background",
|
||||
"count": 99,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 99,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "legacy_result_miss",
|
||||
"traffic": "background",
|
||||
"count": 1,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
}
|
||||
],
|
||||
"wireBytesPerResponse": 799783,
|
||||
"uncompressedBytes": 2115777,
|
||||
"verifiedResponses": 100
|
||||
}
|
||||
],
|
||||
"completedAt": "2026-11-02T10:49:41.535Z",
|
||||
"assertions": "All 200 response bodies verified against expected output or the validated wire digest"
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"scope": "Compiled local loopback changed-text gzip responses; repeated optimized measurements ran after all other task benchmarks/tests ended. The full optimized run overlapped the metadata benchmark during its early scenarios. Shared host, synthetic workload; no production capacity claim.",
|
||||
"verifiedOptimizedResponses": 2500,
|
||||
"rows": [
|
||||
{
|
||||
"bytes": 16384,
|
||||
"before": {
|
||||
"serialP50Ms": 44.88915300000008,
|
||||
"concurrency8P95Ms": 462.1094459999995
|
||||
},
|
||||
"optimized": {
|
||||
"serialP50Ms": 8.908395999999811,
|
||||
"concurrency8P95Ms": 111.85025099999984
|
||||
},
|
||||
"repeat": {
|
||||
"serialP50Ms": 7.257277000000158,
|
||||
"concurrency8P95Ms": 114.94514900000013
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 262144,
|
||||
"before": {
|
||||
"serialP50Ms": 45.89932399999998,
|
||||
"concurrency8P95Ms": 444.0948499999995
|
||||
},
|
||||
"optimized": {
|
||||
"serialP50Ms": 9.481284999999843,
|
||||
"concurrency8P95Ms": 136.36852099999942
|
||||
},
|
||||
"repeat": {
|
||||
"serialP50Ms": 9.021533999999974,
|
||||
"concurrency8P95Ms": 107.61299899999995
|
||||
}
|
||||
},
|
||||
{
|
||||
"bytes": 2097152,
|
||||
"before": {
|
||||
"serialP50Ms": 60.49789199999941,
|
||||
"concurrency8P95Ms": 528.2149260000006
|
||||
},
|
||||
"optimized": {
|
||||
"serialP50Ms": 24.991613999999572,
|
||||
"concurrency8P95Ms": 177.60703299999932
|
||||
},
|
||||
"repeat": {
|
||||
"serialP50Ms": 19.012864000000263,
|
||||
"concurrency8P95Ms": 216.19974999999977
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Shared cache performance evaluation</title><style>
|
||||
body{font-family:var(--font-sans,system-ui);color:var(--foreground,#17212b);line-height:1.5;margin:0}h2{font-size:20px;margin:0 0 8px}p{margin:8px 0 16px}.muted,small{color:var(--muted-foreground,#52606d)}label{font-weight:600}select{font:inherit;background:var(--card,#fff);color:inherit;border:1px solid var(--border,#aaa);border-radius:6px;padding:8px;margin:8px 0;width:100%;max-width:420px}table{border-collapse:collapse;width:100%;font-variant-numeric:tabular-nums}th,td{text-align:right;padding:12px 8px;border-bottom:1px solid var(--border,#ddd)}th:first-child,td:first-child{text-align:left;padding-left:0}thead th{font-size:12px;font-weight:600}tbody th{font-size:14px;font-weight:500}td{font-weight:650}small{display:block;font-size:11px;font-weight:400}.bad{color:var(--destructive,#ad2222)}.good{color:var(--success,#237044)}ul{padding-left:20px}li{margin:8px 0}.note{font-size:13px}a{color:var(--accent-foreground,#2563a5)}@media(max-width:420px){th,td{padding:10px 4px;font-size:13px}thead th{font-size:11px}h2{font-size:18px}}</style>
|
||||
<h2>Keep shared-cache rollout disabled for now</h2>
|
||||
<p>The current cache slows small and medium warm reads. Large files benefit. A benchmark-only SQLite change identifies a substantial part of the overhead.</p>
|
||||
<label for="metric">Compare warm changed-text responses</label><br><select id="metric"><option value="serial:p50Ms">Median latency · 1 client · milliseconds</option><option value="concurrent8:p95Ms">p95 latency · 8 clients · milliseconds</option><option value="concurrent8:requestsPerSecond">Throughput · 8 clients · requests/second</option><option value="concurrent8:cpuMsPerRequest">CPU · 8 clients · milliseconds/request</option><option value="concurrent8:peakRssMiB">Peak sampled process memory · MiB</option></select>
|
||||
<table aria-label="Warm cache benchmark comparison"><thead><tr><th>File / baseline</th><th>Baseline</th><th>Current<br>shared cache</th><th>Experimental<br>SQLite NORMAL</th></tr></thead><tbody id="rows"></tbody></table>
|
||||
<p class="note muted">16 and 256 KiB: raw source cache with repeated transformation and gzip. 2 MiB: existing transformed-file cache. Two warm batches per setting: 32 serial requests or 64 requests at concurrency eight. CPU and memory include both server and benchmark client.</p>
|
||||
<ul><li><strong>Correctness:</strong> 2,700 HTTP responses passed byte checks.</li><li><strong>Admin scaling:</strong> one pool statistics query reached 78.7 ms p95 at 100,000 synthetic blob records. It blocks the event loop.</li><li><strong>Eviction:</strong> the 4 MiB limit held, but cycling over a 6.25 MiB working set caused 300 misses in 300 reads.</li><li><strong>Next steps:</strong> reduce metadata commits, cache admin aggregates, and test a representative mixed workload across server processes.</li></ul>
|
||||
<p class="note">NORMAL was tested only on temporary cache indexes. In WAL mode it can lose recent commits after power loss, so recovery needs validation before adoption. <a href="https://www.sqlite.org/pragma.html#pragma_synchronous">SQLite durability documentation</a>.</p>
|
||||
<p class="note muted">Local compiled-code evaluation · Node 24.14.1 · 2 November 2026. Shared host, synthetic content, warm filesystem cache, no TLS or production traffic. These measurements are not production capacity guarantees. Application settings remain unchanged.</p>
|
||||
<script>const data=[{"sizeBytes": 16384, "label": "16 KiB", "baseline": "raw source cache", "baselineMetrics": {"coldMs": 145.9149209999996, "serial": {"p50Ms": 8.318075000000135, "p95Ms": 10.736985999999888, "requestsPerSecond": 117.44442918645578, "cpuMsPerRequest": 11.06740625, "peakRssMiB": 146.50390625}, "concurrent8": {"p50Ms": 50.20099499999969, "p95Ms": 71.84271200000012, "requestsPerSecond": 142.73942902734086, "cpuMsPerRequest": 9.620406249999998, "peakRssMiB": 170.53125}}, "currentMetrics": {"coldMs": 709.8329450000001, "serial": {"p50Ms": 44.88915300000008, "p95Ms": 68.10151200000018, "requestsPerSecond": 20.710932531095363, "cpuMsPerRequest": 13.53253125, "peakRssMiB": 147.47265625}, "concurrent8": {"p50Ms": 362.3927130000002, "p95Ms": 462.1094459999995, "requestsPerSecond": 20.755357071571403, "cpuMsPerRequest": 11.042078125, "peakRssMiB": 154.1328125}}, "experimentalNormalMetrics": {"coldMs": 211.99763500000017, "serial": {"p50Ms": 6.900600000000395, "p95Ms": 9.86466399999972, "requestsPerSecond": 134.73985687410286, "cpuMsPerRequest": 8.7118125, "peakRssMiB": 141.24609375}, "concurrent8": {"p50Ms": 38.635037999999895, "p95Ms": 46.82847199999969, "requestsPerSecond": 197.41218048206238, "cpuMsPerRequest": 6.15025, "peakRssMiB": 147.6875}}, "gzipSavingPercent": 61.97907215871288}, {"sizeBytes": 262144, "label": "256 KiB", "baseline": "raw source cache", "baselineMetrics": {"coldMs": 100.41967600000021, "serial": {"p50Ms": 36.49021599999992, "p95Ms": 53.95963900000015, "requestsPerSecond": 26.236596142201567, "cpuMsPerRequest": 42.746187500000005, "peakRssMiB": 215.1875}, "concurrent8": {"p50Ms": 120.57758600000034, "p95Ms": 250.78685799999994, "requestsPerSecond": 53.7503475211922, "cpuMsPerRequest": 37.485390625, "peakRssMiB": 268.109375}}, "currentMetrics": {"coldMs": 726.5002400000001, "serial": {"p50Ms": 45.89932399999998, "p95Ms": 73.79595599999993, "requestsPerSecond": 20.372770202529612, "cpuMsPerRequest": 16.253875, "peakRssMiB": 160.78515625}, "concurrent8": {"p50Ms": 326.38565800000015, "p95Ms": 444.0948499999995, "requestsPerSecond": 23.057422718927143, "cpuMsPerRequest": 12.072328124999999, "peakRssMiB": 185.7578125}}, "experimentalNormalMetrics": {"coldMs": 293.5069330000001, "serial": {"p50Ms": 11.702889000000141, "p95Ms": 16.41937599999983, "requestsPerSecond": 80.13277379588973, "cpuMsPerRequest": 14.18359375, "peakRssMiB": 160.62890625}, "concurrent8": {"p50Ms": 72.28398599999946, "p95Ms": 89.62643300000036, "requestsPerSecond": 105.43423551997391, "cpuMsPerRequest": 11.027765625, "peakRssMiB": 185.6328125}}, "gzipSavingPercent": 61.890196641851716}, {"sizeBytes": 2097152, "label": "2 MiB", "baseline": "existing transformed cache", "baselineMetrics": {"coldMs": 2903.1252619999996, "serial": {"p50Ms": 236.22282199999972, "p95Ms": 288.4866490000004, "requestsPerSecond": 4.133831174669408, "cpuMsPerRequest": 362.9403125, "peakRssMiB": 336.703125}, "concurrent8": {"p50Ms": 690.5366940000022, "p95Ms": 929.2231830000001, "requestsPerSecond": 10.958910900736049, "cpuMsPerRequest": 253.19115625, "peakRssMiB": 308.02734375}}, "currentMetrics": {"coldMs": 4133.51807, "serial": {"p50Ms": 60.49789199999941, "p95Ms": 100.03485599999931, "requestsPerSecond": 15.358397676800456, "cpuMsPerRequest": 50.210843749999995, "peakRssMiB": 298.671875}, "concurrent8": {"p50Ms": 478.30868799999917, "p95Ms": 528.2149260000006, "requestsPerSecond": 16.483621344424616, "cpuMsPerRequest": 55.64621875, "peakRssMiB": 296.6875}}, "experimentalNormalMetrics": {"coldMs": 3895.830503, "serial": {"p50Ms": 25.95565600000009, "p95Ms": 32.11927700000069, "requestsPerSecond": 40.429950182644916, "cpuMsPerRequest": 43.713375, "peakRssMiB": 307.65625}, "concurrent8": {"p50Ms": 161.56209900000067, "p95Ms": 324.75534399999924, "requestsPerSecond": 43.95237969807028, "cpuMsPerRequest": 39.839515625000004, "peakRssMiB": 307.93359375}}, "gzipSavingPercent": 62.199088089151175}];const select=document.getElementById('metric');function render(){const [group,metric]=select.value.split(':');document.getElementById('rows').innerHTML=data.map(r=>{const values=['baseline','current','experimentalNormal'].map(k=>r[k+'Metrics'][group][metric]);return '<tr><th scope="row">'+r.label+'<small>'+r.baseline+'</small></th>'+values.map((v,i)=>{const ratio=v/values[0];const faster=metric==='requestsPerSecond'?ratio>1:ratio<1;return '<td class="'+(i?(faster?'good':'bad'):'')+'">'+v.toFixed(1)+'</td>'}).join('')+'</tr>'}).join('')}select.addEventListener('change',render);render();</script></html>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,301 +0,0 @@
|
||||
{
|
||||
"measuredAt": "2026-11-02T10:48:24.664Z",
|
||||
"runtime": {
|
||||
"execution": "compiled JavaScript",
|
||||
"node": "v24.14.1",
|
||||
"platform": "linux",
|
||||
"arch": "x64",
|
||||
"cpu": "Intel Xeon E312xx (Sandy Bridge, IBRS update)",
|
||||
"logicalCpus": 12,
|
||||
"totalMemoryGiB": 35.22977066040039,
|
||||
"loadAverage": [
|
||||
2.19,
|
||||
3.52,
|
||||
3.52
|
||||
]
|
||||
},
|
||||
"scope": "Compiled local loopback HTTP; changed text; 32 serial and 64 concurrency-8 warm samples per scenario. Percentiles pooled across two batches. CPU/RSS include client and server. Experimental NORMAL affects disposable benchmark databases only.",
|
||||
"verifiedHttpResponses": 2700,
|
||||
"rows": [
|
||||
{
|
||||
"sizeBytes": 16384,
|
||||
"label": "16 KiB",
|
||||
"baseline": "raw source cache",
|
||||
"baselineMetrics": {
|
||||
"coldMs": 145.9149209999996,
|
||||
"serial": {
|
||||
"p50Ms": 8.318075000000135,
|
||||
"p95Ms": 10.736985999999888,
|
||||
"requestsPerSecond": 117.44442918645578,
|
||||
"cpuMsPerRequest": 11.06740625,
|
||||
"peakRssMiB": 146.50390625
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 50.20099499999969,
|
||||
"p95Ms": 71.84271200000012,
|
||||
"requestsPerSecond": 142.73942902734086,
|
||||
"cpuMsPerRequest": 9.620406249999998,
|
||||
"peakRssMiB": 170.53125
|
||||
}
|
||||
},
|
||||
"currentMetrics": {
|
||||
"coldMs": 709.8329450000001,
|
||||
"serial": {
|
||||
"p50Ms": 44.88915300000008,
|
||||
"p95Ms": 68.10151200000018,
|
||||
"requestsPerSecond": 20.710932531095363,
|
||||
"cpuMsPerRequest": 13.53253125,
|
||||
"peakRssMiB": 147.47265625
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 362.3927130000002,
|
||||
"p95Ms": 462.1094459999995,
|
||||
"requestsPerSecond": 20.755357071571403,
|
||||
"cpuMsPerRequest": 11.042078125,
|
||||
"peakRssMiB": 154.1328125
|
||||
}
|
||||
},
|
||||
"experimentalNormalMetrics": {
|
||||
"coldMs": 211.99763500000017,
|
||||
"serial": {
|
||||
"p50Ms": 6.900600000000395,
|
||||
"p95Ms": 9.86466399999972,
|
||||
"requestsPerSecond": 134.73985687410286,
|
||||
"cpuMsPerRequest": 8.7118125,
|
||||
"peakRssMiB": 141.24609375
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 38.635037999999895,
|
||||
"p95Ms": 46.82847199999969,
|
||||
"requestsPerSecond": 197.41218048206238,
|
||||
"cpuMsPerRequest": 6.15025,
|
||||
"peakRssMiB": 147.6875
|
||||
}
|
||||
},
|
||||
"gzipSavingPercent": 61.97907215871288
|
||||
},
|
||||
{
|
||||
"sizeBytes": 262144,
|
||||
"label": "256 KiB",
|
||||
"baseline": "raw source cache",
|
||||
"baselineMetrics": {
|
||||
"coldMs": 100.41967600000021,
|
||||
"serial": {
|
||||
"p50Ms": 36.49021599999992,
|
||||
"p95Ms": 53.95963900000015,
|
||||
"requestsPerSecond": 26.236596142201567,
|
||||
"cpuMsPerRequest": 42.746187500000005,
|
||||
"peakRssMiB": 215.1875
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 120.57758600000034,
|
||||
"p95Ms": 250.78685799999994,
|
||||
"requestsPerSecond": 53.7503475211922,
|
||||
"cpuMsPerRequest": 37.485390625,
|
||||
"peakRssMiB": 268.109375
|
||||
}
|
||||
},
|
||||
"currentMetrics": {
|
||||
"coldMs": 726.5002400000001,
|
||||
"serial": {
|
||||
"p50Ms": 45.89932399999998,
|
||||
"p95Ms": 73.79595599999993,
|
||||
"requestsPerSecond": 20.372770202529612,
|
||||
"cpuMsPerRequest": 16.253875,
|
||||
"peakRssMiB": 160.78515625
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 326.38565800000015,
|
||||
"p95Ms": 444.0948499999995,
|
||||
"requestsPerSecond": 23.057422718927143,
|
||||
"cpuMsPerRequest": 12.072328124999999,
|
||||
"peakRssMiB": 185.7578125
|
||||
}
|
||||
},
|
||||
"experimentalNormalMetrics": {
|
||||
"coldMs": 293.5069330000001,
|
||||
"serial": {
|
||||
"p50Ms": 11.702889000000141,
|
||||
"p95Ms": 16.41937599999983,
|
||||
"requestsPerSecond": 80.13277379588973,
|
||||
"cpuMsPerRequest": 14.18359375,
|
||||
"peakRssMiB": 160.62890625
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 72.28398599999946,
|
||||
"p95Ms": 89.62643300000036,
|
||||
"requestsPerSecond": 105.43423551997391,
|
||||
"cpuMsPerRequest": 11.027765625,
|
||||
"peakRssMiB": 185.6328125
|
||||
}
|
||||
},
|
||||
"gzipSavingPercent": 61.890196641851716
|
||||
},
|
||||
{
|
||||
"sizeBytes": 2097152,
|
||||
"label": "2 MiB",
|
||||
"baseline": "existing transformed cache",
|
||||
"baselineMetrics": {
|
||||
"coldMs": 2903.1252619999996,
|
||||
"serial": {
|
||||
"p50Ms": 236.22282199999972,
|
||||
"p95Ms": 288.4866490000004,
|
||||
"requestsPerSecond": 4.133831174669408,
|
||||
"cpuMsPerRequest": 362.9403125,
|
||||
"peakRssMiB": 336.703125
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 690.5366940000022,
|
||||
"p95Ms": 929.2231830000001,
|
||||
"requestsPerSecond": 10.958910900736049,
|
||||
"cpuMsPerRequest": 253.19115625,
|
||||
"peakRssMiB": 308.02734375
|
||||
}
|
||||
},
|
||||
"currentMetrics": {
|
||||
"coldMs": 4133.51807,
|
||||
"serial": {
|
||||
"p50Ms": 60.49789199999941,
|
||||
"p95Ms": 100.03485599999931,
|
||||
"requestsPerSecond": 15.358397676800456,
|
||||
"cpuMsPerRequest": 50.210843749999995,
|
||||
"peakRssMiB": 298.671875
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 478.30868799999917,
|
||||
"p95Ms": 528.2149260000006,
|
||||
"requestsPerSecond": 16.483621344424616,
|
||||
"cpuMsPerRequest": 55.64621875,
|
||||
"peakRssMiB": 296.6875
|
||||
}
|
||||
},
|
||||
"experimentalNormalMetrics": {
|
||||
"coldMs": 3895.830503,
|
||||
"serial": {
|
||||
"p50Ms": 25.95565600000009,
|
||||
"p95Ms": 32.11927700000069,
|
||||
"requestsPerSecond": 40.429950182644916,
|
||||
"cpuMsPerRequest": 43.713375,
|
||||
"peakRssMiB": 307.65625
|
||||
},
|
||||
"concurrent8": {
|
||||
"p50Ms": 161.56209900000067,
|
||||
"p95Ms": 324.75534399999924,
|
||||
"requestsPerSecond": 43.95237969807028,
|
||||
"cpuMsPerRequest": 39.839515625000004,
|
||||
"peakRssMiB": 307.93359375
|
||||
}
|
||||
},
|
||||
"gzipSavingPercent": 62.199088089151175
|
||||
}
|
||||
],
|
||||
"indexProbe": {
|
||||
"measuredAt": "2026-11-02T10:42:36.314Z",
|
||||
"scope": "Synthetic metadata-only scale probe. Dummy blob rows have no payload files; excludes directory scanning and disk reads for those rows. Real reads use one verified blob. Eviction probe uses real 64 KiB files.",
|
||||
"node": "v24.14.1",
|
||||
"cardinality": [
|
||||
{
|
||||
"seedBlobs": 0,
|
||||
"seedAliases": 0,
|
||||
"seedDecisions": 0,
|
||||
"seedHistory": 0,
|
||||
"adminStats": {
|
||||
"p50Ms": 0.5495260000002418,
|
||||
"p95Ms": 0.8194220000000314,
|
||||
"maxMs": 0.8764419999997699
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 22.106009000000086,
|
||||
"p95Ms": 32.67359299999998,
|
||||
"maxMs": 38.92065599999978
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 6.600801999999931,
|
||||
"p95Ms": 12.472383000000264,
|
||||
"maxMs": 15.8033989999999
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 71.12627699999939,
|
||||
"p95Ms": 98.24754799999982,
|
||||
"maxMs": 100.35789100000011
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 10000,
|
||||
"seedAliases": 20000,
|
||||
"seedDecisions": 10000,
|
||||
"seedHistory": 10000,
|
||||
"adminStats": {
|
||||
"p50Ms": 6.904306000000361,
|
||||
"p95Ms": 9.677666999999929,
|
||||
"maxMs": 12.638716999999815
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 22.83701199999996,
|
||||
"p95Ms": 47.79449499999828,
|
||||
"maxMs": 102.36107600000014
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 8.062501999999768,
|
||||
"p95Ms": 13.995523999999932,
|
||||
"maxMs": 14.909832000001188
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 75.03789299999971,
|
||||
"p95Ms": 117.16210499999943,
|
||||
"maxMs": 143.80038499999955
|
||||
}
|
||||
},
|
||||
{
|
||||
"seedBlobs": 100000,
|
||||
"seedAliases": 200000,
|
||||
"seedDecisions": 100000,
|
||||
"seedHistory": 100000,
|
||||
"adminStats": {
|
||||
"p50Ms": 66.83604900000137,
|
||||
"p95Ms": 78.69937500000015,
|
||||
"maxMs": 87.98320400000011
|
||||
},
|
||||
"warmSourceHit": {
|
||||
"p50Ms": 26.310491000000184,
|
||||
"p95Ms": 82.98941600000035,
|
||||
"maxMs": 112.1549300000006
|
||||
},
|
||||
"decisionWrite": {
|
||||
"p50Ms": 22.948387000000366,
|
||||
"p95Ms": 45.47333599999911,
|
||||
"maxMs": 56.50094800000079
|
||||
},
|
||||
"smallFill": {
|
||||
"p50Ms": 136.3280279999999,
|
||||
"p95Ms": 214.8330500000011,
|
||||
"maxMs": 312.4176129999978
|
||||
}
|
||||
}
|
||||
],
|
||||
"eviction": {
|
||||
"requests": 300,
|
||||
"distinctObjects": 100,
|
||||
"upstreamFills": 300,
|
||||
"hitRate": 0,
|
||||
"elapsedMs": 24658.882357999995,
|
||||
"p50Ms": 74.17433299999539,
|
||||
"p95Ms": 107.83662400000321,
|
||||
"peakAllocated": 3997696,
|
||||
"final": {
|
||||
"blobs": 60,
|
||||
"originalBytes": 3932160,
|
||||
"storedBytes": 3932160,
|
||||
"allocatedBytes": 3932160,
|
||||
"oldestAccess": 1793616151486,
|
||||
"budgetBytes": 4194304,
|
||||
"reservedBytes": 0,
|
||||
"maxObjectBytes": 65536,
|
||||
"activeReaders": 0,
|
||||
"decisions": 0
|
||||
}
|
||||
},
|
||||
"assertions": "passed"
|
||||
},
|
||||
"recommendation": "Keep production disabled pending reduction of synchronous metadata commits and retesting. No application settings changed."
|
||||
}
|
||||
@@ -1,455 +0,0 @@
|
||||
{
|
||||
"node": "v24.14.1",
|
||||
"measuredAt": "2026-11-02T10:19:09.724Z",
|
||||
"scope": "Synthetic local acceptance workload; not a production projection",
|
||||
"sourceRequests": 5,
|
||||
"upstreamFills": 1,
|
||||
"source": {
|
||||
"blobs": 1,
|
||||
"originalBytes": 19200,
|
||||
"storedBytes": 139,
|
||||
"allocatedBytes": 4096,
|
||||
"oldestAccess": 1793614746536,
|
||||
"budgetBytes": 1048576,
|
||||
"reservedBytes": 0,
|
||||
"maxObjectBytes": 32768,
|
||||
"activeReaders": 0,
|
||||
"decisions": 0
|
||||
},
|
||||
"results": {
|
||||
"blobs": 1,
|
||||
"originalBytes": 19600,
|
||||
"storedBytes": 140,
|
||||
"allocatedBytes": 4096,
|
||||
"oldestAccess": 1793614747125,
|
||||
"budgetBytes": 1048576,
|
||||
"reservedBytes": 0,
|
||||
"maxObjectBytes": 32768,
|
||||
"activeReaders": 0,
|
||||
"decisions": 3
|
||||
},
|
||||
"eviction": {
|
||||
"blobs": 13,
|
||||
"originalBytes": 52000,
|
||||
"storedBytes": 52000,
|
||||
"allocatedBytes": 53248,
|
||||
"oldestAccess": 1793614748735,
|
||||
"budgetBytes": 65536,
|
||||
"reservedBytes": 0,
|
||||
"maxObjectBytes": 4096,
|
||||
"activeReaders": 0,
|
||||
"decisions": 0
|
||||
},
|
||||
"decisionsReused": 2,
|
||||
"unchangedDecisionsComputed": 2,
|
||||
"changedOutputsComputed": 1,
|
||||
"compressionSavingPercent": 99.27604166666667,
|
||||
"responses": [
|
||||
{
|
||||
"status": 200,
|
||||
"encoding": "gzip",
|
||||
"bytes": 139
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"encoding": "gzip",
|
||||
"bytes": 139
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"encoding": "gzip",
|
||||
"bytes": 139
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"encoding": "gzip",
|
||||
"bytes": 140
|
||||
},
|
||||
{
|
||||
"status": 200,
|
||||
"encoding": "gzip",
|
||||
"bytes": 140
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"name": "compress",
|
||||
"traffic": "file",
|
||||
"count": 2,
|
||||
"bytes": 38800,
|
||||
"ms": 11.220815999999104,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 2,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "decision_hit",
|
||||
"traffic": "file",
|
||||
"count": 2,
|
||||
"bytes": 38400,
|
||||
"ms": 0,
|
||||
"b0": 2,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "decision_miss",
|
||||
"traffic": "file",
|
||||
"count": 3,
|
||||
"bytes": 57600,
|
||||
"ms": 0,
|
||||
"b0": 3,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "decompress",
|
||||
"traffic": "file",
|
||||
"count": 3,
|
||||
"bytes": 57600,
|
||||
"ms": 11.292176999999356,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 3,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "inspected_changed",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 7.701614000000518,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 1,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "inspected_unchanged",
|
||||
"traffic": "file",
|
||||
"count": 2,
|
||||
"bytes": 38400,
|
||||
"ms": 8.860568000000058,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 2,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "result_fill",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19600,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "result_first_seen_miss",
|
||||
"traffic": "file",
|
||||
"count": 3,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 3,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "result_miss",
|
||||
"traffic": "file",
|
||||
"count": 3,
|
||||
"bytes": 57600,
|
||||
"ms": 0,
|
||||
"b0": 3,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "result_stored",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 140,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "rewrite_changed",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 49.649725999999646,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 1,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "rewrite_changed_cached",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "rewrite_unchanged",
|
||||
"traffic": "file",
|
||||
"count": 2,
|
||||
"bytes": 38400,
|
||||
"ms": 139.08289400000012,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 2,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "rewrite_unchanged_cached",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_fill",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_first_seen_miss",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_hit",
|
||||
"traffic": "file",
|
||||
"count": 4,
|
||||
"bytes": 76800,
|
||||
"ms": 0,
|
||||
"b0": 4,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_miss",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 19200,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_reuse_1d",
|
||||
"traffic": "file",
|
||||
"count": 4,
|
||||
"bytes": 76800,
|
||||
"ms": 0,
|
||||
"b0": 4,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_reuse_1h",
|
||||
"traffic": "file",
|
||||
"count": 4,
|
||||
"bytes": 76800,
|
||||
"ms": 0,
|
||||
"b0": 4,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_reuse_7d",
|
||||
"traffic": "file",
|
||||
"count": 4,
|
||||
"bytes": 76800,
|
||||
"ms": 0,
|
||||
"b0": 4,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "source_stored",
|
||||
"traffic": "file",
|
||||
"count": 1,
|
||||
"bytes": 139,
|
||||
"ms": 0,
|
||||
"b0": 1,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "workload_eviction",
|
||||
"traffic": "background",
|
||||
"count": 17,
|
||||
"bytes": 68000,
|
||||
"ms": 16365,
|
||||
"b0": 0,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 17,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "workload_fill",
|
||||
"traffic": "background",
|
||||
"count": 30,
|
||||
"bytes": 120000,
|
||||
"ms": 0,
|
||||
"b0": 30,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "workload_first_seen_miss",
|
||||
"traffic": "background",
|
||||
"count": 30,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 30,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "workload_miss",
|
||||
"traffic": "background",
|
||||
"count": 30,
|
||||
"bytes": 0,
|
||||
"ms": 0,
|
||||
"b0": 30,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
},
|
||||
{
|
||||
"name": "workload_stored",
|
||||
"traffic": "background",
|
||||
"count": 30,
|
||||
"bytes": 120000,
|
||||
"ms": 0,
|
||||
"b0": 30,
|
||||
"b1": 0,
|
||||
"b2": 0,
|
||||
"b3": 0,
|
||||
"b4": 0,
|
||||
"b5": 0,
|
||||
"b6": 0
|
||||
}
|
||||
],
|
||||
"assertions": "passed"
|
||||
}
|
||||
@@ -128,281 +128,5 @@ clients can wait for the actual store reset.
|
||||
|
||||
## Shared blob cache
|
||||
|
||||
The optional shared filesystem cache stores immutable source content across projects.
|
||||
It uses Node's built-in SQLite module and requires Node 22.15 or newer. All API and
|
||||
streamer processes on one host must mount the same local cache directory. SQLite
|
||||
WAL is not a distributed lock service: do not put this directory on NFS or share
|
||||
it across hosts. S3 storage continues to use the existing storage implementation.
|
||||
|
||||
Enable the integrated implementation with `SHARED_CACHE_ENABLED=true`. The default
|
||||
is false so a code deployment does not silently migrate production data. The other
|
||||
settings are independent rollback controls:
|
||||
|
||||
- `SHARED_CACHE_PATH`: defaults to `.shared-cache-v1` inside `FOLDER`.
|
||||
- `SHARED_CACHE_BYTES`: source pool budget, default 10 GiB.
|
||||
- `SHARED_CACHE_RESULT_BYTES`: transformed output budget, default 512 MiB.
|
||||
- `SHARED_CACHE_MAX_FILE_BYTES`: maximum source admission size, default 32 MiB.
|
||||
- `SHARED_CACHE_FREE_BYTES`: free-device-space reserve, default 1 GiB.
|
||||
- `SHARED_CACHE_LOW_WATER`: eviction target fraction, default 0.9.
|
||||
- `SHARED_CACHE_GZIP`: store gzip when beneficial, default true.
|
||||
- `SHARED_CACHE_GZIP_MIN_SAVING`: minimum fractional saving, default 0.10.
|
||||
- `SHARED_CACHE_DECISIONS`: enable unchanged decisions and changed-output reuse,
|
||||
default true.
|
||||
- `CACHE_MONITORING_ENABLED`: collect cache observations, default true. Monitoring
|
||||
is independent of shared storage and also records legacy cache/inspection events.
|
||||
|
||||
These are initial limits, not capacity recommendations from the production sample.
|
||||
Restart processes together when changing pool limits. Reserve headroom for SQLite,
|
||||
filesystem directories, existing caches and other application temporary files.
|
||||
The budget accounts for blob allocation with a conservative 4 KiB minimum plus
|
||||
in-flight reservations of three times the maximum object size and a small overhead.
|
||||
Keep each pool budget larger than this reservation. Admission can bypass the cache
|
||||
while other fills/readers occupy the budget. Oversized source objects are streamed
|
||||
without admission, still subject to the application's file-size limit.
|
||||
|
||||
Git blobs are verified against the requested Git SHA before publication. Resolved
|
||||
LFS content is admitted only after verifying both the Git pointer and its SHA-256
|
||||
payload digest and size. Gzip is a representation of the same uncompressed content.
|
||||
Files are written privately, synced and atomically renamed before index publication.
|
||||
Fills and readers have renewable leases. Eviction skips readers, and stale fills
|
||||
are recovered before their reservations are released. LRU access timestamps are
|
||||
coarsened to 30 seconds. Orphan reconciliation runs at most hourly across processes.
|
||||
Alias and reuse-history indexes are bounded; decisions expire after seven days and
|
||||
are capped at 100,000 entries.
|
||||
|
||||
Existing generation caches are read as a migration fallback and verified before
|
||||
promotion. They are not deleted during promotion, so rollback remains possible.
|
||||
The new pool budget does not include legacy copies: monitor total filesystem usage
|
||||
and retire legacy data only after validating rollout. Uploaded ZIP originals and
|
||||
other durable source material are untouched. Repository removal invalidates access
|
||||
and project mappings, while shared blobs remain subject to global eviction.
|
||||
|
||||
The HTTP fast path applies to individual file responses backed by the shared source
|
||||
pool, including small text files. Decisions include content identity, path, project
|
||||
context, all transformation options, generation/revision, mask, hostname and engine
|
||||
version. Unchanged decisions serve the original representation. Changed output has
|
||||
its own bounded pool. Gzip negotiation honors quality values, uses `Vary`, and
|
||||
preserves MIME type. File validators are weak when shared delivery is enabled so
|
||||
identity and gzip representations can revalidate the same logical content. HEAD
|
||||
continues to use metadata only. Range requests receive a complete response; this
|
||||
implementation does not add random access into gzip files. Website rendering keeps
|
||||
its renderer cache; ZIP scans do not admit bulk entries into the source blob pool.
|
||||
|
||||
The admin overview's Cache section reads `/api/admin/cache?minutes=60` behind the
|
||||
existing admin authorization. Windows are 15 minutes, one hour, 24 hours and seven
|
||||
days. SQLite telemetry batches at most 512 groups every five seconds and retains
|
||||
minute aggregates for 48 hours and hourly aggregates for 30 days. No paths, terms,
|
||||
user IDs or blob hashes appear in metric labels. The UI distinguishes unavailable
|
||||
telemetry, dropped events, disabled storage and empty windows. Rows separate file,
|
||||
website, ZIP, background and known-monitor traffic. Monitor classification is an
|
||||
operational heuristic, not a complete bot detector.
|
||||
|
||||
Hit counts and byte hit rates measure source lookups; misses classify first observed
|
||||
keys, known misses and eviction refetches within bounded seven-day history. Reuse
|
||||
intervals are consecutive blob accesses, not distinct people or browser visits.
|
||||
Eviction time measures idle age; codec and inspection timings are elapsed work time,
|
||||
not CPU samples. Cached decisions are separate from actual inspections. Minute and
|
||||
hour boundaries make the displayed windows approximate.
|
||||
|
||||
Run the reproducible acceptance workload with:
|
||||
|
||||
```sh
|
||||
node scripts/cache-workload.js docs/cache-workload-results.json
|
||||
npx mocha test/shared-blob-cache.test.js test/shared-cache-http.test.js
|
||||
```
|
||||
|
||||
The JSON report asserts cross-project source reuse, unchanged-decision reuse,
|
||||
changed-output reuse, gzip delivery and budget enforcement. Its compression ratio
|
||||
comes from synthetic text and must not be presented as a production projection.
|
||||
Production rollout should compare request/byte hit rates, eviction refetches, p95
|
||||
latency, upstream errors and free disk over a representative week, with large files,
|
||||
ZIP work and known monitors visible separately.
|
||||
|
||||
### Benefits and costs
|
||||
|
||||
| Choice | Benefit | Cost or limit |
|
||||
| --- | --- | --- |
|
||||
| Global content identity | Reuses identical files across paths and projects; renames do not duplicate content | Requires verified hashes and authorization on every request; uses digest-prefix directories to avoid one huge directory |
|
||||
| Byte budget with approximate LRU | Predictable blob footprint and automatic reclamation | Evicted files incur upstream fetches; active readers can temporarily prevent admission |
|
||||
| Selective gzip | Reduces payload storage and can serve compressed bytes directly | First-fill compression costs work; identity consumers and uncached anonymization require decoding |
|
||||
| Rule-aware decisions and results | Repeated unchanged reads skip regex inspection; changed output is reusable | More metadata and a separate output budget; settings changes produce new decisions |
|
||||
| SQLite coordination and telemetry | Cross-process coordination without another service; admin can measure actual reuse and rewrite work | Local-filesystem scope; short synchronous transactions; metadata/headroom are outside blob budgets |
|
||||
|
||||
### Rollout sequence
|
||||
|
||||
1. Deploy with shared storage disabled and collect legacy hits, inspections and codec
|
||||
timings. Keep known-monitor traffic separate from file readers.
|
||||
2. Enable the shared cache on the single-host filesystem deployment with both byte
|
||||
budgets configured. Keep legacy copies for rollback.
|
||||
3. Compare a representative week of byte/request hits, rewrite decisions, eviction
|
||||
refetches, request latency, upstream errors and whole-device free space. Adjust
|
||||
admission size and budgets from those observations.
|
||||
4. Retire legacy cache copies only after the rollback window. Uploaded originals
|
||||
remain durable and are never candidates for shared-pool eviction.
|
||||
|
||||
The implementation and acceptance workload are local changes; this work does not
|
||||
enable or migrate production storage.
|
||||
|
||||
### Production observations used for this design
|
||||
|
||||
The read-only audit on 2026-11-02 found 425,312 source files across 31,522 projects,
|
||||
containing 144.32 GB of payload. Deduplication within projects could remove 1.87 GB;
|
||||
global deduplication could remove 2.93 GB total (about 2.03%), including another
|
||||
1.06 GB across projects. One file could not be read. These are decimal GB and
|
||||
payload savings, not a compression estimate or the expected new working-set size.
|
||||
|
||||
The preceding 24-hour access sample contained 29,980 successful file-body responses,
|
||||
including 9,249 repeat responses (30.9%). URL repetitions are not the same as blob
|
||||
cache hits. A separate approximately two-hour metric window recorded 2,302 source
|
||||
hits out of 3,600 lookups (63.9%). This supports retaining a bounded source cache;
|
||||
it does not establish the optimal byte budget.
|
||||
|
||||
In the uniform anonymization replay, 937 resident files were measured: 764 text,
|
||||
173 binary, and 21 with changed output. Thirteen resolved files exceeded the 4 MiB
|
||||
sample limit, and missing files/mappings were excluded. The sample's mean gzip-6
|
||||
work was 1.46 ms per file and mean decompression was 0.24 ms; these replay timings
|
||||
are not live-request latency or a forecast for large files. Continuous telemetry is
|
||||
needed to replace these samples with representative workload measurements.
|
||||
|
||||
### Local acceptance evidence
|
||||
|
||||
The checked-in `cache-workload-results.json` is generated by assertions, not hand
|
||||
written. Five file requests across two projects needed one upstream source fill;
|
||||
unchanged and changed responses reused decisions, and changed bytes occupied one
|
||||
result blob. The 64 KiB eviction workload ended at 53,248 allocated bytes with no
|
||||
remaining fill reservations. Compression figures describe this synthetic fixture.
|
||||
|
||||
Validation also covers separate operating-system producers, failed/invalid fills,
|
||||
crash publication recovery, active-reader eviction protection, LFS pointer/payload
|
||||
verification, gzip negotiation, rule changes, admin authorization and HEAD/304.
|
||||
The disposable MongoDB/Redis performance integration run passed 130 tests. The
|
||||
admin Cache section was checked at 1280 px and 390 px, including filter layout,
|
||||
scrollable tables, empty filters and unavailable telemetry.
|
||||
|
||||
The final complete default test run recorded 1,062 passing, 159 pending and one
|
||||
failure: `test/error-codes.test.js` reports nine missing frontend translations for
|
||||
the pre-existing maintenance API changes. Cache tests passed in that full run.
|
||||
TypeScript compilation, the scoped lint checks (existing warnings only), the UI
|
||||
build and `git diff --check` passed. Production rollout was not performed.
|
||||
|
||||
## Initial cache performance evaluation, 2026-11-02
|
||||
|
||||
The initial implementation passed functional checks, but its metadata write path regressed small-file performance. The following measurements are preserved as the before-optimization baseline; the implementation and follow-up results below supersede the recommendations in this section. These are local measurements, not production capacity estimates.
|
||||
|
||||
### Warm changed-text responses
|
||||
|
||||
Each percentile pools two batches. Serial measurements contain 32 requests; concurrency-eight measurements contain 64. The small/medium baseline reads a local raw source and repeats anonymization/gzip. The 2 MiB baseline additionally uses the existing transformed-file cache, with 99 measured cache hits out of 100 requests. Authentication and Redis coordination are outside this comparison.
|
||||
|
||||
| File | Baseline median, ms | Current median, ms | Experimental NORMAL median, ms | Baseline p95 at 8 clients, ms | Current p95 at 8 clients, ms | NORMAL p95 at 8 clients, ms |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| 16 KiB | 8.3 | 44.9 | 6.9 | 71.8 | 462.1 | 46.8 |
|
||||
| 256 KiB | 36.5 | 45.9 | 11.7 | 250.8 | 444.1 | 89.6 |
|
||||
| 2 MiB | 236.2 | 60.5 | 26.0 | 929.2 | 528.2 | 324.8 |
|
||||
|
||||
### Findings
|
||||
|
||||
- The cache hit path performs synchronous SQLite writes for reader leases, reuse history and release. The temporary-database A/B changes only pool connections to `PRAGMA synchronous=NORMAL`; the measured reduction supports commit latency as a major bottleneck. This is a diagnostic experiment, not an implemented fix.
|
||||
- NORMAL in WAL mode can lose recent committed transactions following power loss or a system crash. Validate recovery/accounting before changing the durability of disposable cache indexes. See [SQLite synchronous documentation](https://www.sqlite.org/pragma.html#pragma_synchronous).
|
||||
- For changed 2 MiB content at eight clients, current shared caching reduced combined client/server CPU from 253.2 to 55.6 ms per request. Peak sampled RSS was 308.0 versus 296.7 MiB. These are whole-process values, including runtime, HTTP client and worker threads.
|
||||
- Synthetic text transferred about 62.2% fewer bytes with gzip. Incompressible 256 KiB binary data was stored and served as identity, avoiding ineffective gzip storage. These compression ratios are not production projections.
|
||||
- Cold responses include first-use initialization. For 16 KiB changed text they took 145.9 ms in the baseline, 709.8 ms currently, and 212.0 ms in the NORMAL experiment. Do not use this single cold sample as steady-state miss latency.
|
||||
- At 100,000 synthetic blob rows, a single pool stats query took 78.7 ms p95 synchronously; saving a decision took 45.5 ms p95. Cache/materialize admin aggregates and reduce retention scans on request paths. Dummy blob rows have no files, so this measures metadata scaling, not full directory reconciliation.
|
||||
- A 4 MiB pool cycling sequentially over 100 distinct 64 KiB objects stayed below budget, but all 300 reads fetched again. Its working set was larger than the pool. Reuse, request order and admission policy must inform the budget; LRU alone cannot guarantee hits.
|
||||
|
||||
### Reproduce and limitations
|
||||
|
||||
Node v24.14.1, Linux, Intel Xeon E312xx (Sandy Bridge, IBRS update), 12 logical CPUs. This is a shared host with background load, warm OS page cache, loopback HTTP and a synthetic 20 ms upstream wait. It excludes real upstream bandwidth, TLS, reverse proxies, database authorization, multi-process throughput and production request distributions. Small samples and fixed scenario order mean p95 and speedup ratios are descriptive. An initial ts-node exploration was superseded by the compiled results below. The metadata probe does no worker execution, and excludes TypeScript loading from its timed samples.
|
||||
|
||||
```sh
|
||||
npx tsc --incremental false
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js docs/cache-performance-normal-results.json --normal
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js docs/cache-performance-legacy-results.json --legacy
|
||||
node scripts/cache-index-performance.js
|
||||
```
|
||||
|
||||
All 2,700 HTTP responses were checked against expected bytes or a validated wire digest. Eviction assertions passed. Raw latency samples, CPU, RSS, event-loop delay, storage and metric counters are in `cache-performance-results.json`, `cache-performance-normal-results.json`, `cache-performance-legacy-results.json` and `cache-index-performance-results.json`. `cache-performance-summary.json` contains pooled comparisons.
|
||||
|
||||
Before rollout: reduce per-read durable commits without weakening active-reader eviction protection; consider NORMAL only for rebuildable indexes with crash/recovery tests; replace full admin stats scans with cached aggregates; then replay a representative mixed workload with several server processes. Application defaults and production were not changed by this evaluation.
|
||||
|
||||
|
||||
## Optimized implementation, 2026-11-02
|
||||
|
||||
The pool now uses NORMAL WAL commits for reader leases, coarsened access history,
|
||||
anonymization decisions and telemetry. Admission reservations, publication intent
|
||||
before rename, and final blob/alias publication still use FULL commits. Payload
|
||||
fsync remains in place. Reader leases still become visible immediately to other
|
||||
processes and protect active streams from eviction. This saves hit-path disk
|
||||
flushes without making payload accounting depend on disposable history.
|
||||
|
||||
Recent disposable metadata and telemetry can be lost after system failure.
|
||||
Reservation and publication recovery conservatively retain accounting until files
|
||||
are indexed or removed; missing payload files are invalidated and fetched again.
|
||||
The SIGKILL test stops an actual producer after rename and before index publication,
|
||||
then verifies reservation retention, orphan cleanup and successful refill. This
|
||||
tests process failure, not a physical power cut.
|
||||
|
||||
Admin pool statistics now read transactional counters and an indexed oldest-access
|
||||
lookup. Counters are initialized once for an existing index and maintained by
|
||||
SQLite triggers in the same transactions as row changes. Decision/history/alias
|
||||
retention deletes only excess rows through indexes. Expired decision/history
|
||||
cleanup is limited to 256 rows each per admission or maintenance pass. Access
|
||||
history persists at most once per key per 30 seconds, so reuse-window boundaries
|
||||
have that resolution. Metadata remains capped at 100,000 decisions/history rows
|
||||
and 200,000 aliases per pool.
|
||||
|
||||
Stop all cache-using processes together before upgrading an existing index, then
|
||||
restart them on the same version. Do not mix old and new writers during migration.
|
||||
The admin API response shape is unchanged. Shared caching remains opt-in with
|
||||
`SHARED_CACHE_ENABLED=true`; production configuration was not changed.
|
||||
|
||||
The tradeoff is intentional: cache hits avoid durable flushes, while cold fills
|
||||
still pay for durable publication and compression. Trigger updates add a small
|
||||
amount of write work in exchange for constant-time aggregate reads. Approximate
|
||||
LRU and fixed budgets can still thrash when the working set exceeds the pool.
|
||||
|
||||
|
||||
### Follow-up measurements and validation
|
||||
|
||||
All 2,200 responses in the complete optimized HTTP run and all 300 in the focused
|
||||
repeat matched expected output. The repeat ran after this task's other tests and
|
||||
benchmarks ended. The early scenarios in the complete run overlapped the metadata
|
||||
probe, so both results are retained rather than treating the faster run as a
|
||||
universal estimate. These remain small synthetic samples on a shared host.
|
||||
|
||||
- 16 KiB changed text: warm serial median 44.9 → 7.3 ms; eight-client p95 462.1 → 114.9 ms.
|
||||
- 256 KiB changed text: warm serial median 45.9 → 9.0 ms; eight-client p95 444.1 → 107.6 ms.
|
||||
- 2048 KiB changed text: warm serial median 60.5 → 19.0 ms; eight-client p95 528.2 → 216.2 ms.
|
||||
|
||||
At 100,000 synthetic blob rows, admin stats p95 fell from 78.70 to 0.50 ms,
|
||||
decision-write p95 from 45.47 to 1.11 ms, and warm-source-hit p95 from 82.99 to
|
||||
6.37 ms. The 4 MiB eviction probe peaked at 3,997,696 allocated bytes; all budget
|
||||
assertions passed. Its oversized sequential working set still produced no hits.
|
||||
|
||||
The final full suite recorded 1,065 passing, 159 pending and the existing single
|
||||
error-code translation failure (nine maintenance API codes). New counter,
|
||||
durability-mode and SIGKILL recovery tests passed, as did HTTP and admin UI
|
||||
regressions. TypeScript, scoped lint and diff whitespace checks passed.
|
||||
Production rollout and representative multi-process throughput testing remain
|
||||
outside this local evaluation.
|
||||
|
||||
Reproduce the follow-up without overwriting the original baselines:
|
||||
|
||||
```sh
|
||||
npx tsc
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js docs/cache-performance-optimized-results.json
|
||||
node scripts/cache-index-performance.js docs/cache-index-performance-optimized-results.json
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js docs/cache-performance-optimized-repeat-results.json --shared
|
||||
```
|
||||
|
||||
Raw results and the pooled comparison are in the corresponding
|
||||
`cache-*-optimized-*.json` files.
|
||||
|
||||
### PR integration validation
|
||||
|
||||
Reapplied the cache changes onto main at `d0b217a` in an isolated checkout.
|
||||
The production build and scoped ESLint passed, and 199 cache, HTTP, admin access,
|
||||
HEAD/revalidation and Vue UI tests passed. Integration also covers public
|
||||
submodule origin selection and withholding parent credentials. The historical
|
||||
full-workspace and benchmark measurements above were not rerun as part of this
|
||||
PR preparation.
|
||||
See [Shared blob cache](shared-cache.md) for configuration, storage and quota
|
||||
accounting, admin metrics, production observations, rollout and benchmark commands.
|
||||
@@ -0,0 +1,188 @@
|
||||
# Shared blob cache
|
||||
|
||||
The optional shared filesystem cache stores immutable source content across projects.
|
||||
It uses Node's built-in SQLite module and requires Node 22.15 or newer. All API and
|
||||
streamer processes on one host must mount the same local cache directory. SQLite
|
||||
WAL is not a distributed lock service: do not put this directory on NFS or share
|
||||
it across hosts. S3 storage continues to use the existing storage implementation.
|
||||
|
||||
Enable the integrated implementation with `SHARED_CACHE_ENABLED=true`. The default
|
||||
is false so a code deployment does not silently migrate production data. The other
|
||||
settings are independent rollback controls:
|
||||
|
||||
- `SHARED_CACHE_PATH`: defaults to `.shared-cache-v1` inside `FOLDER`.
|
||||
- `SHARED_CACHE_BYTES`: source pool budget, default 10 GiB.
|
||||
- `SHARED_CACHE_RESULT_BYTES`: transformed output budget, default 512 MiB.
|
||||
- `SHARED_CACHE_MAX_FILE_BYTES`: maximum source admission size, default 32 MiB.
|
||||
- `SHARED_CACHE_FREE_BYTES`: free-device-space reserve, default 1 GiB.
|
||||
- `SHARED_CACHE_LOW_WATER`: eviction target fraction, default 0.9.
|
||||
- `SHARED_CACHE_GZIP`: store gzip when beneficial, default true.
|
||||
- `SHARED_CACHE_GZIP_MIN_SAVING`: minimum fractional saving, default 0.10.
|
||||
- `SHARED_CACHE_DECISIONS`: enable unchanged decisions and changed-output reuse,
|
||||
default true.
|
||||
- `CACHE_MONITORING_ENABLED`: collect cache observations, default true. Monitoring
|
||||
is independent of shared storage and also records legacy cache/inspection events.
|
||||
|
||||
Logical user quotas remain based on repository file sizes. Shared-pool deduplication,
|
||||
compression and eviction do not change user quota usage.
|
||||
|
||||
These are initial limits, not capacity recommendations from the production sample.
|
||||
Restart processes together when changing pool limits. Reserve headroom for SQLite,
|
||||
filesystem directories, existing caches and other application temporary files.
|
||||
The budget accounts for blob allocation with a conservative 4 KiB minimum plus
|
||||
in-flight reservations of three times the maximum object size and a small overhead.
|
||||
Keep each pool budget larger than this reservation. Admission can bypass the cache
|
||||
while other fills/readers occupy the budget. Oversized source objects are streamed
|
||||
without admission, still subject to the application's file-size limit.
|
||||
|
||||
Git blobs are verified against the requested Git SHA before publication. Resolved
|
||||
LFS content is admitted only after verifying both the Git pointer and its SHA-256
|
||||
payload digest and size. Gzip is a representation of the same uncompressed content.
|
||||
Files are written privately, synced and atomically renamed before index publication.
|
||||
Fills and readers have renewable leases. Eviction skips readers, and stale fills
|
||||
are recovered before their reservations are released. LRU access timestamps are
|
||||
coarsened to 30 seconds. Orphan reconciliation runs at most hourly across processes.
|
||||
Alias and reuse-history indexes are bounded; decisions expire after seven days and
|
||||
are capped at 100,000 entries.
|
||||
|
||||
Existing generation caches are read as a migration fallback and verified before
|
||||
promotion. They are not deleted during promotion, so rollback remains possible.
|
||||
The new pool budget does not include legacy copies: monitor total filesystem usage
|
||||
and retire legacy data only after validating rollout. Uploaded ZIP originals and
|
||||
other durable source material are untouched. Repository removal invalidates access
|
||||
and project mappings, while shared blobs remain subject to global eviction.
|
||||
|
||||
The HTTP fast path applies to individual file responses backed by the shared source
|
||||
pool, including small text files. Decisions include content identity, path, project
|
||||
context, all transformation options, generation/revision, mask, hostname and engine
|
||||
version. Unchanged decisions serve the original representation. Changed output has
|
||||
its own bounded pool. Gzip negotiation honors quality values, uses `Vary`, and
|
||||
preserves MIME type. File validators are weak when shared delivery is enabled so
|
||||
identity and gzip representations can revalidate the same logical content. HEAD
|
||||
continues to use metadata only. Range requests receive a complete response; this
|
||||
implementation does not add random access into gzip files. Website rendering keeps
|
||||
its renderer cache; ZIP scans do not admit bulk entries into the source blob pool.
|
||||
|
||||
The admin overview's Cache section reads `/api/admin/cache?minutes=60` behind the
|
||||
existing admin authorization. Windows are 15 minutes, one hour, 24 hours and seven
|
||||
days. SQLite telemetry batches at most 512 groups every five seconds and retains
|
||||
minute aggregates for 48 hours and hourly aggregates for 30 days. No paths, terms,
|
||||
user IDs or blob hashes appear in metric labels. The UI distinguishes unavailable
|
||||
telemetry, dropped events, disabled storage and empty windows. Rows separate file,
|
||||
website, ZIP, background and known-monitor traffic. Monitor classification is an
|
||||
operational heuristic, not a complete bot detector.
|
||||
|
||||
Hit counts and byte hit rates measure source lookups; misses classify first observed
|
||||
keys, known misses and eviction refetches within bounded seven-day history. Reuse
|
||||
intervals are consecutive blob accesses, not distinct people or browser visits.
|
||||
Eviction time measures idle age; codec and inspection timings are elapsed work time,
|
||||
not CPU samples. Cached decisions are separate from actual inspections. Minute and
|
||||
hour boundaries make the displayed windows approximate.
|
||||
|
||||
Run the reproducible acceptance workload with:
|
||||
|
||||
```sh
|
||||
mkdir -p benchmark-results/cache
|
||||
node scripts/cache-workload.js benchmark-results/cache/workload.json
|
||||
npx mocha test/shared-blob-cache.test.js test/shared-cache-http.test.js
|
||||
```
|
||||
|
||||
The JSON report asserts cross-project source reuse, unchanged-decision reuse,
|
||||
changed-output reuse, gzip delivery and budget enforcement. Its compression ratio
|
||||
comes from synthetic text and must not be presented as a production projection.
|
||||
Production rollout should compare request/byte hit rates, eviction refetches, p95
|
||||
latency, upstream errors and free disk over a representative week, with large files,
|
||||
ZIP work and known monitors visible separately.
|
||||
|
||||
### Benefits and costs
|
||||
|
||||
| Choice | Benefit | Cost or limit |
|
||||
| --- | --- | --- |
|
||||
| Global content identity | Reuses identical files across paths and projects; renames do not duplicate content | Requires verified hashes and authorization on every request; uses digest-prefix directories to avoid one huge directory |
|
||||
| Byte budget with approximate LRU | Predictable blob footprint and automatic reclamation | Evicted files incur upstream fetches; active readers can temporarily prevent admission |
|
||||
| Selective gzip | Reduces payload storage and can serve compressed bytes directly | First-fill compression costs work; identity consumers and uncached anonymization require decoding |
|
||||
| Rule-aware decisions and results | Repeated unchanged reads skip regex inspection; changed output is reusable | More metadata and a separate output budget; settings changes produce new decisions |
|
||||
| SQLite coordination and telemetry | Cross-process coordination without another service; admin can measure actual reuse and rewrite work | Local-filesystem scope; short synchronous transactions; metadata/headroom are outside blob budgets |
|
||||
|
||||
### Rollout sequence
|
||||
|
||||
1. Deploy with shared storage disabled and collect legacy hits, inspections and codec
|
||||
timings. Keep known-monitor traffic separate from file readers.
|
||||
2. Enable the shared cache on the single-host filesystem deployment with both byte
|
||||
budgets configured. Keep legacy copies for rollback.
|
||||
3. Compare a representative week of byte/request hits, rewrite decisions, eviction
|
||||
refetches, request latency, upstream errors and whole-device free space. Adjust
|
||||
admission size and budgets from those observations.
|
||||
4. Retire legacy cache copies only after the rollback window. Uploaded originals
|
||||
remain durable and are never candidates for shared-pool eviction.
|
||||
|
||||
The implementation and acceptance workload are local changes; this work does not
|
||||
enable or migrate production storage.
|
||||
|
||||
### Production observations used for this design
|
||||
|
||||
The read-only audit on 2026-11-02 found 425,312 source files across 31,522 projects,
|
||||
containing 144.32 GB of payload. Deduplication within projects could remove 1.87 GB;
|
||||
global deduplication could remove 2.93 GB total (about 2.03%), including another
|
||||
1.06 GB across projects. One file could not be read. These are decimal GB and
|
||||
payload savings, not a compression estimate or the expected new working-set size.
|
||||
|
||||
The preceding 24-hour access sample contained 29,980 successful file-body responses,
|
||||
including 9,249 repeat responses (30.9%). URL repetitions are not the same as blob
|
||||
cache hits. A separate approximately two-hour metric window recorded 2,302 source
|
||||
hits out of 3,600 lookups (63.9%). This supports retaining a bounded source cache;
|
||||
it does not establish the optimal byte budget.
|
||||
|
||||
In the uniform anonymization replay, 937 resident files were measured: 764 text,
|
||||
173 binary, and 21 with changed output. Thirteen resolved files exceeded the 4 MiB
|
||||
sample limit, and missing files/mappings were excluded. The sample's mean gzip-6
|
||||
work was 1.46 ms per file and mean decompression was 0.24 ms; these replay timings
|
||||
are not live-request latency or a forecast for large files. Continuous telemetry is
|
||||
needed to replace these samples with representative workload measurements.
|
||||
|
||||
### Metadata durability and accounting
|
||||
|
||||
Reader leases, access history, decisions and telemetry use NORMAL WAL commits.
|
||||
Reservations, publication intent and final blob publication use FULL commits;
|
||||
payloads are synced before rename. Recent disposable metadata may be lost after
|
||||
system failure. Recovery retains reservations until orphan files are removed or
|
||||
accounted for. SIGKILL recovery is tested; physical power failure is not simulated.
|
||||
|
||||
Admin statistics use transactional counters and an indexed oldest-access lookup.
|
||||
History and decisions are capped at 100,000 rows each, aliases at 200,000. Expired
|
||||
history/decision cleanup removes at most 256 rows per pass. Access history has
|
||||
30-second resolution. Stop all cache processes before upgrading an existing index
|
||||
and restart them on the same version; do not mix old and new writers.
|
||||
|
||||
### Performance and validation
|
||||
|
||||
Local synthetic measurements on Node 24.14.1, dated 2026-11-02, compared the initial
|
||||
FULL-commit implementation with optimized bookkeeping. Warm serial changed-text
|
||||
medians fell from 44.9 to 7.3 ms at 16 KiB, 45.9 to 9.0 ms at 256 KiB, and 60.5 to
|
||||
19.0 ms at 2 MiB. At 100,000 synthetic blob rows, admin stats p95 fell from 78.7 to
|
||||
0.50 ms and decision-write p95 from 45.5 to 1.11 ms.
|
||||
|
||||
The optimized runs verified 2,500 HTTP responses. The 4 MiB eviction probe peaked
|
||||
at 3,997,696 allocated bytes. Its oversized sequential working set had no hits:
|
||||
a bounded LRU cache does not guarantee useful reuse. Measurements used loopback
|
||||
HTTP, warm OS caches and a shared host; they exclude production traffic, TLS,
|
||||
authorization overhead and multi-process throughput. They are not capacity estimates.
|
||||
|
||||
On the PR checkout based on main at d0b217a, the production build, scoped lint and
|
||||
199 cache, HTTP, admin access, HEAD/revalidation and Vue UI tests passed. Coverage
|
||||
includes process crash recovery, concurrent fills, active readers, LFS verification,
|
||||
and public submodule origins without parent credentials. Admin layout was also
|
||||
checked at 1280 px and 390 px during implementation.
|
||||
|
||||
Generate fresh reports locally; generated output is ignored by Git:
|
||||
|
||||
```sh
|
||||
npx tsc
|
||||
node scripts/cache-index-performance.js
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js
|
||||
CACHE_BENCH_COMPILED=1 node scripts/cache-performance.js benchmark-results/cache/repeat.json --shared
|
||||
```
|
||||
|
||||
Default reports go to `benchmark-results/cache/`. Scripts also accept an explicit
|
||||
output path. Keep raw measurements with the evaluation that produced them rather
|
||||
than committing generated reports to the documentation directory.
|
||||
Reference in new issue
Block a user