Under a parked transaction, an owner that recreates a child runs twice per mainline write (zombie rerun notifies through the A30-kept tail before the commit trims it)
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 68/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- frontend, performance
調査の方向性
packages/signals/src/scheduler.ts の ambient な parked-transaction パスから始め、特に runHeap と finalizePureQueue を確認し、core.ts の owner-height の挙動をレビューします。packages/signals/tests/zombie-recompute-keeps-flag.test.ts を実行してから、lane-outside-view.test.ts と transition-orphan-recompute.test.ts の関連するケースを比較します。実行回数の上限が controlRuns に達し、その一方で関連する zombie-update テストの両方が引き続き成功すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Found while fixing #3543. Not a leak, values are identical, but it is a 2× cost on a common shape for as long as any action is pending.
What happens
While any transaction is parked, an owner that recreates a child each pass — a compiled <Show when={n() > 0 && n() < 2}> condition, whose getter is memo(() => n() > 0)() && n() < 2 — runs twice per mainline write, creating and disposing an extra child each time. The zombie child itself runs once.
Per write to n, in the ambient flush (activeTransition === null, transitions.size > 0), from an instrumented run of packages/signals/tests/zombie-recompute-keeps-flag.test.ts:
runHeap(dirtyQueue)(scheduler.ts:796): the ownerPrecomputes first (a child the owner creates doesn't lift the owner's height,core.ts:1962). It zombifies the old childC1— stillDIRTY|IN_HEAPfrom the write, somarkDisposalmigrates it tozombieQueue— createsC2, stages,queuePendingNode(P).runHeap(zombieQueue)(scheduler.ts:875):C1reruns as a zombie. Its value changed, soinsertSubsnotifies its subscribers — andPis still one, because A30 (#3469, 27b24aa06) keeps a staged pass's previous dep tail linked until the commit trims it.finalizePureQueue():commitPendingNodes()disposesC1and trimsP's tail — afterPis already dirty. TherunHeapatscheduler.ts:1323recomputesPagain with identical inputs: zombifiesC2, createsC3, commits again.
Measured on that test: 40 alternating writes cost 60 nested-memo runs with no transaction parked and 100 with one parked — the extra 40 are 20 zombie reruns plus 20 second-pass creations. Both are waste: P's staged value from step 1 already reflects the new n, and nothing ever renders C1's rerun.
Why A30 is not the problem
A30 is right to keep the tail: at recompute time nobody knows whether this flush will park, and if it does, the committed frame (which derives from C1) stays on screen and must keep receiving writes (#3469, #3410). The tail dep in #3469 is a live signal written in a later flush — that is the case A30 exists for. Here the tail dep is a zombie that reruns inside the same flush, a few lines before the commit that disposes it. Trimming earlier reopens #3469.
Proposal
Zombies whose owner commits this flush should not rerun before that commit. Concretely, in the ambient-with-parked-transactions branch, commit pending nodes before running the zombie queue (or run the zombie queue after finalizePureQueue and before the effect phases). A zombie whose owner commits is disposed by the commit and never reruns — which is already what happens when no transaction is parked (zombieQueue isn't run at all). Only zombies of actually-parked owners rerun, which is what :875 is for (#2916, #3463), and their owners' tails are legitimately kept.
Alternative if the ordering is load-bearing elsewhere: in insertSubs, skip a subscriber whose link to the notifying node lies past its _depsTail (a held-trim tail) when the notifier is a zombie — the notification is to a frame this flush is replacing, not to the live pass. Narrower, but it leaves the pointless zombie rerun in place.
Acceptance: the run-count bound in zombie-recompute-keeps-flag.test.ts (controlRuns + 40, currently exact) tightens to controlRuns; lane-outside-view.test.ts (#3463) and transition-orphan-recompute.test.ts ("still updates zombies for mainline writes in a separate flush") stay green.
Related: #3543 (the flag loss this surfaced), #3469 / A30, #3463, #3410.
- 主要言語
- TypeScript
- スター
- 36.1k
- フォーク
- 1.1k
- 平均マージ
- 11時間 42分
- マージ済み PR(30日)
- 326
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
solidjs/solid のほかの issue
-
[2.0 next, regressed after rc.13] Async-generator action times out on its authoritative live echoオープン
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 半日 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 64/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
Bump Firebase JS SDK (12.19.0 → 13.0.0)対応中かも @SelaseKay が今日担当しました。 オープンNeeds Attention type: enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
invertase/react-native-firebase#9364 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 4 日以内に返信
-
e2e-failure ready-to-code
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
redhat-developer/rhdh-plugin-export-overlays#4261 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug] 官网文档的图片挂了オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
メンテナーはふだん 1 日以内に返信
-
area:cli bug triage:in-progress
難易度 1/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信