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

perf: move jsr manifest checksum to locker #488

Merged
merged 4 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
32 changes: 18 additions & 14 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3057,7 +3057,7 @@ struct PendingModuleLoadItem {

struct LoadedJsrPackageViaHttpsUrl {
nv: PackageNv,
manifest_checksum: String,
manifest_checksum_for_locker: Option<LoaderChecksum>,
}

type PendingInfoFuture<'a> = LocalBoxFuture<'a, PendingInfo>;
Expand Down Expand Up @@ -3282,10 +3282,12 @@ impl<'a, 'graph> Builder<'a, 'graph> {
loaded_package_via_https_url,
}) => {
if let Some(pkg) = loaded_package_via_https_url {
self
.graph
.packages
.ensure_package(pkg.nv, pkg.manifest_checksum);
if let Some(locker) = &mut self.locker {
if let Some(checksum) = pkg.manifest_checksum_for_locker {
locker.set_pkg_manifest_checksum(&pkg.nv, checksum);
}
}
self.graph.packages.ensure_package(pkg.nv);
}

match result {
Expand Down Expand Up @@ -3459,10 +3461,12 @@ impl<'a, 'graph> Builder<'a, 'graph> {
match version_info_result {
Ok(version_info_load_item) => {
let version_info = version_info_load_item.info;
self
.graph
.packages
.ensure_package(nv.clone(), version_info_load_item.checksum);
self.graph.packages.ensure_package(nv.clone());
if let Some(locker) = &mut self.locker {
if let Some(checksum) = version_info_load_item.checksum_for_locker {
locker.set_pkg_manifest_checksum(nv, checksum);
}
}
let base_url = self.jsr_url_provider.package_url(nv);
let export_name =
normalize_export_name(resolution_item.nv_ref.sub_path());
Expand Down Expand Up @@ -4277,7 +4281,7 @@ impl<'a, 'graph> Builder<'a, 'graph> {
maybe_checksum = self
.locker
.as_ref()
.and_then(|l| l.get_checksum(&requested_specifier));
.and_then(|l| l.get_remote_checksum(&requested_specifier));
}
let fut = async move {
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -4328,7 +4332,7 @@ impl<'a, 'graph> Builder<'a, 'graph> {
maybe_version_info.replace(info);
loaded_package_via_https_url.replace(LoadedJsrPackageViaHttpsUrl {
nv: package_nv,
manifest_checksum: inner.checksum,
manifest_checksum_for_locker: inner.checksum_for_locker,
});
}

Expand Down Expand Up @@ -4474,7 +4478,7 @@ impl<'a, 'graph> Builder<'a, 'graph> {
self.state.jsr.metadata.queue_load_package_version_info(
package_nv,
self.fill_pass_mode.to_cache_setting(),
self.graph.packages.get_manifest_checksum(package_nv),
self.locker.as_deref(),
JsrMetadataStoreServices {
executor: self.executor,
jsr_url_provider: self.jsr_url_provider,
Expand Down Expand Up @@ -4551,8 +4555,8 @@ impl<'a, 'graph> Builder<'a, 'graph> {
&& matches!(specifier.scheme(), "https" | "http")
{
if let Some(locker) = &mut self.locker {
if !locker.has_checksum(&specifier) {
locker.set_checksum(
if !locker.has_remote_checksum(&specifier) {
locker.set_remote_checksum(
&specifier,
LoaderChecksum::new(LoaderChecksum::gen(
module_source_and_info.source().as_bytes(),
Expand Down
30 changes: 17 additions & 13 deletions src/jsr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ use crate::source::LoadOptions;
use crate::source::LoadResponse;
use crate::source::Loader;
use crate::source::LoaderChecksum;
use crate::source::Locker;
use crate::Executor;

#[derive(Clone)]
pub struct PendingJsrPackageVersionInfoLoadItem {
pub checksum: String,
pub checksum_for_locker: Option<LoaderChecksum>,
pub info: Arc<JsrPackageVersionInfo>,
}

Expand Down Expand Up @@ -103,7 +104,7 @@ impl JsrMetadataStore {
&mut self,
package_nv: &PackageNv,
cache_setting: CacheSetting,
maybe_expected_checksum: Option<&str>,
maybe_locker: Option<&dyn Locker>,
services: JsrMetadataStoreServices,
) {
if self
Expand All @@ -121,24 +122,27 @@ impl JsrMetadataStore {
package_nv.name, package_nv.version
))
.unwrap();
let maybe_expected_checksum =
maybe_expected_checksum.map(|c| LoaderChecksum::new(c.to_string()));
let maybe_expected_checksum = maybe_locker
.as_ref()
.and_then(|locker| locker.get_pkg_manifest_checksum(package_nv));
let should_compute_checksum =
maybe_expected_checksum.is_none() && maybe_locker.is_some();
let fut = self.load_data(
specifier,
services,
cache_setting,
// we won't have a checksum when loading this the
// first time or when not using a lockfile
maybe_expected_checksum.clone(),
|content| {
// if we have the expected checksum, then we can re-use that here
let checksum = maybe_expected_checksum
.map(|c| c.into_string())
.unwrap_or_else(|| LoaderChecksum::gen(content));
// we won't have a checksum when not using a lockfile
maybe_expected_checksum,
move |content| {
let checksum_for_locker = if should_compute_checksum {
Some(LoaderChecksum::new(LoaderChecksum::gen(content)))
} else {
None
};
let version_info: JsrPackageVersionInfo =
serde_json::from_slice(content)?;
Ok(PendingJsrPackageVersionInfoLoadItem {
checksum,
checksum_for_locker,
info: Arc::new(version_info),
})
},
Expand Down
57 changes: 5 additions & 52 deletions src/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,11 @@ impl JsrPackageVersionInfo {

#[derive(Debug, Clone)]
struct PackageNvInfo {
manifest_checksum: String,
/// Collection of exports used.
exports: BTreeMap<String, String>,
found_dependencies: HashSet<JsrDepPackageReq>,
}

#[derive(Debug, Clone)]
pub struct PackageManifestIntegrityError {
pub nv: PackageNv,
pub actual: String,
pub expected: String,
}

#[derive(Debug, Clone, Default, Serialize)]
pub struct PackageSpecifiers {
#[serde(flatten)]
Expand Down Expand Up @@ -153,60 +145,21 @@ impl PackageSpecifiers {
self.package_reqs.insert(package_req, nv.clone());
}

pub(crate) fn ensure_package(
&mut self,
nv: PackageNv,
manifest_checksum: String,
) {
pub(crate) fn ensure_package(&mut self, nv: PackageNv) {
self.packages.entry(nv).or_insert_with(|| PackageNvInfo {
manifest_checksum,
exports: Default::default(),
found_dependencies: Default::default(),
});
}

pub(crate) fn get_manifest_checksum(&self, nv: &PackageNv) -> Option<&str> {
self.packages.get(nv).map(|p| p.manifest_checksum.as_str())
}

pub fn add_manifest_checksum(
&mut self,
nv: PackageNv,
checksum: String,
) -> Result<(), Box<PackageManifestIntegrityError>> {
let package = self.packages.get(&nv);
if let Some(package) = package {
if package.manifest_checksum != checksum {
Err(Box::new(PackageManifestIntegrityError {
nv,
actual: checksum,
expected: package.manifest_checksum.clone(),
}))
} else {
Ok(())
}
} else {
self.packages.insert(
nv,
PackageNvInfo {
manifest_checksum: checksum,
exports: Default::default(),
found_dependencies: Default::default(),
},
);
Ok(())
}
}

/// Gets the dependencies (package constraints) of JSR packages found in the graph.
pub fn packages_with_checksum_and_deps(
pub fn packages_with_deps(
&self,
) -> impl Iterator<
Item = (&PackageNv, &String, impl Iterator<Item = &JsrDepPackageReq>),
> {
) -> impl Iterator<Item = (&PackageNv, impl Iterator<Item = &JsrDepPackageReq>)>
{
self.packages.iter().map(|(nv, info)| {
let deps = info.found_dependencies.iter();
(nv, &info.manifest_checksum, deps)
(nv, deps)
})
}

Expand Down
60 changes: 47 additions & 13 deletions src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,43 +175,77 @@ impl fmt::Display for LoaderChecksum {
}

pub trait Locker {
fn get_checksum(&self, specifier: &ModuleSpecifier)
-> Option<LoaderChecksum>;
fn has_checksum(&self, specifier: &ModuleSpecifier) -> bool;
fn set_checksum(
fn get_remote_checksum(
&self,
specifier: &ModuleSpecifier,
) -> Option<LoaderChecksum>;
fn has_remote_checksum(&self, specifier: &ModuleSpecifier) -> bool;
fn set_remote_checksum(
&mut self,
specifier: &ModuleSpecifier,
checksum: LoaderChecksum,
);

fn get_pkg_manifest_checksum(
&self,
package_nv: &PackageNv,
) -> Option<LoaderChecksum>;
fn set_pkg_manifest_checksum(
&mut self,
package_nv: &PackageNv,
checksum: LoaderChecksum,
);
}

#[derive(Debug, Default, Clone)]
pub struct HashMapLocker(HashMap<ModuleSpecifier, LoaderChecksum>);
pub struct HashMapLocker {
remote: HashMap<ModuleSpecifier, LoaderChecksum>,
pkg_manifests: HashMap<PackageNv, LoaderChecksum>,
}

impl HashMapLocker {
pub fn inner(&self) -> &HashMap<ModuleSpecifier, LoaderChecksum> {
&self.0
pub fn remote(&self) -> &HashMap<ModuleSpecifier, LoaderChecksum> {
&self.remote
}

pub fn pkg_manifests(&self) -> &HashMap<PackageNv, LoaderChecksum> {
&self.pkg_manifests
}
}

impl Locker for HashMapLocker {
fn get_checksum(
fn get_remote_checksum(
&self,
specifier: &ModuleSpecifier,
) -> Option<LoaderChecksum> {
self.0.get(specifier).cloned()
self.remote.get(specifier).cloned()
}

fn has_checksum(&self, specifier: &ModuleSpecifier) -> bool {
self.0.contains_key(specifier)
fn has_remote_checksum(&self, specifier: &ModuleSpecifier) -> bool {
self.remote.contains_key(specifier)
}

fn set_checksum(
fn set_remote_checksum(
&mut self,
specifier: &ModuleSpecifier,
checksum: LoaderChecksum,
) {
self.0.insert(specifier.clone(), checksum);
self.remote.insert(specifier.clone(), checksum);
}

fn get_pkg_manifest_checksum(
&self,
package_nv: &PackageNv,
) -> Option<LoaderChecksum> {
self.pkg_manifests.get(package_nv).cloned()
}

fn set_pkg_manifest_checksum(
&mut self,
package_nv: &PackageNv,
checksum: LoaderChecksum,
) {
self.pkg_manifests.insert(package_nv.clone(), checksum);
}
}

Expand Down
27 changes: 21 additions & 6 deletions tests/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ pub struct TestBuilder {
workspace_members: Vec<WorkspaceMember>,
workspace_fast_check: bool,
lockfile_jsr_packages: BTreeMap<PackageReq, PackageNv>,
verify_and_fill_checksums: bool,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidentally leftover in last PR. This does nothing.

}

impl TestBuilder {
Expand All @@ -183,7 +182,6 @@ impl TestBuilder {
workspace_members: Default::default(),
workspace_fast_check: false,
lockfile_jsr_packages: Default::default(),
verify_and_fill_checksums: false,
}
}

Expand Down Expand Up @@ -238,17 +236,34 @@ impl TestBuilder {
}

#[allow(unused)]
pub fn verify_and_fill_checksums(&mut self, value: bool) -> &mut Self {
self.verify_and_fill_checksums = value;
pub fn ensure_locker(&mut self) -> &mut Self {
self.locker.get_or_insert_with(Default::default);
self
}

#[allow(unused)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these attributes?

Copy link
Member Author

@dsherret dsherret May 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple test runners sharing this code and they unfortunately error when one of them doesn't use a method.

pub fn add_checksum(&mut self, specifier: &str, checksum: &str) -> &mut Self {
pub fn add_remote_checksum(
&mut self,
specifier: &str,
checksum: &str,
) -> &mut Self {
let specifier = ModuleSpecifier::parse(specifier).unwrap();
let loader_checksum = LoaderChecksum::new(checksum.to_string());
let checksums = self.locker.get_or_insert_with(Default::default);
checksums.set_checksum(&specifier, loader_checksum);
checksums.set_remote_checksum(&specifier, loader_checksum);
self
}

#[allow(unused)]
pub fn add_pkg_manifest_checksum(
&mut self,
pkg_nv: &str,
checksum: &str,
) -> &mut Self {
let pkg_nv = PackageNv::from_str(pkg_nv).unwrap();
let loader_checksum = LoaderChecksum::new(checksum.to_string());
let checksums = self.locker.get_or_insert_with(Default::default);
checksums.set_pkg_manifest_checksum(&pkg_nv, loader_checksum);
self
}

Expand Down
4 changes: 2 additions & 2 deletions tests/specs/graph/checksums/invalid.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
~~ {
"checksums": {
"remoteChecksums": {
"https://localhost/mod.ts": "invalid"
}
} ~~
Expand Down Expand Up @@ -47,7 +47,7 @@ import 'https://localhost/mod.ts'
"redirects": {}
}

checksums:
remote checksums:
{
"https://localhost/mod.ts": "invalid"
}
Loading