@@ -2144,19 +2144,34 @@ impl AggregationUpdateQueue {
2144
2144
TaskDataCategory :: Meta ,
2145
2145
) ;
2146
2146
let state = get_mut_or_insert_with ! ( task, Activeness , || ActivenessState :: new( task_id) ) ;
2147
+ let is_new = state. is_empty ( ) ;
2147
2148
let is_zero = state. decrement_active_counter ( ) ;
2148
2149
let is_empty = state. is_empty ( ) ;
2149
2150
if is_empty {
2150
2151
task. remove ( & CachedDataItemKey :: Activeness { } ) ;
2151
2152
}
2152
- if is_zero {
2153
+ debug_assert ! (
2154
+ !( is_new && is_zero) ,
2155
+ // This allows us to but the `if is_zero` block in the else branch of the `if is_new`
2156
+ // block below for fewer checks and less problems with the borrow checker.
2157
+ "A new Activeness will never be zero after decrementing"
2158
+ ) ;
2159
+ if is_new {
2160
+ // A task is considered "active" purely by the existence of an `Activeness` item, even
2161
+ // if that item has an negative active counter. So we need to make sure to
2162
+ // schedule it here. That case is pretty rare and only happens under extreme race
2163
+ // conditions.
2164
+ self . find_and_schedule_dirty_internal ( task_id, task, ctx) ;
2165
+ } else if is_zero {
2153
2166
let followers = get_followers ( & task) ;
2154
2167
drop ( task) ;
2155
2168
if !followers. is_empty ( ) {
2156
2169
self . push ( AggregationUpdateJob :: DecreaseActiveCounts {
2157
2170
task_ids : followers,
2158
2171
} ) ;
2159
2172
}
2173
+ } else {
2174
+ drop ( task) ;
2160
2175
}
2161
2176
}
2162
2177
@@ -2173,16 +2188,27 @@ impl AggregationUpdateQueue {
2173
2188
TaskDataCategory :: Meta ,
2174
2189
) ;
2175
2190
let state = get_mut_or_insert_with ! ( task, Activeness , || ActivenessState :: new( task_id) ) ;
2191
+ let is_new = state. is_empty ( ) ;
2176
2192
let is_positive_now = state. increment_active_counter ( ) ;
2177
2193
let is_empty = state. is_empty ( ) ;
2178
2194
// This can happen if active count was negative before
2179
2195
if is_empty {
2180
2196
task. remove ( & CachedDataItemKey :: Activeness { } ) ;
2181
2197
}
2198
+ debug_assert ! (
2199
+ !is_new || is_positive_now,
2200
+ // This allows us to nest the `if is_new` block below `if is_positive_now` for fewer
2201
+ // checks.
2202
+ "A new Activeness will always be positive after incrementing"
2203
+ ) ;
2182
2204
if is_positive_now {
2183
2205
let followers = get_followers ( & task) ;
2184
- // Fast path to schedule
2185
- self . find_and_schedule_dirty_internal ( task_id, task, ctx) ;
2206
+ if is_new {
2207
+ // Fast path to schedule
2208
+ self . find_and_schedule_dirty_internal ( task_id, task, ctx) ;
2209
+ } else {
2210
+ drop ( task) ;
2211
+ }
2186
2212
2187
2213
if !followers. is_empty ( ) {
2188
2214
self . push ( AggregationUpdateJob :: IncreaseActiveCounts {
0 commit comments