Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expiration should do nothing except disable time slicing #21345

Merged
merged 1 commit into from
Apr 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions packages/react-reconciler/src/ReactFiberLane.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ export function markStarvedLanesAsExpired(
// expiration time. If so, we'll assume the update is being starved and mark
// it as expired to force it to finish.
let lanes = pendingLanes;
let expiredLanes = 0;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
Expand All @@ -420,15 +419,11 @@ export function markStarvedLanesAsExpired(
}
} else if (expirationTime <= currentTime) {
// This lane expired
expiredLanes |= lane;
root.expiredLanes |= lane;
}

lanes &= ~lane;
}

if (expiredLanes !== 0) {
markRootExpired(root, expiredLanes);
}
}

// This returns the highest priority pending lanes regardless of whether they
Expand Down Expand Up @@ -459,16 +454,22 @@ export function includesOnlyTransitions(lanes: Lanes) {
}

export function shouldTimeSlice(root: FiberRoot, lanes: Lanes) {
if (!enableSyncDefaultUpdates) {
if ((lanes & root.expiredLanes) !== NoLanes) {
// At least one of these lanes expired. To prevent additional starvation,
// finish rendering without yielding execution.
return false;
}
if (enableSyncDefaultUpdates) {
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
// TODO: Check for root override, once that lands
return (lanes & SyncDefaultLanes) === NoLanes;
} else {
return true;
}
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
// TODO: Check for root override, once that lands
return (lanes & SyncDefaultLanes) === NoLanes;
}

export function isTransitionLane(lane: Lane) {
Expand Down Expand Up @@ -613,14 +614,6 @@ export function markRootPinged(
root.pingedLanes |= root.suspendedLanes & pingedLanes;
}

export function markRootExpired(root: FiberRoot, expiredLanes: Lanes) {
const entanglements = root.entanglements;
const SyncLaneIndex = 0;
entanglements[SyncLaneIndex] |= expiredLanes;
root.entangledLanes |= SyncLane;
root.pendingLanes |= SyncLane;
}

export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
root.mutableReadLanes |= updateLane & root.pendingLanes;
}
Expand All @@ -634,6 +627,7 @@ export function markRootFinished(root: FiberRoot, remainingLanes: Lanes) {
root.suspendedLanes = 0;
root.pingedLanes = 0;

root.expiredLanes &= remainingLanes;
root.mutableReadLanes &= remainingLanes;

root.entangledLanes &= remainingLanes;
Expand Down
38 changes: 16 additions & 22 deletions packages/react-reconciler/src/ReactFiberLane.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ export function markStarvedLanesAsExpired(
// expiration time. If so, we'll assume the update is being starved and mark
// it as expired to force it to finish.
let lanes = pendingLanes;
let expiredLanes = 0;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
Expand All @@ -420,15 +419,11 @@ export function markStarvedLanesAsExpired(
}
} else if (expirationTime <= currentTime) {
// This lane expired
expiredLanes |= lane;
root.expiredLanes |= lane;
}

lanes &= ~lane;
}

if (expiredLanes !== 0) {
markRootExpired(root, expiredLanes);
}
}

// This returns the highest priority pending lanes regardless of whether they
Expand Down Expand Up @@ -459,16 +454,22 @@ export function includesOnlyTransitions(lanes: Lanes) {
}

