From 694611b727538d78c64d36c320006645ca41ee0b Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 15 Oct 2025 20:12:09 +0200 Subject: [PATCH 1/2] Turbopack: Track errored tasks as dependency when using untracked() --- .../turbo-tasks-backend/src/backend/mod.rs | 49 +++--- .../crates/turbo-tasks-testing/src/lib.rs | 30 +--- turbopack/crates/turbo-tasks/src/backend.rs | 19 +-- turbopack/crates/turbo-tasks/src/lib.rs | 4 +- turbopack/crates/turbo-tasks/src/manager.rs | 145 ++++++++++-------- turbopack/crates/turbo-tasks/src/raw_vc.rs | 73 +++++---- .../crates/turbo-tasks/src/read_options.rs | 9 ++ 7 files changed, 173 insertions(+), 156 deletions(-) diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs index ab823703f720f..f26b6f6e4129a 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs @@ -28,8 +28,8 @@ use tokio::time::{Duration, Instant}; use tracing::{Span, field::Empty, info_span, trace_span}; use turbo_tasks::{ CellId, FxDashMap, FxIndexMap, KeyValuePair, RawVc, ReadCellOptions, ReadConsistency, - SessionId, TRANSIENT_TASK_BIT, TaskExecutionReason, TaskId, TraitTypeId, TurboTasksBackendApi, - ValueTypeId, + ReadOutputOptions, ReadTracking, SessionId, TRANSIENT_TASK_BIT, TaskExecutionReason, TaskId, + TraitTypeId, TurboTasksBackendApi, ValueTypeId, backend::{ Backend, CachedTaskType, CellContent, TaskExecutionSpec, TransientTaskRoot, TransientTaskType, TurboTasksExecutionError, TypedCellContent, @@ -458,7 +458,7 @@ impl TurboTasksBackendInner { self: &Arc, task_id: TaskId, reader: Option, - consistency: ReadConsistency, + options: ReadOutputOptions, turbo_tasks: &dyn TurboTasksBackendApi>, ) -> Result> { self.assert_not_persistent_calling_transient(reader, task_id, /* cell_id */ None); @@ -469,15 +469,16 @@ impl TurboTasksBackendInner { fn listen_to_done_event( this: &TurboTasksBackendInner, reader: Option, + tracking: ReadTracking, done_event: &Event, ) -> EventListener { done_event.listen_with_note(move || { let reader_desc = reader.map(|r| this.get_task_desc_fn(r)); move || { if let Some(reader_desc) = reader_desc.as_ref() { - format!("try_read_task_output from {}", reader_desc()) + format!("try_read_task_output from {} ({})", reader_desc(), tracking) } else { - "try_read_task_output (untracked)".to_string() + format!("try_read_task_output ({})", tracking) } } }) @@ -487,16 +488,19 @@ impl TurboTasksBackendInner { this: &TurboTasksBackendInner, task: &impl TaskGuard, reader: Option, + tracking: ReadTracking, ctx: &impl ExecuteContext<'_>, ) -> Option, anyhow::Error>> { match get!(task, InProgress) { - Some(InProgressState::Scheduled { done_event, .. }) => { - Some(Ok(Err(listen_to_done_event(this, reader, done_event)))) - } + Some(InProgressState::Scheduled { done_event, .. }) => Some(Ok(Err( + listen_to_done_event(this, reader, tracking, done_event), + ))), Some(InProgressState::InProgress(box InProgressStateInner { done_event, .. - })) => Some(Ok(Err(listen_to_done_event(this, reader, done_event)))), + })) => Some(Ok(Err(listen_to_done_event( + this, reader, tracking, done_event, + )))), Some(InProgressState::Canceled) => Some(Err(anyhow::anyhow!( "{} was canceled", ctx.get_task_description(task.id()) @@ -505,7 +509,7 @@ impl TurboTasksBackendInner { } } - if matches!(consistency, ReadConsistency::Strong) { + if matches!(options.consistency, ReadConsistency::Strong) { // Ensure it's an root node loop { let aggregation_number = get_aggregation_number(&task); @@ -687,7 +691,7 @@ impl TurboTasksBackendInner { } } - if let Some(value) = check_in_progress(self, &task, reader, &ctx) { + if let Some(value) = check_in_progress(self, &task, reader, options.tracking, &ctx) { return value; } @@ -705,6 +709,7 @@ impl TurboTasksBackendInner { }; if self.should_track_dependencies() && let Some(reader) = reader + && options.tracking.should_track(result.is_err()) && (!task.is_immutable() || cfg!(feature = "verify_immutable")) { let _ = task.add(CachedDataItem::OutputDependent { @@ -810,7 +815,9 @@ impl TurboTasksBackendInner { None }; if let Some(content) = content { - add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + if options.tracking.should_track(false) { + add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + } return Ok(Ok(TypedCellContent( cell.type_id, CellContent(Some(content.reference)), @@ -835,14 +842,18 @@ impl TurboTasksBackendInner { ) .copied(); let Some(max_id) = max_id else { - add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + if options.tracking.should_track(true) { + add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + } bail!( "Cell {cell:?} no longer exists in task {} (no cell of this type exists)", ctx.get_task_description(task_id) ); }; if cell.index >= max_id { - add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + if options.tracking.should_track(true) { + add_cell_dependency(self, task, reader, cell, task_id, &mut ctx); + } bail!( "Cell {cell:?} no longer exists in task {} (index out of bounds)", ctx.get_task_description(task_id) @@ -2457,7 +2468,7 @@ impl TurboTasksBackendInner { }) } - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, task_id: TaskId, cell: CellId, @@ -3139,11 +3150,11 @@ impl Backend for TurboTasksBackend { &self, task_id: TaskId, reader: Option, - consistency: ReadConsistency, + options: ReadOutputOptions, turbo_tasks: &dyn TurboTasksBackendApi, ) -> Result> { self.0 - .try_read_task_output(task_id, reader, consistency, turbo_tasks) + .try_read_task_output(task_id, reader, options, turbo_tasks) } fn try_read_task_cell( @@ -3158,7 +3169,7 @@ impl Backend for TurboTasksBackend { .try_read_task_cell(task_id, reader, cell, options, turbo_tasks) } - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, task_id: TaskId, cell: CellId, @@ -3166,7 +3177,7 @@ impl Backend for TurboTasksBackend { turbo_tasks: &dyn TurboTasksBackendApi, ) -> Result { self.0 - .try_read_own_task_cell_untracked(task_id, cell, options, turbo_tasks) + .try_read_own_task_cell(task_id, cell, options, turbo_tasks) } fn read_task_collectibles( diff --git a/turbopack/crates/turbo-tasks-testing/src/lib.rs b/turbopack/crates/turbo-tasks-testing/src/lib.rs index f01f2fbaf6c19..34564c3e75c3d 100644 --- a/turbopack/crates/turbo-tasks-testing/src/lib.rs +++ b/turbopack/crates/turbo-tasks-testing/src/lib.rs @@ -17,7 +17,7 @@ use rustc_hash::FxHashMap; use tokio::sync::mpsc::Receiver; use turbo_tasks::{ CellId, ExecutionId, InvalidationReason, LocalTaskId, MagicAny, RawVc, ReadCellOptions, - ReadConsistency, TaskId, TaskPersistence, TraitTypeId, TurboTasksApi, TurboTasksCallApi, + ReadOutputOptions, TaskId, TaskPersistence, TraitTypeId, TurboTasksApi, TurboTasksCallApi, backend::{CellContent, TaskCollectiblesMap, TypedCellContent}, event::{Event, EventListener}, message_queue::CompilationEvent, @@ -176,7 +176,7 @@ impl TurboTasksApi for VcStorage { fn try_read_task_output( &self, id: TaskId, - _consistency: ReadConsistency, + _options: ReadOutputOptions, ) -> Result> { let tasks = self.tasks.lock().unwrap(); let i = *id - 1; @@ -190,14 +190,6 @@ impl TurboTasksApi for VcStorage { } } - fn try_read_task_output_untracked( - &self, - task: TaskId, - consistency: ReadConsistency, - ) -> Result> { - self.try_read_task_output(task, consistency) - } - fn try_read_task_cell( &self, task: TaskId, @@ -212,23 +204,7 @@ impl TurboTasksApi for VcStorage { } .into_typed(index.type_id))) } - - fn try_read_task_cell_untracked( - &self, - task: TaskId, - index: CellId, - _options: ReadCellOptions, - ) -> Result> { - let map = self.cells.lock().unwrap(); - Ok(Ok(if let Some(cell) = map.get(&(task, index)) { - cell.to_owned() - } else { - Default::default() - } - .into_typed(index.type_id))) - } - - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, current_task: TaskId, index: CellId, diff --git a/turbopack/crates/turbo-tasks/src/backend.rs b/turbopack/crates/turbo-tasks/src/backend.rs index 018fc1c579b90..70f4147aa166a 100644 --- a/turbopack/crates/turbo-tasks/src/backend.rs +++ b/turbopack/crates/turbo-tasks/src/backend.rs @@ -17,16 +17,11 @@ use tracing::Span; use turbo_rcstr::RcStr; use crate::{ - RawVc, ReadCellOptions, ReadRef, SharedReference, TaskId, TaskIdSet, TraitRef, TraitTypeId, - TurboTasksPanic, ValueTypeId, VcRead, VcValueTrait, VcValueType, - event::EventListener, - macro_helpers::NativeFunction, - magic_any::MagicAny, - manager::{ReadConsistency, TurboTasksBackendApi}, - raw_vc::CellId, - registry, - task::shared_reference::TypedSharedReference, - task_statistics::TaskStatisticsApi, + RawVc, ReadCellOptions, ReadOutputOptions, ReadRef, SharedReference, TaskId, TaskIdSet, + TraitRef, TraitTypeId, TurboTasksPanic, ValueTypeId, VcRead, VcValueTrait, VcValueType, + event::EventListener, macro_helpers::NativeFunction, magic_any::MagicAny, + manager::TurboTasksBackendApi, raw_vc::CellId, registry, + task::shared_reference::TypedSharedReference, task_statistics::TaskStatisticsApi, triomphe_utils::unchecked_sidecast_triomphe_arc, }; @@ -564,7 +559,7 @@ pub trait Backend: Sync + Send { &self, task: TaskId, reader: Option, - consistency: ReadConsistency, + options: ReadOutputOptions, turbo_tasks: &dyn TurboTasksBackendApi, ) -> Result>; @@ -581,7 +576,7 @@ pub trait Backend: Sync + Send { /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, current_task: TaskId, index: CellId, diff --git a/turbopack/crates/turbo-tasks/src/lib.rs b/turbopack/crates/turbo-tasks/src/lib.rs index fd7accad9472d..7cbb05bfd780f 100644 --- a/turbopack/crates/turbo-tasks/src/lib.rs +++ b/turbopack/crates/turbo-tasks/src/lib.rs @@ -108,14 +108,14 @@ pub use join_iter_ext::{JoinIterExt, TryFlatJoinIterExt, TryJoinIterExt}; pub use key_value_pair::KeyValuePair; pub use magic_any::MagicAny; pub use manager::{ - CurrentCellRef, ReadConsistency, TaskPersistence, TurboTasks, TurboTasksApi, + CurrentCellRef, ReadConsistency, ReadTracking, TaskPersistence, TurboTasks, TurboTasksApi, TurboTasksBackendApi, TurboTasksCallApi, Unused, UpdateInfo, dynamic_call, emit, mark_finished, mark_root, mark_session_dependent, mark_stateful, prevent_gc, run, run_once, run_once_with_reason, trait_call, turbo_tasks, turbo_tasks_scope, }; pub use output::OutputContent; pub use raw_vc::{CellId, RawVc, ReadRawVcFuture, ResolveTypeError}; -pub use read_options::ReadCellOptions; +pub use read_options::{ReadCellOptions, ReadOutputOptions}; pub use read_ref::ReadRef; use rustc_hash::FxHasher; pub use serialization_invalidation::SerializationInvalidator; diff --git a/turbopack/crates/turbo-tasks/src/manager.rs b/turbopack/crates/turbo-tasks/src/manager.rs index 9ac93282ccc61..d32500ba675c4 100644 --- a/turbopack/crates/turbo-tasks/src/manager.rs +++ b/turbopack/crates/turbo-tasks/src/manager.rs @@ -1,4 +1,5 @@ use std::{ + fmt::Display, future::Future, hash::BuildHasherDefault, mem::take, @@ -20,8 +21,8 @@ use tracing::{Instrument, instrument}; use crate::{ Completion, InvalidationReason, InvalidationReasonSet, OutputContent, ReadCellOptions, - ResolvedVc, SharedReference, TaskId, TraitMethod, ValueTypeId, Vc, VcRead, VcValueTrait, - VcValueType, + ReadOutputOptions, ResolvedVc, SharedReference, TaskId, TraitMethod, ValueTypeId, Vc, VcRead, + VcValueTrait, VcValueType, backend::{ Backend, CachedTaskType, CellContent, TaskCollectiblesMap, TaskExecutionSpec, TransientTaskType, TurboTasksExecutionError, TypedCellContent, @@ -103,15 +104,7 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { fn try_read_task_output( &self, task: TaskId, - consistency: ReadConsistency, - ) -> Result>; - - /// INVALIDATION: Be careful with this, it will not track dependencies, so - /// using it could break cache invalidation. - fn try_read_task_output_untracked( - &self, - task: TaskId, - consistency: ReadConsistency, + options: ReadOutputOptions, ) -> Result>; fn try_read_task_cell( @@ -121,15 +114,6 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { options: ReadCellOptions, ) -> Result>; - /// INVALIDATION: Be careful with this, it will not track dependencies, so - /// using it could break cache invalidation. - fn try_read_task_cell_untracked( - &self, - task: TaskId, - index: CellId, - options: ReadCellOptions, - ) -> Result>; - /// Reads a [`RawVc::LocalOutput`]. If the task has completed, returns the [`RawVc`] the local /// task points to. /// @@ -158,7 +142,7 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, current_task: TaskId, index: CellId, @@ -301,10 +285,11 @@ pub enum TaskPersistence { Local, } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] pub enum ReadConsistency { /// The default behavior for most APIs. Reads are faster, but may return stale values, which /// may later trigger re-computation. + #[default] Eventual, /// Ensures all dependencies are fully resolved before returning the cell or output data, at /// the cost of slower reads. @@ -313,6 +298,43 @@ pub enum ReadConsistency { Strong, } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] +pub enum ReadTracking { + /// Reads are tracked as dependencies of the current task. + #[default] + Tracked, + /// The read is only tracked when there is an error, otherwise it is untracked. + /// + /// INVALIDATION: Be careful with this, it will not track dependencies, so + /// using it could break cache invalidation. + TrackOnlyError, + /// The read is not tracked as a dependency of the current task. + /// + /// INVALIDATION: Be careful with this, it will not track dependencies, so + /// using it could break cache invalidation. + Untracked, +} + +impl ReadTracking { + pub fn should_track(&self, is_err: bool) -> bool { + match self { + ReadTracking::Tracked => true, + ReadTracking::TrackOnlyError => is_err, + ReadTracking::Untracked => false, + } + } +} + +impl Display for ReadTracking { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ReadTracking::Tracked => write!(f, "tracked"), + ReadTracking::TrackOnlyError => write!(f, "track only error"), + ReadTracking::Untracked => write!(f, "untracked"), + } + } +} + pub struct TurboTasks { this: Weak, backend: B, @@ -927,8 +949,16 @@ impl TurboTasks { id: TaskId, consistency: ReadConsistency, ) -> Result<()> { - // INVALIDATION: This doesn't return a value, only waits for it to be ready. - read_task_output_untracked(self, id, consistency).await?; + read_task_output( + self, + id, + ReadOutputOptions { + // INVALIDATION: This doesn't return a value, only waits for it to be ready. + tracking: ReadTracking::Untracked, + consistency, + }, + ) + .await?; Ok(()) } @@ -1217,25 +1247,16 @@ impl TurboTasksApi for TurboTasks { fn try_read_task_output( &self, task: TaskId, - consistency: ReadConsistency, + options: ReadOutputOptions, ) -> Result> { self.backend.try_read_task_output( task, current_task_if_available("reading Vcs"), - consistency, + options, self, ) } - fn try_read_task_output_untracked( - &self, - task: TaskId, - consistency: ReadConsistency, - ) -> Result> { - self.backend - .try_read_task_output(task, None, consistency, self) - } - fn try_read_task_cell( &self, task: TaskId, @@ -1251,24 +1272,14 @@ impl TurboTasksApi for TurboTasks { ) } - fn try_read_task_cell_untracked( - &self, - task: TaskId, - index: CellId, - options: ReadCellOptions, - ) -> Result> { - self.backend - .try_read_task_cell(task, index, None, options, self) - } - - fn try_read_own_task_cell_untracked( + fn try_read_own_task_cell( &self, current_task: TaskId, index: CellId, options: ReadCellOptions, ) -> Result { self.backend - .try_read_own_task_cell_untracked(current_task, index, options, self) + .try_read_own_task_cell(current_task, index, options, self) } fn try_read_local_output( @@ -1340,8 +1351,7 @@ impl TurboTasksApi for TurboTasks { index: CellId, options: ReadCellOptions, ) -> Result { - // INVALIDATION: don't need to track a dependency to itself - self.try_read_own_task_cell_untracked(task, index, options) + self.try_read_own_task_cell(task, index, options) } fn update_own_task_cell(&self, task: TaskId, index: CellId, content: CellContent) { @@ -1686,25 +1696,10 @@ pub fn emit(collectible: ResolvedVc) { pub(crate) async fn read_task_output( this: &dyn TurboTasksApi, id: TaskId, - consistency: ReadConsistency, + options: ReadOutputOptions, ) -> Result { loop { - match this.try_read_task_output(id, consistency)? { - Ok(result) => return Ok(result), - Err(listener) => listener.await, - } - } -} - -/// INVALIDATION: Be careful with this, it will not track dependencies, so -/// using it could break cache invalidation. -pub(crate) async fn read_task_output_untracked( - this: &dyn TurboTasksApi, - id: TaskId, - consistency: ReadConsistency, -) -> Result { - loop { - match this.try_read_task_output_untracked(id, consistency)? { + match this.try_read_task_output(id, options)? { Ok(result) => return Ok(result), Err(listener) => listener.await, } @@ -1762,7 +1757,14 @@ impl CurrentCellRef { ) { let tt = turbo_tasks(); let cell_content = tt - .read_own_task_cell(self.current_task, self.index, ReadCellOptions::default()) + .read_own_task_cell( + self.current_task, + self.index, + ReadCellOptions { + tracking: ReadTracking::Untracked, + ..Default::default() + }, + ) .ok(); let update = functor(cell_content.as_ref().and_then(|cc| cc.1.0.as_ref())); if let Some(update) = update { @@ -1873,7 +1875,14 @@ impl CurrentCellRef { pub fn update_with_shared_reference(&self, shared_ref: SharedReference) { let tt = turbo_tasks(); let content = tt - .read_own_task_cell(self.current_task, self.index, ReadCellOptions::default()) + .read_own_task_cell( + self.current_task, + self.index, + ReadCellOptions { + tracking: ReadTracking::Untracked, + ..Default::default() + }, + ) .ok(); let update = if let Some(TypedCellContent(_, CellContent(Some(shared_ref_exp)))) = content { // pointer equality (not value equality) diff --git a/turbopack/crates/turbo-tasks/src/raw_vc.rs b/turbopack/crates/turbo-tasks/src/raw_vc.rs index 7a995445b32aa..f378d260d9a62 100644 --- a/turbopack/crates/turbo-tasks/src/raw_vc.rs +++ b/turbopack/crates/turbo-tasks/src/raw_vc.rs @@ -11,12 +11,14 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::{ - CollectiblesSource, ReadCellOptions, ReadConsistency, ResolvedVc, TaskId, TaskPersistence, - TraitTypeId, ValueType, ValueTypeId, VcValueTrait, + CollectiblesSource, ReadCellOptions, ReadConsistency, ReadOutputOptions, ResolvedVc, TaskId, + TaskPersistence, TraitTypeId, ValueType, ValueTypeId, VcValueTrait, backend::{CellContent, TypedCellContent}, event::EventListener, id::{ExecutionId, LocalTaskId}, - manager::{read_local_output, read_task_cell, read_task_output, with_turbo_tasks}, + manager::{ + ReadTracking, read_local_output, read_task_cell, read_task_output, with_turbo_tasks, + }, registry::{self, get_value_type}, turbo_tasks, }; @@ -170,7 +172,7 @@ impl RawVc { loop { match current { RawVc::TaskOutput(task) => { - current = read_task_output(&*tt, task, ReadConsistency::Eventual) + current = read_task_output(&*tt, task, ReadOutputOptions::default()) .await .map_err(|source| ResolveTypeError::TaskError { source })?; } @@ -199,29 +201,37 @@ impl RawVc { /// See [`crate::Vc::resolve`]. pub(crate) async fn resolve(self) -> Result { - self.resolve_inner(ReadConsistency::Eventual).await + self.resolve_inner(ReadOutputOptions { + tracking: ReadTracking::default(), + consistency: ReadConsistency::Eventual, + }) + .await } /// See [`crate::Vc::resolve_strongly_consistent`]. pub(crate) async fn resolve_strongly_consistent(self) -> Result { - self.resolve_inner(ReadConsistency::Strong).await + self.resolve_inner(ReadOutputOptions { + tracking: ReadTracking::default(), + consistency: ReadConsistency::Strong, + }) + .await } - async fn resolve_inner(self, mut consistency: ReadConsistency) -> Result { + async fn resolve_inner(self, mut options: ReadOutputOptions) -> Result { let tt = turbo_tasks(); let mut current = self; loop { match current { RawVc::TaskOutput(task) => { - current = read_task_output(&*tt, task, consistency).await?; + current = read_task_output(&*tt, task, options).await?; // We no longer need to read strongly consistent, as any Vc returned // from the first task will be inside of the scope of the first // task. So it's already strongly consistent. - consistency = ReadConsistency::Eventual; + options.consistency = ReadConsistency::Eventual; } RawVc::TaskCell(_, _) => return Ok(current), RawVc::LocalOutput(execution_id, local_task_id, ..) => { - debug_assert_eq!(consistency, ReadConsistency::Eventual); + debug_assert_eq!(options.consistency, ReadConsistency::Eventual); current = read_local_output(&*tt, execution_id, local_task_id).await?; } } @@ -331,9 +341,8 @@ impl CollectiblesSource for RawVc { } pub struct ReadRawVcFuture { - consistency: ReadConsistency, current: RawVc, - untracked: bool, + read_output_options: ReadOutputOptions, read_cell_options: ReadCellOptions, listener: Option, } @@ -341,23 +350,35 @@ pub struct ReadRawVcFuture { impl ReadRawVcFuture { pub(crate) fn new(vc: RawVc) -> Self { ReadRawVcFuture { - consistency: ReadConsistency::Eventual, current: vc, - untracked: false, + read_output_options: ReadOutputOptions::default(), read_cell_options: ReadCellOptions::default(), listener: None, } } pub fn strongly_consistent(mut self) -> Self { - self.consistency = ReadConsistency::Strong; + self.read_output_options.consistency = ReadConsistency::Strong; self } + /// This will not track the value as dependency, but will still track the error as dependency, + /// if there is an error. + /// /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. pub fn untracked(mut self) -> Self { - self.untracked = true; + self.read_output_options.tracking = ReadTracking::TrackOnlyError; + self + } + + /// This will not track the value or the error as dependency. + /// Make sure to handle eventual consistency errors. + /// + /// INVALIDATION: Be careful with this, it will not track dependencies, so + /// using it could break cache invalidation. + pub fn untracked_including_errors(mut self) -> Self { + self.read_output_options.tracking = ReadTracking::Untracked; self } @@ -385,17 +406,13 @@ impl Future for ReadRawVcFuture { } let mut listener = match this.current { RawVc::TaskOutput(task) => { - let read_result = if this.untracked { - tt.try_read_task_output_untracked(task, this.consistency) - } else { - tt.try_read_task_output(task, this.consistency) - }; + let read_result = tt.try_read_task_output(task, this.read_output_options); match read_result { Ok(Ok(vc)) => { // We no longer need to read strongly consistent, as any Vc returned // from the first task will be inside of the scope of the first // task. So it's already strongly consistent. - this.consistency = ReadConsistency::Eventual; + this.read_output_options.consistency = ReadConsistency::Eventual; this.current = vc; continue 'outer; } @@ -404,11 +421,8 @@ impl Future for ReadRawVcFuture { } } RawVc::TaskCell(task, index) => { - let read_result = if this.untracked { - tt.try_read_task_cell_untracked(task, index, this.read_cell_options) - } else { - tt.try_read_task_cell(task, index, this.read_cell_options) - }; + let read_result = + tt.try_read_task_cell(task, index, this.read_cell_options); match read_result { Ok(Ok(content)) => { // SAFETY: Constructor ensures that T and U are binary identical @@ -419,7 +433,10 @@ impl Future for ReadRawVcFuture { } } RawVc::LocalOutput(execution_id, local_output_id, ..) => { - debug_assert_eq!(this.consistency, ReadConsistency::Eventual); + debug_assert_eq!( + this.read_output_options.consistency, + ReadConsistency::Eventual + ); let read_result = tt.try_read_local_output(execution_id, local_output_id); match read_result { Ok(Ok(vc)) => { diff --git a/turbopack/crates/turbo-tasks/src/read_options.rs b/turbopack/crates/turbo-tasks/src/read_options.rs index fcf2280421f5e..3c08fe3a3b72b 100644 --- a/turbopack/crates/turbo-tasks/src/read_options.rs +++ b/turbopack/crates/turbo-tasks/src/read_options.rs @@ -1,4 +1,13 @@ +use crate::{ReadConsistency, ReadTracking}; + #[derive(Clone, Copy, Debug, Default)] pub struct ReadCellOptions { + pub tracking: ReadTracking, pub final_read_hint: bool, } + +#[derive(Clone, Copy, Debug, Default)] +pub struct ReadOutputOptions { + pub tracking: ReadTracking, + pub consistency: ReadConsistency, +} From 78962984ca658e87c6a161ffc558daf2bbae18f5 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 17 Oct 2025 04:57:17 +0200 Subject: [PATCH 2/2] fixup cell tracking --- turbopack/crates/turbo-tasks/src/raw_vc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/turbopack/crates/turbo-tasks/src/raw_vc.rs b/turbopack/crates/turbo-tasks/src/raw_vc.rs index f378d260d9a62..2fe020c30c2ab 100644 --- a/turbopack/crates/turbo-tasks/src/raw_vc.rs +++ b/turbopack/crates/turbo-tasks/src/raw_vc.rs @@ -369,6 +369,7 @@ impl ReadRawVcFuture { /// using it could break cache invalidation. pub fn untracked(mut self) -> Self { self.read_output_options.tracking = ReadTracking::TrackOnlyError; + self.read_cell_options.tracking = ReadTracking::TrackOnlyError; self } @@ -379,6 +380,7 @@ impl ReadRawVcFuture { /// using it could break cache invalidation. pub fn untracked_including_errors(mut self) -> Self { self.read_output_options.tracking = ReadTracking::Untracked; + self.read_cell_options.tracking = ReadTracking::Untracked; self }