Skip to content

Commit b3e51f8

Browse files
authored
Turbopack: Use TransientCellData for non-serializable cells (#86069)
Use TransientCellData for non-serializable cells use SharedReference to reduce size <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->
1 parent 78a802c commit b3e51f8

File tree

20 files changed

+250
-74
lines changed

20 files changed

+250
-74
lines changed

turbopack/crates/turbo-tasks-backend/src/backend/mod.rs

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,15 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
817817
}
818818
}
819819

820+
let ReadCellOptions {
821+
is_serializable_cell_content,
822+
tracking,
823+
final_read_hint,
824+
} = options;
825+
820826
let mut ctx = self.execute_context(turbo_tasks);
821827
let (mut task, reader_task) = if self.should_track_dependencies()
822-
&& !matches!(options.tracking, ReadTracking::Untracked)
828+
&& !matches!(tracking, ReadTracking::Untracked)
823829
&& let Some(reader_id) = reader
824830
&& reader_id != task_id
825831
{
@@ -832,16 +838,13 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
832838
(ctx.task(task_id, TaskDataCategory::Data), None)
833839
};
834840

835-
let content = if options.final_read_hint {
836-
remove!(task, CellData { cell })
837-
} else if let Some(content) = get!(task, CellData { cell }) {
838-
let content = content.clone();
839-
Some(content)
841+
let content = if final_read_hint {
842+
task.remove_cell_data(is_serializable_cell_content, cell)
840843
} else {
841-
None
844+
task.get_cell_data(is_serializable_cell_content, cell)
842845
};
843846
if let Some(content) = content {
844-
if options.tracking.should_track(false) {
847+
if tracking.should_track(false) {
845848
add_cell_dependency(task_id, task, reader, reader_task, cell);
846849
}
847850
return Ok(Ok(TypedCellContent(
@@ -868,7 +871,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
868871
)
869872
.copied();
870873
let Some(max_id) = max_id else {
871-
if options.tracking.should_track(true) {
874+
if tracking.should_track(true) {
872875
add_cell_dependency(task_id, task, reader, reader_task, cell);
873876
}
874877
bail!(
@@ -877,7 +880,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
877880
);
878881
};
879882
if cell.index >= max_id {
880-
if options.tracking.should_track(true) {
883+
if tracking.should_track(true) {
881884
add_cell_dependency(task_id, task, reader, reader_task, cell);
882885
}
883886
bail!(
@@ -2019,6 +2022,14 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
20192022
.get(&cell.type_id).is_none_or(|start_index| cell.index >= *start_index))
20202023
}));
20212024
}
2025+
if task_id.is_transient() || iter_many!(task, TransientCellData { cell }
2026+
if cell_counters.get(&cell.type_id).is_none_or(|start_index| cell.index >= *start_index) => cell
2027+
).count() > 0 {
2028+
removed_data.extend(task.extract_if(CachedDataItemType::TransientCellData, |key, _| {
2029+
matches!(key, CachedDataItemKey::TransientCellData { cell } if cell_counters
2030+
.get(&cell.type_id).is_none_or(|start_index| cell.index >= *start_index))
2031+
}));
2032+
}
20222033

20232034
old_edges.extend(
20242035
task.iter(CachedDataItemType::OutdatedCollectible)
@@ -2459,6 +2470,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
24592470
fn task_execution_completed_cleanup(&self, ctx: &mut impl ExecuteContext<'_>, task_id: TaskId) {
24602471
let mut task = ctx.task(task_id, TaskDataCategory::All);
24612472
task.shrink_to_fit(CachedDataItemType::CellData);
2473+
task.shrink_to_fit(CachedDataItemType::TransientCellData);
24622474
task.shrink_to_fit(CachedDataItemType::CellTypeMaxIndex);
24632475
task.shrink_to_fit(CachedDataItemType::CellDependency);
24642476
task.shrink_to_fit(CachedDataItemType::OutputDependency);
@@ -2594,13 +2606,14 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
25942606
&self,
25952607
task_id: TaskId,
25962608
cell: CellId,
2597-
_options: ReadCellOptions,
2609+
options: ReadCellOptions,
25982610
turbo_tasks: &dyn TurboTasksBackendApi<TurboTasksBackend<B>>,
25992611
) -> Result<TypedCellContent> {
26002612
let mut ctx = self.execute_context(turbo_tasks);
26012613
let task = ctx.task(task_id, TaskDataCategory::Data);
2602-
if let Some(content) = get!(task, CellData { cell }) {
2603-
Ok(CellContent(Some(content.reference.clone())).into_typed(cell.type_id))
2614+
if let Some(content) = task.get_cell_data(options.is_serializable_cell_content, cell) {
2615+
debug_assert!(content.type_id == cell.type_id, "Cell type ID mismatch");
2616+
Ok(CellContent(Some(content.reference)).into_typed(cell.type_id))
26042617
} else {
26052618
Ok(CellContent(None).into_typed(cell.type_id))
26062619
}
@@ -2741,6 +2754,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
27412754
&self,
27422755
task_id: TaskId,
27432756
cell: CellId,
2757+
is_serializable_cell_content: bool,
27442758
content: CellContent,
27452759
verification_mode: VerificationMode,
27462760
turbo_tasks: &dyn TurboTasksBackendApi<TurboTasksBackend<B>>,
@@ -2749,6 +2763,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
27492763
task_id,
27502764
cell,
27512765
content,
2766+
is_serializable_cell_content,
27522767
verification_mode,
27532768
self.execute_context(turbo_tasks),
27542769
);
@@ -3336,12 +3351,19 @@ impl<B: BackingStorage> Backend for TurboTasksBackend<B> {
33363351
&self,
33373352
task_id: TaskId,
33383353
cell: CellId,
3354+
is_serializable_cell_content: bool,
33393355
content: CellContent,
33403356
verification_mode: VerificationMode,
33413357
turbo_tasks: &dyn TurboTasksBackendApi<Self>,
33423358
) {
3343-
self.0
3344-
.update_task_cell(task_id, cell, content, verification_mode, turbo_tasks);
3359+
self.0.update_task_cell(
3360+
task_id,
3361+
cell,
3362+
is_serializable_cell_content,
3363+
content,
3364+
verification_mode,
3365+
turbo_tasks,
3366+
);
33453367
}
33463368

33473369
fn mark_own_task_as_finished(

turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ use std::{
1414
};
1515

1616
use serde::{Deserialize, Serialize};
17-
use turbo_tasks::{FxIndexMap, KeyValuePair, TaskId, TurboTasksBackendApi};
17+
use turbo_tasks::{
18+
CellId, FxIndexMap, KeyValuePair, TaskId, TurboTasksBackendApi, TypedSharedReference,
19+
};
1820

1921
use crate::{
2022
backend::{
2123
OperationGuard, TaskDataCategory, TransientTask, TurboTasksBackend, TurboTasksBackendInner,
2224
TurboTasksBackendJob,
23-
storage::{SpecificTaskDataCategory, StorageWriteGuard, get, iter_many},
25+
storage::{SpecificTaskDataCategory, StorageWriteGuard, get, iter_many, remove},
2426
},
2527
backing_storage::BackingStorage,
2628
data::{
@@ -467,6 +469,35 @@ pub trait TaskGuard: Debug {
467469
.unwrap_or_default();
468470
dirty_count > clean_count
469471
}
472+
fn remove_cell_data(
473+
&mut self,
474+
is_serializable_cell_content: bool,
475+
cell: CellId,
476+
) -> Option<TypedSharedReference> {
477+
if is_serializable_cell_content {
478+
remove!(self, CellData { cell })
479+
} else {
480+
remove!(self, TransientCellData { cell }).map(|sr| sr.into_typed(cell.type_id))
481+
}
482+
}
483+
fn get_cell_data(
484+
&self,
485+
is_serializable_cell_content: bool,
486+
cell: CellId,
487+
) -> Option<TypedSharedReference> {
488+
if is_serializable_cell_content {
489+
get!(self, CellData { cell }).cloned()
490+
} else {
491+
get!(self, TransientCellData { cell }).map(|sr| sr.clone().into_typed(cell.type_id))
492+
}
493+
}
494+
fn has_cell_data(&self, is_serializable_cell_content: bool, cell: CellId) -> bool {
495+
if is_serializable_cell_content {
496+
self.has_key(&CachedDataItemKey::CellData { cell })
497+
} else {
498+
self.has_key(&CachedDataItemKey::TransientCellData { cell })
499+
}
500+
}
470501
}
471502

472503
pub struct TaskGuardImpl<'a, B: BackingStorage> {

turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
AggregationUpdateQueue, ExecuteContext, Operation, TaskGuard,
1616
invalidate::make_task_dirty_internal,
1717
},
18-
storage::{get, get_many, remove},
18+
storage::{get_many, remove},
1919
},
2020
data::{CachedDataItem, CachedDataItemKey, CellRef},
2121
};
@@ -24,12 +24,14 @@ use crate::{
2424
#[allow(clippy::large_enum_variant)]
2525
pub enum UpdateCellOperation {
2626
InvalidateWhenCellDependency {
27+
is_serializable_cell_content: bool,
2728
cell_ref: CellRef,
2829
dependent_tasks: SmallVec<[TaskId; 4]>,
2930
content: Option<TypedSharedReference>,
3031
queue: AggregationUpdateQueue,
3132
},
3233
FinalCellChange {
34+
is_serializable_cell_content: bool,
3335
cell_ref: CellRef,
3436
content: Option<TypedSharedReference>,
3537
queue: AggregationUpdateQueue,
@@ -46,6 +48,7 @@ impl UpdateCellOperation {
4648
task_id: TaskId,
4749
cell: CellId,
4850
content: CellContent,
51+
is_serializable_cell_content: bool,
4952
#[cfg(feature = "verify_determinism")] verification_mode: VerificationMode,
5053
#[cfg(not(feature = "verify_determinism"))] _verification_mode: VerificationMode,
5154
mut ctx: impl ExecuteContext,
@@ -64,18 +67,17 @@ impl UpdateCellOperation {
6467
let assume_unchanged =
6568
!ctx.should_track_dependencies() || !task.has_key(&CachedDataItemKey::Dirty {});
6669

67-
let old_content = get!(task, CellData { cell });
68-
6970
if assume_unchanged {
70-
if old_content.is_some() {
71+
let has_old_content = task.has_cell_data(is_serializable_cell_content, cell);
72+
if has_old_content {
7173
// Never update cells when recomputing if they already have a value.
7274
// It's not expected that content changes during recomputation.
7375

7476
// Check if this assumption holds.
7577
#[cfg(feature = "verify_determinism")]
7678
if !is_stateful
7779
&& matches!(verification_mode, VerificationMode::EqualityCheck)
78-
&& content.as_ref() != old_content
80+
&& content != task.get_cell_data(is_serializable_cell_content, cell)
7981
{
8082
let task_description = ctx.get_task_description(task_id);
8183
let cell_type = turbo_tasks::registry::get_value_type(cell.type_id).global_name;
@@ -115,12 +117,16 @@ impl UpdateCellOperation {
115117
// tasks and after that set the new cell content. When the cell content is unset,
116118
// readers will wait for it to be set via InProgressCell.
117119

118-
let old_content = task.remove(&CachedDataItemKey::CellData { cell });
120+
let old_content = task.remove(&CachedDataItemKey::cell_data(
121+
is_serializable_cell_content,
122+
cell,
123+
));
119124

120125
drop(task);
121126
drop(old_content);
122127

123128
UpdateCellOperation::InvalidateWhenCellDependency {
129+
is_serializable_cell_content,
124130
cell_ref: CellRef {
125131
task: task_id,
126132
cell,
@@ -138,12 +144,16 @@ impl UpdateCellOperation {
138144
// So we can just update the cell content.
139145

140146
let old_content = if let Some(new_content) = content {
141-
task.insert(CachedDataItem::CellData {
147+
task.insert(CachedDataItem::cell_data(
148+
is_serializable_cell_content,
142149
cell,
143-
value: new_content,
144-
})
150+
new_content,
151+
))
145152
} else {
146-
task.remove(&CachedDataItemKey::CellData { cell })
153+
task.remove(&CachedDataItemKey::cell_data(
154+
is_serializable_cell_content,
155+
cell,
156+
))
147157
};
148158

149159
let in_progress_cell = remove!(task, InProgressCell { cell });
@@ -163,6 +173,7 @@ impl Operation for UpdateCellOperation {
163173
ctx.operation_suspend_point(&self);
164174
match self {
165175
UpdateCellOperation::InvalidateWhenCellDependency {
176+
is_serializable_cell_content,
166177
cell_ref,
167178
ref mut dependent_tasks,
168179
ref mut content,
@@ -203,24 +214,27 @@ impl Operation for UpdateCellOperation {
203214
}
204215
if dependent_tasks.is_empty() {
205216
self = UpdateCellOperation::FinalCellChange {
217+
is_serializable_cell_content,
206218
cell_ref,
207219
content: take(content),
208220
queue: take(queue),
209221
};
210222
}
211223
}
212224
UpdateCellOperation::FinalCellChange {
225+
is_serializable_cell_content,
213226
cell_ref: CellRef { task, cell },
214227
content,
215228
ref mut queue,
216229
} => {
217230
let mut task = ctx.task(task, TaskDataCategory::Data);
218231

219232
if let Some(content) = content {
220-
task.add_new(CachedDataItem::CellData {
233+
task.add_new(CachedDataItem::cell_data(
234+
is_serializable_cell_content,
221235
cell,
222-
value: content,
223-
})
236+
content,
237+
));
224238
}
225239

226240
let in_progress_cell = remove!(task, InProgressCell { cell });

0 commit comments

Comments
 (0)