1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00
denoland-deno/cli/graph_container.rs
Divy Srivastava 88983fb3eb
fix(node): seperate worker module cache (#23634)
Construct a new module graph container for workers instead of sharing it
with the main worker.

Fixes #17248
Fixes #23461

---------

Co-authored-by: David Sherret <dsherret@gmail.com>
2024-05-16 07:09:35 +00:00

157 lines
4.5 KiB
Rust

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use std::sync::Arc;
use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_core::parking_lot::RwLock;
use deno_core::resolve_url_or_path;
use deno_graph::ModuleGraph;
use deno_runtime::colors;
use deno_runtime::permissions::PermissionsContainer;
use crate::args::CliOptions;
use crate::module_loader::ModuleLoadPreparer;
pub trait ModuleGraphContainer: Clone + 'static {
/// Acquires a permit to modify the module graph without other code
/// having the chance to modify it. In the meantime, other code may
/// still read from the existing module graph.
async fn acquire_update_permit(&self) -> impl ModuleGraphUpdatePermit;
/// Gets a copy of the graph.
fn graph(&self) -> Arc<ModuleGraph>;
}
/// A permit for updating the module graph. When complete and
/// everything looks fine, calling `.commit()` will store the
/// new graph in the ModuleGraphContainer.
pub trait ModuleGraphUpdatePermit {
/// Gets the module graph for mutation.
fn graph_mut(&mut self) -> &mut ModuleGraph;
/// Saves the mutated module graph in the container.
fn commit(self);
}
/// Holds the `ModuleGraph` for the main worker.
#[derive(Clone)]
pub struct MainModuleGraphContainer {
// Allow only one request to update the graph data at a time,
// but allow other requests to read from it at any time even
// while another request is updating the data.
update_queue: Arc<crate::util::sync::TaskQueue>,
inner: Arc<RwLock<Arc<ModuleGraph>>>,
cli_options: Arc<CliOptions>,
module_load_preparer: Arc<ModuleLoadPreparer>,
}
impl MainModuleGraphContainer {
pub fn new(
cli_options: Arc<CliOptions>,
module_load_preparer: Arc<ModuleLoadPreparer>,
) -> Self {
Self {
update_queue: Default::default(),
inner: Arc::new(RwLock::new(Arc::new(ModuleGraph::new(
cli_options.graph_kind(),
)))),
cli_options,
module_load_preparer,
}
}
pub async fn check_specifiers(
&self,
specifiers: &[ModuleSpecifier],
) -> Result<(), AnyError> {
let mut graph_permit = self.acquire_update_permit().await;
let graph = graph_permit.graph_mut();
self
.module_load_preparer
.prepare_module_load(
graph,
specifiers,
false,
self.cli_options.ts_type_lib_window(),
PermissionsContainer::allow_all(),
)
.await?;
graph_permit.commit();
Ok(())
}
/// Helper around prepare_module_load that loads and type checks
/// the provided files.
pub async fn load_and_type_check_files(
&self,
files: &[String],
) -> Result<(), AnyError> {
let specifiers = self.collect_specifiers(files)?;
if specifiers.is_empty() {
log::warn!("{} No matching files found.", colors::yellow("Warning"));
}
self.check_specifiers(&specifiers).await
}
pub fn collect_specifiers(
&self,
files: &[String],
) -> Result<Vec<ModuleSpecifier>, AnyError> {
let excludes = self.cli_options.resolve_config_excludes()?;
Ok(
files
.iter()
.filter_map(|file| {
let file_url =
resolve_url_or_path(file, self.cli_options.initial_cwd()).ok()?;
if file_url.scheme() != "file" {
return Some(file_url);
}
// ignore local files that match any of files listed in `exclude` option
let file_path = file_url.to_file_path().ok()?;
if excludes.matches_path(&file_path) {
None
} else {
Some(file_url)
}
})
.collect::<Vec<_>>(),
)
}
}
impl ModuleGraphContainer for MainModuleGraphContainer {
async fn acquire_update_permit(&self) -> impl ModuleGraphUpdatePermit {
let permit = self.update_queue.acquire().await;
MainModuleGraphUpdatePermit {
permit,
inner: self.inner.clone(),
graph: (**self.inner.read()).clone(),
}
}
fn graph(&self) -> Arc<ModuleGraph> {
self.inner.read().clone()
}
}
/// A permit for updating the module graph. When complete and
/// everything looks fine, calling `.commit()` will store the
/// new graph in the ModuleGraphContainer.
pub struct MainModuleGraphUpdatePermit<'a> {
permit: crate::util::sync::TaskQueuePermit<'a>,
inner: Arc<RwLock<Arc<ModuleGraph>>>,
graph: ModuleGraph,
}
impl<'a> ModuleGraphUpdatePermit for MainModuleGraphUpdatePermit<'a> {
fn graph_mut(&mut self) -> &mut ModuleGraph {
&mut self.graph
}
fn commit(self) {
*self.inner.write() = Arc::new(self.graph);
drop(self.permit); // explicit drop for clarity
}
}