@@ -52,7 +52,7 @@ use crate::{
52
52
AggregatedDataUpdate , AggregationUpdateJob , AggregationUpdateQueue ,
53
53
CleanupOldEdgesOperation , ConnectChildOperation , ExecuteContext , ExecuteContextImpl ,
54
54
Operation , OutdatedEdge , TaskGuard , connect_children, get_aggregation_number,
55
- get_uppers, is_root_node, prepare_new_children,
55
+ get_uppers, is_root_node, make_task_dirty_internal , prepare_new_children,
56
56
} ,
57
57
storage:: {
58
58
InnerStorageSnapshot , Storage , count, get, get_many, get_mut, get_mut_or_insert_with,
@@ -420,6 +420,8 @@ struct TaskExecutionCompletePrepareResult {
420
420
pub new_children : FxHashSet < TaskId > ,
421
421
pub removed_data : Vec < CachedDataItem > ,
422
422
pub is_now_immutable : bool ,
423
+ pub new_output : Option < OutputValue > ,
424
+ pub output_dependent_tasks : SmallVec < [ TaskId ; 4 ] > ,
423
425
}
424
426
425
427
// Operations
@@ -493,16 +495,8 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
493
495
Some ( Ok ( Err ( listen_to_done_event ( this, reader, done_event) ) ) )
494
496
}
495
497
Some ( InProgressState :: InProgress ( box InProgressStateInner {
496
- done,
497
- done_event,
498
- ..
499
- } ) ) => {
500
- if !* done {
501
- Some ( Ok ( Err ( listen_to_done_event ( this, reader, done_event) ) ) )
502
- } else {
503
- None
504
- }
505
- }
498
+ done_event, ..
499
+ } ) ) => Some ( Ok ( Err ( listen_to_done_event ( this, reader, done_event) ) ) ) ,
506
500
Some ( InProgressState :: Canceled ) => Some ( Err ( anyhow:: anyhow!(
507
501
"{} was canceled" ,
508
502
ctx. get_task_description( task. id( ) )
@@ -1593,7 +1587,6 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1593
1587
done_event,
1594
1588
session_dependent : false ,
1595
1589
marked_as_completed : false ,
1596
- done : false ,
1597
1590
new_children : Default :: default ( ) ,
1598
1591
} ) ) ,
1599
1592
} ) ;
@@ -1692,20 +1685,12 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1692
1685
Some ( TaskExecutionSpec { future, span } )
1693
1686
}
1694
1687
1695
- fn task_execution_result (
1696
- & self ,
1697
- task_id : TaskId ,
1698
- result : Result < RawVc , TurboTasksExecutionError > ,
1699
- turbo_tasks : & dyn TurboTasksBackendApi < TurboTasksBackend < B > > ,
1700
- ) {
1701
- operation:: UpdateOutputOperation :: run ( task_id, result, self . execute_context ( turbo_tasks) ) ;
1702
- }
1703
-
1704
1688
fn task_execution_completed (
1705
1689
& self ,
1706
1690
task_id : TaskId ,
1707
1691
duration : Duration ,
1708
1692
_memory_usage : usize ,
1693
+ result : Result < RawVc , TurboTasksExecutionError > ,
1709
1694
cell_counters : & AutoMap < ValueTypeId , u32 , BuildHasherDefault < FxHasher > , 8 > ,
1710
1695
stateful : bool ,
1711
1696
has_invalidator : bool ,
@@ -1734,10 +1719,13 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1734
1719
new_children,
1735
1720
mut removed_data,
1736
1721
is_now_immutable,
1722
+ new_output,
1723
+ output_dependent_tasks,
1737
1724
} ) = self . task_execution_completed_prepare (
1738
1725
& mut ctx,
1739
1726
& span,
1740
1727
task_id,
1728
+ result,
1741
1729
cell_counters,
1742
1730
stateful,
1743
1731
has_invalidator,
@@ -1751,7 +1739,20 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1751
1739
// suspend in `CleanupOldEdgesOperation`), but that's ok as the task is still dirty and
1752
1740
// would be executed again.
1753
1741
1742
+ if !output_dependent_tasks. is_empty ( ) {
1743
+ self . task_execution_completed_invalidate_output_dependent (
1744
+ & mut ctx,
1745
+ task_id,
1746
+ output_dependent_tasks,
1747
+ ) ;
1748
+ }
1749
+
1754
1750
let has_new_children = !new_children. is_empty ( ) ;
1751
+
1752
+ if has_new_children {
1753
+ self . task_execution_completed_unfinished_children_dirty ( & mut ctx, & new_children)
1754
+ }
1755
+
1755
1756
if has_new_children
1756
1757
&& self . task_execution_completed_connect ( & mut ctx, task_id, new_children)
1757
1758
{
@@ -1762,6 +1763,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1762
1763
if self . task_execution_completed_finish (
1763
1764
& mut ctx,
1764
1765
task_id,
1766
+ new_output,
1765
1767
& mut removed_data,
1766
1768
is_now_immutable,
1767
1769
) {
@@ -1781,6 +1783,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1781
1783
ctx : & mut impl ExecuteContext < ' _ > ,
1782
1784
span : & Span ,
1783
1785
task_id : TaskId ,
1786
+ result : Result < RawVc , TurboTasksExecutionError > ,
1784
1787
cell_counters : & AutoMap < ValueTypeId , u32 , BuildHasherDefault < FxHasher > , 8 > ,
1785
1788
stateful : bool ,
1786
1789
has_invalidator : bool ,
@@ -1794,12 +1797,12 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1794
1797
new_children : Default :: default ( ) ,
1795
1798
removed_data : Default :: default ( ) ,
1796
1799
is_now_immutable : false ,
1800
+ new_output : None ,
1801
+ output_dependent_tasks : Default :: default ( ) ,
1797
1802
} ) ;
1798
1803
}
1799
1804
let & mut InProgressState :: InProgress ( box InProgressStateInner {
1800
1805
stale,
1801
- ref mut done,
1802
- ref done_event,
1803
1806
ref mut new_children,
1804
1807
session_dependent,
1805
1808
..
@@ -1843,12 +1846,6 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1843
1846
return None ;
1844
1847
}
1845
1848
1846
- if cfg ! ( not( feature = "no_fast_stale" ) ) || !stale {
1847
- // mark the task as completed, so dependent tasks can continue working
1848
- * done = true ;
1849
- done_event. notify ( usize:: MAX ) ;
1850
- }
1851
-
1852
1849
// take the children from the task to process them
1853
1850
let mut new_children = take ( new_children) ;
1854
1851
@@ -1976,6 +1973,53 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
1976
1973
) ;
1977
1974
}
1978
1975
1976
+ // Check if output need to be updated
1977
+ let current_output = get ! ( task, Output ) ;
1978
+ let new_output = match result {
1979
+ Ok ( RawVc :: TaskOutput ( output_task_id) ) => {
1980
+ if let Some ( OutputValue :: Output ( current_task_id) ) = current_output
1981
+ && * current_task_id == output_task_id
1982
+ {
1983
+ None
1984
+ } else {
1985
+ Some ( OutputValue :: Output ( output_task_id) )
1986
+ }
1987
+ }
1988
+ Ok ( RawVc :: TaskCell ( output_task_id, cell) ) => {
1989
+ if let Some ( OutputValue :: Cell ( CellRef {
1990
+ task : current_task_id,
1991
+ cell : current_cell,
1992
+ } ) ) = current_output
1993
+ && * current_task_id == output_task_id
1994
+ && * current_cell == cell
1995
+ {
1996
+ None
1997
+ } else {
1998
+ Some ( OutputValue :: Cell ( CellRef {
1999
+ task : output_task_id,
2000
+ cell,
2001
+ } ) )
2002
+ }
2003
+ }
2004
+ Ok ( RawVc :: LocalOutput ( ..) ) => {
2005
+ panic ! ( "Non-local tasks must not return a local Vc" ) ;
2006
+ }
2007
+ Err ( err) => {
2008
+ if let Some ( OutputValue :: Error ( old_error) ) = current_output
2009
+ && old_error == & err
2010
+ {
2011
+ None
2012
+ } else {
2013
+ Some ( OutputValue :: Error ( err) )
2014
+ }
2015
+ }
2016
+ } ;
2017
+ let mut output_dependent_tasks = SmallVec :: < [ _ ; 4 ] > :: new ( ) ;
2018
+ // When output has changed, grab the dependent tasks
2019
+ if new_output. is_some ( ) && ctx. should_track_dependencies ( ) {
2020
+ output_dependent_tasks = get_many ! ( task, OutputDependent { task } => task) ;
2021
+ }
2022
+
1979
2023
drop ( task) ;
1980
2024
1981
2025
// Check if the task can be marked as immutable
@@ -2002,9 +2046,76 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
2002
2046
new_children,
2003
2047
removed_data,
2004
2048
is_now_immutable,
2049
+ new_output,
2050
+ output_dependent_tasks,
2005
2051
} )
2006
2052
}
2007
2053
2054
+ fn task_execution_completed_invalidate_output_dependent (
2055
+ & self ,
2056
+ ctx : & mut impl ExecuteContext < ' _ > ,
2057
+ task_id : TaskId ,
2058
+ output_dependent_tasks : SmallVec < [ TaskId ; 4 ] > ,
2059
+ ) {
2060
+ debug_assert ! ( !output_dependent_tasks. is_empty( ) ) ;
2061
+
2062
+ let mut queue = AggregationUpdateQueue :: new ( ) ;
2063
+ for dependent_task_id in output_dependent_tasks {
2064
+ if ctx. is_once_task ( dependent_task_id) {
2065
+ // once tasks are never invalidated
2066
+ continue ;
2067
+ }
2068
+ let dependent = ctx. task ( dependent_task_id, TaskDataCategory :: All ) ;
2069
+ if dependent. has_key ( & CachedDataItemKey :: OutdatedOutputDependency { target : task_id } ) {
2070
+ // output dependency is outdated, so it hasn't read the output yet
2071
+ // and doesn't need to be invalidated
2072
+ continue ;
2073
+ }
2074
+ if !dependent. has_key ( & CachedDataItemKey :: OutputDependency { target : task_id } ) {
2075
+ // output dependency has been removed, so the task doesn't depend on the
2076
+ // output anymore and doesn't need to be invalidated
2077
+ continue ;
2078
+ }
2079
+ make_task_dirty_internal (
2080
+ dependent,
2081
+ dependent_task_id,
2082
+ true ,
2083
+ #[ cfg( feature = "trace_task_dirty" ) ]
2084
+ TaskDirtyCause :: OutputChange { task_id } ,
2085
+ & mut queue,
2086
+ ctx,
2087
+ ) ;
2088
+ }
2089
+
2090
+ queue. execute ( ctx) ;
2091
+ }
2092
+
2093
+ fn task_execution_completed_unfinished_children_dirty (
2094
+ & self ,
2095
+ ctx : & mut impl ExecuteContext < ' _ > ,
2096
+ new_children : & FxHashSet < TaskId > ,
2097
+ ) {
2098
+ debug_assert ! ( !new_children. is_empty( ) ) ;
2099
+
2100
+ let mut queue = AggregationUpdateQueue :: new ( ) ;
2101
+ for & child_id in new_children {
2102
+ let child_task = ctx. task ( child_id, TaskDataCategory :: Meta ) ;
2103
+ if !child_task. has_key ( & CachedDataItemKey :: Output { } ) {
2104
+ make_task_dirty_internal (
2105
+ child_task,
2106
+ child_id,
2107
+ false ,
2108
+ #[ cfg( feature = "trace_task_dirty" ) ]
2109
+ TaskDirtyCause :: InitialDirty ,
2110
+ & mut queue,
2111
+ ctx,
2112
+ ) ;
2113
+ }
2114
+ }
2115
+
2116
+ queue. execute ( ctx) ;
2117
+ }
2118
+
2008
2119
fn task_execution_completed_connect (
2009
2120
& self ,
2010
2121
ctx : & mut impl ExecuteContext < ' _ > ,
@@ -2075,6 +2186,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
2075
2186
& self ,
2076
2187
ctx : & mut impl ExecuteContext < ' _ > ,
2077
2188
task_id : TaskId ,
2189
+ new_output : Option < OutputValue > ,
2078
2190
removed_data : & mut Vec < CachedDataItem > ,
2079
2191
is_now_immutable : bool ,
2080
2192
) -> bool {
@@ -2091,7 +2203,6 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
2091
2203
once_task : _,
2092
2204
stale,
2093
2205
session_dependent,
2094
- done : _,
2095
2206
marked_as_completed : _,
2096
2207
new_children,
2097
2208
} ) = in_progress
@@ -2111,6 +2222,12 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
2111
2222
return true ;
2112
2223
}
2113
2224
2225
+ // Set the output if it has changed
2226
+ let mut old_content = None ;
2227
+ if let Some ( value) = new_output {
2228
+ old_content = task. insert ( CachedDataItem :: Output { value } ) ;
2229
+ }
2230
+
2114
2231
// If the task is not stateful and has no mutable children, it does not have a way to be
2115
2232
// invalidated and we can mark it as immutable.
2116
2233
if is_now_immutable {
@@ -2191,6 +2308,10 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
2191
2308
} ;
2192
2309
2193
2310
drop ( task) ;
2311
+ drop ( old_content) ;
2312
+
2313
+ // Notify dependent tasks that are waiting for this task to finish
2314
+ done_event. notify ( usize:: MAX ) ;
2194
2315
2195
2316
if let Some ( data_update) = data_update {
2196
2317
AggregationUpdateQueue :: run ( data_update, ctx) ;
@@ -2978,20 +3099,12 @@ impl<B: BackingStorage> Backend for TurboTasksBackend<B> {
2978
3099
self . 0 . try_start_task_execution ( task_id, turbo_tasks)
2979
3100
}
2980
3101
2981
- fn task_execution_result (
2982
- & self ,
2983
- task_id : TaskId ,
2984
- result : Result < RawVc , TurboTasksExecutionError > ,
2985
- turbo_tasks : & dyn TurboTasksBackendApi < Self > ,
2986
- ) {
2987
- self . 0 . task_execution_result ( task_id, result, turbo_tasks) ;
2988
- }
2989
-
2990
3102
fn task_execution_completed (
2991
3103
& self ,
2992
3104
task_id : TaskId ,
2993
3105
_duration : Duration ,
2994
3106
_memory_usage : usize ,
3107
+ result : Result < RawVc , TurboTasksExecutionError > ,
2995
3108
cell_counters : & AutoMap < ValueTypeId , u32 , BuildHasherDefault < FxHasher > , 8 > ,
2996
3109
stateful : bool ,
2997
3110
has_invalidator : bool ,
@@ -3001,6 +3114,7 @@ impl<B: BackingStorage> Backend for TurboTasksBackend<B> {
3001
3114
task_id,
3002
3115
_duration,
3003
3116
_memory_usage,
3117
+ result,
3004
3118
cell_counters,
3005
3119
stateful,
3006
3120
has_invalidator,
0 commit comments