Repository navigation
turbo-tasks: add lazy cell reads via LazyReadRef - #101008
Draft
lukesandberg wants to merge 2 commits into
Draft
lukesandberg wants to merge 2 commits into
lukesandberg wants to merge 2 commits into
Conversation
Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
Contributor
Tests PassedCommit: 3038a78 |
Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Adds
vc.lazy_reader().await?, which returns aLazyReadRef<T>for any value type. The value is only accessible through an explicitLazyReadRef::get().get()ever being called, the dependency registered by this read is removed. That proves the task doesn't depend on the cell.get()was called, the dependency is kept and becomes a normal full dependency when the execution completes.Stacked on #100884 and reuses its
CellKey::Keyed(id)machinery.Why?
Some tasks need a cell's value only in rare cases, and only find out in synchronous code. One example is the server actions hash salt (encryption key) in #100950: today that needs an optimistic "run without it, bail, re-run with it" strategy. With
lazy_reader(), the task can read the cell up front, pass the ref into synchronous code, and depend on it only when it is actually used.How?
lazy_reader()call gets its ownCellKey::Keyed(id)dependency edge, the same per-execution id thatkeyed()uses.convert_keyed_cell_dependencywith no key hashes, which removes only that edge..await), hashed/keyed reads (get,contains_key,keyed()), and otherLazyReadRefs of the same cell keep their own edges. Mixed reads in one execution therefore behave correctly, in any order.Keyededge in place. The existing completion-time conversion turns it into a normal full dependency.KeyedReadRef, sharing the alive-ref counter. A ref that is leaked or dropped outside the creating execution fails the task with a panic error, and its dependency is kept as a full dependency.poll,get()ordropalso panics at the misuse site.convert_keyed_cell_dependencyand theupdate_cellhandling from turbo-tasks: add batched keyed reads via KeyedReadRef #100884 also apply to removal.Vc-only API:lazy_reader()andkeyed()exist only onVc(so also onResolvedVcvia deref, and onOperationVc::connect()), not on theReadVcFuturebuilder.vc.untracked().lazy_reader()/vc.untracked().keyed()don't make sense, since there is no dependency to cancel or narrow, so they are compile errors. Previouslyvc.untracked().keyed()from turbo-tasks: add batched keyed reads via KeyedReadRef #100884 compiled and silently became a tracked read.keyed()norlazy_reader()don't pay anything new. The completion scan and leak check stay gated on the existing per-execution counter.keyed()andlazy_reader()share one read helper.keyed()behaviour is unchanged.KeyedReadRefandLazyReadRef.turbopack/AGENTS.mdnext to thekeyed()guidance.Adopting this in the server actions transform is a separate follow-up.
Verification
turbopack/crates/turbo-tasks-backend/tests/lazy_read_ref.rs(16 tests) covers:get()and lazy plus batchedkeyed()reads;Debugnot counting as an access;cargo test -p turbo-tasks -p turbo-tasks-backendpasses, including the existingkeyed_read_ref.rs.cargo test --release -p turbo-tasks-backend --test lazy_read_ref --test keyed_read_refpasses, covering the release-mode fallback paths.vc.untracked().lazy_reader()andvc.untracked().keyed()fail with E0599 (no method onReadVcFuture), whilelazy_reader()/keyed()onVcandResolvedVcstill compile.cargo clippy -p turbo-tasks -p turbo-tasks-backend --all-targets -- -D warnings,cargo fmt --check, andRUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --document-private-items -p turbo-tasks -p turbo-tasks-backendpass../scripts/check-rustdoc.sh, and Next.js e2e tests (no consumer is converted in this PR).