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

improve versioned content map #65466

Merged
merged 1 commit into from
May 8, 2024
Merged
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
85 changes: 47 additions & 38 deletions packages/next-swc/crates/next-api/src/versioned_content_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,30 @@ use turbopack_binding::{
#[turbo_tasks::value(transparent)]
pub struct OutputAssetsOperation(Vc<OutputAssets>);

#[derive(
Clone, Copy, TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Serialize, Deserialize, Debug,
)]
#[derive(Clone, TraceRawVcs, PartialEq, Eq, ValueDebugFormat, Serialize, Deserialize, Debug)]
struct MapEntry {
assets_operation: Vc<OutputAssets>,
side_effects: Vc<Completion>,
path_to_asset: HashMap<Vc<FileSystemPath>, Vc<Box<dyn OutputAsset>>>,
}

#[turbo_tasks::value(transparent)]
struct OptionMapEntry(Option<MapEntry>);

type PathToOutputOperation = HashMap<Vc<FileSystemPath>, Vc<OutputAssets>>;
type OutputOperationToSideEffects = HashMap<Vc<OutputAssets>, Vc<Completion>>;
type OutputOperationToComputeEntry = HashMap<Vc<OutputAssets>, Vc<OptionMapEntry>>;

#[turbo_tasks::value]
pub struct VersionedContentMap {
map_path_to_op: State<PathToOutputOperation>,
map_op_to_side_effects: State<OutputOperationToSideEffects>,
map_op_to_compute_entry: State<OutputOperationToComputeEntry>,
}

impl ValueDefault for VersionedContentMap {
fn value_default() -> Vc<Self> {
VersionedContentMap {
map_path_to_op: State::new(HashMap::new()),
map_op_to_side_effects: State::new(HashMap::new()),
map_op_to_compute_entry: State::new(HashMap::new()),
}
.cell()
}
Expand All @@ -71,43 +70,49 @@ impl VersionedContentMap {
client_output_path: Vc<FileSystemPath>,
) -> Result<Vc<Completion>> {
let this = self.await?;
let side_effects =
self.output_side_effects(assets_operation, client_relative_path, client_output_path);
let compute_entry =
self.compute_entry(assets_operation, client_relative_path, client_output_path);
let assets = *assets_operation.await?;
this.map_op_to_side_effects
.update_conditionally(|map| map.insert(assets, side_effects) != Some(side_effects));
Ok(side_effects)
this.map_op_to_compute_entry
.update_conditionally(|map| map.insert(assets, compute_entry) != Some(compute_entry));
let Some(entry) = &*compute_entry.await? else {
unreachable!("compute_entry always returns Some(MapEntry)")
};
Ok(entry.side_effects)
}

#[turbo_tasks::function]
async fn output_side_effects(
async fn compute_entry(
self: Vc<Self>,
assets_operation: Vc<OutputAssetsOperation>,
client_relative_path: Vc<FileSystemPath>,
client_output_path: Vc<FileSystemPath>,
) -> Result<Vc<Completion>> {
) -> Result<Vc<OptionMapEntry>> {
let assets = *assets_operation.await?;
let entries: Vec<_> = assets
.await?
.iter()
.map(|&asset| async move { Ok((asset.ident().path().resolve().await?, assets)) })
.map(|&asset| async move { Ok((asset.ident().path().resolve().await?, asset, assets)) })
.try_join()
.await?;
self.await?.map_path_to_op.update_conditionally(move |map| {

self.await?.map_path_to_op.update_conditionally(|map| {
let mut changed = false;
for (k, v) in entries {
for &(k, _, v) in entries.iter() {
if map.insert(k, v) != Some(v) {
changed = true;
}
}
changed
});
// Make sure all written client assets are up-to-date
Ok(emit_client_assets(
assets,
client_relative_path,
client_output_path,
))
let side_effects = emit_client_assets(assets, client_relative_path, client_output_path);
let map_entry = Vc::cell(Some(MapEntry {
assets_operation: assets,
side_effects,
path_to_asset: entries.into_iter().map(|(k, v, _)| (k, v)).collect(),
}));
Ok(map_entry)
}

#[turbo_tasks::function]
Expand Down Expand Up @@ -142,20 +147,21 @@ impl VersionedContentMap {
) -> Result<Vc<Box<dyn OutputAsset>>> {
let result = self.raw_get(path).await?;
if let Some(MapEntry {
assets_operation,
assets_operation: _,
side_effects,
}) = *result
path_to_asset,
}) = &*result
{
// NOTE(alexkirsz) This is necessary to mark the task as active again.
Vc::connect(assets_operation);
Vc::connect(side_effects);

side_effects.await?;

for &asset in assets_operation.await?.iter() {
if asset.ident().path().resolve().await? == path {
return Ok(asset);
}
if let Some(asset) = path_to_asset.get(&path) {
return Ok(*asset);
} else {
let path = path.to_string().await?;
bail!(
"could not find asset for path {} (asset has been removed)",
path
);
}
}
let path = path.to_string().await?;
Expand Down Expand Up @@ -186,16 +192,19 @@ impl VersionedContentMap {
let Some(assets) = assets else {
return Ok(Vc::cell(None));
};
let side_effects = {
let map = self.map_op_to_side_effects.get();
// Need to reconnect the operation to the map
Vc::connect(assets);

let compute_entry = {
let map = self.map_op_to_compute_entry.get();
map.get(&assets).copied()
};
let Some(side_effects) = side_effects else {
let Some(compute_entry) = compute_entry else {
return Ok(Vc::cell(None));
};
Ok(Vc::cell(Some(MapEntry {
assets_operation: assets,
side_effects,
})))
// Need to reconnect the operation to the map
Vc::connect(compute_entry);

Ok(compute_entry)
}
}
Loading