export function shouldTimeSlice(root: FiberRoot, lanes: Lanes) {
if (!enableSyncDefaultUpdates) {
if ((lanes & root.expiredLanes) !== NoLanes) {
// At least one of these lanes expired. To prevent additional starvation,
// finish rendering without yielding execution.
return false;
}
if (enableSyncDefaultUpdates) {
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
// TODO: Check for root override, once that lands
return (lanes & SyncDefaultLanes) === NoLanes;
} else {
return true;
}
const SyncDefaultLanes =
InputContinuousHydrationLane |
InputContinuousLane |
DefaultHydrationLane |
DefaultLane;
// TODO: Check for root override, once that lands
return (lanes & SyncDefaultLanes) === NoLanes;
}

export function isTransitionLane(lane: Lane) {
Expand Down Expand Up @@ -613,14 +614,6 @@ export function markRootPinged(
root.pingedLanes |= root.suspendedLanes & pingedLanes;
}

export function markRootExpired(root: FiberRoot, expiredLanes: Lanes) {
const entanglements = root.entanglements;
const SyncLaneIndex = 0;
entanglements[SyncLaneIndex] |= expiredLanes;
root.entangledLanes |= SyncLane;
root.pendingLanes |= SyncLane;
}

export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
root.mutableReadLanes |= updateLane & root.pendingLanes;
}
Expand All @@ -634,6 +627,7 @@ export function markRootFinished(root: FiberRoot, remainingLanes: Lanes) {
root.suspendedLanes = 0;
root.pingedLanes = 0;

root.expiredLanes &= remainingLanes;
root.mutableReadLanes &= remainingLanes;

root.entangledLanes &= remainingLanes;
Expand Down
1 change: 1 addition & 0 deletions packages/react-reconciler/src/ReactFiberRoot.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function FiberRootNode(containerInfo, tag, hydrate) {
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;

Expand Down
1 change: 1 addition & 0 deletions packages/react-reconciler/src/ReactFiberRoot.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function FiberRootNode(containerInfo, tag, hydrate) {
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;

Expand Down
38 changes: 11 additions & 27 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ import {
markRootUpdated,
markRootSuspended as markRootSuspended_dontCallThisOneDirectly,
markRootPinged,
markRootExpired,
markRootEntangled,
markRootFinished,
getHighestPriorityLane,
addFiberToLanesMap,
Expand Down Expand Up @@ -787,22 +787,17 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
return null;
}

// We disable time-slicing in some cases: if the work has been CPU-bound
// for too long ("expired" work, to prevent starvation), or we're in
// sync-updates-by-default mode.
// TODO: We only check `didTimeout` defensively, to account for a Scheduler
// bug we're still investigating. Once the bug in Scheduler is fixed,
// we can remove this, since we track expiration ourselves.
if (!disableSchedulerTimeoutInWorkLoop && didTimeout) {
// Something expired. Flush synchronously until there's no expired
// work left.
markRootExpired(root, lanes);
// This will schedule a synchronous callback.
ensureRootIsScheduled(root, now());
return null;
}

let exitStatus = shouldTimeSlice(root, lanes)
? renderRootConcurrent(root, lanes)
: // Time slicing is disabled for default updates in this root.
renderRootSync(root, lanes);
let exitStatus =
shouldTimeSlice(root, lanes) &&
(disableSchedulerTimeoutInWorkLoop || !didTimeout)
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes);
if (exitStatus !== RootIncomplete) {
if (exitStatus === RootErrored) {
executionContext |= RetryAfterError;
Expand Down Expand Up @@ -990,16 +985,7 @@ function performSyncWorkOnRoot(root) {
flushPassiveEffects();

let lanes = getNextLanes(root, NoLanes);
if (includesSomeLane(lanes, SyncLane)) {
if (
root === workInProgressRoot &&
includesSomeLane(lanes, workInProgressRootRenderLanes)
) {
// There's a partial tree, and at least one of its lanes has expired. Finish
// rendering it before rendering the rest of the expired work.
lanes = workInProgressRootRenderLanes;
}
} else {
if (!includesSomeLane(lanes, SyncLane)) {
// There's no remaining sync work left.
ensureRootIsScheduled(root, now());
return null;
Expand Down Expand Up @@ -1052,11 +1038,9 @@ function performSyncWorkOnRoot(root) {
return null;
}

// TODO: Do we still need this API? I think we can delete it. Was only used
// internally.
export function flushRoot(root: FiberRoot, lanes: Lanes) {
if (lanes !== NoLanes) {
markRootExpired(root, lanes);
markRootEntangled(root, mergeLanes(lanes, SyncLane));
ensureRootIsScheduled(root, now());
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
resetRenderTimer();
Expand Down
38 changes: 11 additions & 27 deletions packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ import {
markRootUpdated,
markRootSuspended as markRootSuspended_dontCallThisOneDirectly,
markRootPinged,
markRootExpired,
markRootEntangled,
markRootFinished,
getHighestPriorityLane,
addFiberToLanesMap,
Expand Down Expand Up @@ -787,22 +787,17 @@ function performConcurrentWorkOnRoot(root, didTimeout) {
return null;
}

// We disable time-slicing in some cases: if the work has been CPU-bound
// for too long ("expired" work, to prevent starvation), or we're in
// sync-updates-by-default mode.
// TODO: We only check `didTimeout` defensively, to account for a Scheduler
// bug we're still investigating. Once the bug in Scheduler is fixed,
// we can remove this, since we track expiration ourselves.
if (!disableSchedulerTimeoutInWorkLoop && didTimeout) {
// Something expired. Flush synchronously until there's no expired
// work left.
markRootExpired(root, lanes);
// This will schedule a synchronous callback.
ensureRootIsScheduled(root, now());
return null;
}

let exitStatus = shouldTimeSlice(root, lanes)
? renderRootConcurrent(root, lanes)
: // Time slicing is disabled for default updates in this root.
renderRootSync(root, lanes);
let exitStatus =
shouldTimeSlice(root, lanes) &&
(disableSchedulerTimeoutInWorkLoop || !didTimeout)
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes);
if (exitStatus !== RootIncomplete) {
if (exitStatus === RootErrored) {
executionContext |= RetryAfterError;
Expand Down Expand Up @@ -990,16 +985,7 @@ function performSyncWorkOnRoot(root) {
flushPassiveEffects();

let lanes = getNextLanes(root, NoLanes);
if (includesSomeLane(lanes, SyncLane)) {
if (
root === workInProgressRoot &&
includesSomeLane(lanes, workInProgressRootRenderLanes)
) {
// There's a partial tree, and at least one of its lanes has expired. Finish
// rendering it before rendering the rest of the expired work.
lanes = workInProgressRootRenderLanes;
}
} else {
if (!includesSomeLane(lanes, SyncLane)) {
// There's no remaining sync work left.
ensureRootIsScheduled(root, now());
return null;
Expand Down Expand Up @@ -1052,11 +1038,9 @@ function performSyncWorkOnRoot(root) {
return null;
}

// TODO: Do we still need this API? I think we can delete it. Was only used
// internally.
export function flushRoot(root: FiberRoot, lanes: Lanes) {
if (lanes !== NoLanes) {
markRootExpired(root, lanes);
markRootEntangled(root, mergeLanes(lanes, SyncLane));
ensureRootIsScheduled(root, now());
if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
resetRenderTimer();
Expand Down
1 change: 1 addition & 0 deletions packages/react-reconciler/src/ReactInternalTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ type BaseFiberRootProperties = {|
pendingLanes: Lanes,
suspendedLanes: Lanes,
pingedLanes: Lanes,
expiredLanes: Lanes,
mutableReadLanes: Lanes,

finishedLanes: Lanes,
Expand Down
Loading