fix(core): fix performance of hashing external dependencies up front (#18359)
This commit is contained in:
parent
4304a451cc
commit
3eba026e39
@ -63,7 +63,7 @@ exports[`TaskHasher hashTarget should hash entire subtree of dependencies 1`] =
|
|||||||
},
|
},
|
||||||
"runtime": {},
|
"runtime": {},
|
||||||
},
|
},
|
||||||
"value": "17607022607820563118",
|
"value": "14419327228911184578",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ exports[`TaskHasher hashTarget should hash executor dependencies of @nx packages
|
|||||||
},
|
},
|
||||||
"runtime": {},
|
"runtime": {},
|
||||||
},
|
},
|
||||||
"value": "15096054768893599383",
|
"value": "379625642227035180",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ exports[`TaskHasher hashTarget should use externalDependencies to override nx:ru
|
|||||||
},
|
},
|
||||||
"runtime": {},
|
"runtime": {},
|
||||||
},
|
},
|
||||||
"value": "18142315317355318287",
|
"value": "14779270419297346086",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ exports[`TaskHasher should hash missing dependent npm project versions 1`] = `
|
|||||||
},
|
},
|
||||||
"runtime": {},
|
"runtime": {},
|
||||||
},
|
},
|
||||||
"value": "3668827038634092448",
|
"value": "13210933885500739919",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ exports[`TaskHasher should hash npm project versions 1`] = `
|
|||||||
},
|
},
|
||||||
"runtime": {},
|
"runtime": {},
|
||||||
},
|
},
|
||||||
"value": "3668827038634092448",
|
"value": "13210933885500739919",
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -976,23 +976,23 @@ describe('TaskHasher', () => {
|
|||||||
const hasher1 = createHasher();
|
const hasher1 = createHasher();
|
||||||
const hasher2 = createHasher();
|
const hasher2 = createHasher();
|
||||||
|
|
||||||
const hashA1 = hasher1.hashTask({
|
const hashA1 = await hasher1.hashTask({
|
||||||
id: 'a-build',
|
id: 'a-build',
|
||||||
target: { project: 'a', target: 'build' },
|
target: { project: 'a', target: 'build' },
|
||||||
overrides: {},
|
overrides: {},
|
||||||
});
|
});
|
||||||
const hashB1 = hasher1.hashTask({
|
const hashB1 = await hasher1.hashTask({
|
||||||
id: 'b-build',
|
id: 'b-build',
|
||||||
target: { project: 'b', target: 'build' },
|
target: { project: 'b', target: 'build' },
|
||||||
overrides: {},
|
overrides: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const hashB2 = hasher2.hashTask({
|
const hashB2 = await hasher2.hashTask({
|
||||||
id: 'b-build',
|
id: 'b-build',
|
||||||
target: { project: 'b', target: 'build' },
|
target: { project: 'b', target: 'build' },
|
||||||
overrides: {},
|
overrides: {},
|
||||||
});
|
});
|
||||||
const hashA2 = hasher2.hashTask({
|
const hashA2 = await hasher2.hashTask({
|
||||||
id: 'a-build',
|
id: 'a-build',
|
||||||
target: { project: 'a', target: 'build' },
|
target: { project: 'a', target: 'build' },
|
||||||
overrides: {},
|
overrides: {},
|
||||||
|
|||||||
@ -186,9 +186,9 @@ class TaskHasherImpl {
|
|||||||
private runtimeHashes: {
|
private runtimeHashes: {
|
||||||
[runtime: string]: Promise<PartialHash>;
|
[runtime: string]: Promise<PartialHash>;
|
||||||
} = {};
|
} = {};
|
||||||
private externalDependencyHashes: Map<string, PartialHash> = new Map<
|
private externalDependencyHashes: Map<string, PartialHash[]> = new Map<
|
||||||
string,
|
string,
|
||||||
PartialHash
|
PartialHash[]
|
||||||
>();
|
>();
|
||||||
private allExternalDependenciesHash: PartialHash;
|
private allExternalDependenciesHash: PartialHash;
|
||||||
private projectRootMappings = createProjectRootMappings(
|
private projectRootMappings = createProjectRootMappings(
|
||||||
@ -300,11 +300,16 @@ class TaskHasherImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private combinePartialHashes(partialHashes: PartialHash[]): PartialHash {
|
private combinePartialHashes(partialHashes: PartialHash[]): PartialHash {
|
||||||
let details = {};
|
if (partialHashes.length === 1) {
|
||||||
for (const partial of partialHashes) {
|
return partialHashes[0];
|
||||||
details = { ...details, ...partial.details };
|
|
||||||
}
|
}
|
||||||
const value = hashArray(partialHashes.map(({ value }) => value));
|
const details = {};
|
||||||
|
const hashValues: string[] = [];
|
||||||
|
for (const partial of partialHashes) {
|
||||||
|
hashValues.push(partial.value);
|
||||||
|
Object.assign(details, partial.details);
|
||||||
|
}
|
||||||
|
const value = hashArray(hashValues);
|
||||||
|
|
||||||
return { value, details };
|
return { value, details };
|
||||||
}
|
}
|
||||||
@ -416,25 +421,29 @@ class TaskHasherImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getExternalDependencyHash(externalNodeName: string) {
|
private getExternalDependencyHash(externalNodeName: string) {
|
||||||
return this.externalDependencyHashes.get(externalNodeName);
|
const combinedHash = this.combinePartialHashes(
|
||||||
|
this.externalDependencyHashes.get(externalNodeName)
|
||||||
|
);
|
||||||
|
// Set the combined hash into the hashes so it's not recalculated next time
|
||||||
|
this.externalDependencyHashes.set(externalNodeName, [combinedHash]);
|
||||||
|
return combinedHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private hashExternalDependency(
|
private hashExternalDependency(
|
||||||
externalNodeName: string,
|
externalNodeName: string,
|
||||||
visited: Set<string>
|
visited: Set<string>
|
||||||
): PartialHash {
|
): PartialHash[] {
|
||||||
// try to retrieve the hash from cache
|
// try to retrieve the hash from cache
|
||||||
if (this.externalDependencyHashes.has(externalNodeName)) {
|
if (this.externalDependencyHashes.has(externalNodeName)) {
|
||||||
return this.externalDependencyHashes.get(externalNodeName);
|
return this.externalDependencyHashes.get(externalNodeName);
|
||||||
}
|
}
|
||||||
visited.add(externalNodeName);
|
visited.add(externalNodeName);
|
||||||
const node = this.projectGraph.externalNodes[externalNodeName];
|
const node = this.projectGraph.externalNodes[externalNodeName];
|
||||||
let partialHash: PartialHash;
|
const partialHashes: Set<PartialHash> = new Set<PartialHash>();
|
||||||
if (node) {
|
if (node) {
|
||||||
const partialHashes: PartialHash[] = [];
|
|
||||||
if (node.data.hash) {
|
if (node.data.hash) {
|
||||||
// we already know the hash of this dependency
|
// we already know the hash of this dependency
|
||||||
partialHashes.push({
|
partialHashes.add({
|
||||||
value: node.data.hash,
|
value: node.data.hash,
|
||||||
details: {
|
details: {
|
||||||
[externalNodeName]: node.data.hash,
|
[externalNodeName]: node.data.hash,
|
||||||
@ -442,7 +451,7 @@ class TaskHasherImpl {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// we take version as a hash
|
// we take version as a hash
|
||||||
partialHashes.push({
|
partialHashes.add({
|
||||||
value: node.data.version,
|
value: node.data.version,
|
||||||
details: {
|
details: {
|
||||||
[externalNodeName]: node.data.version,
|
[externalNodeName]: node.data.version,
|
||||||
@ -453,25 +462,27 @@ class TaskHasherImpl {
|
|||||||
if (this.projectGraph.dependencies[externalNodeName]) {
|
if (this.projectGraph.dependencies[externalNodeName]) {
|
||||||
this.projectGraph.dependencies[externalNodeName].forEach((d) => {
|
this.projectGraph.dependencies[externalNodeName].forEach((d) => {
|
||||||
if (!visited.has(d.target)) {
|
if (!visited.has(d.target)) {
|
||||||
partialHashes.push(this.hashExternalDependency(d.target, visited));
|
for (const hash of this.hashExternalDependency(d.target, visited)) {
|
||||||
|
partialHashes.add(hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
partialHash = this.combinePartialHashes(partialHashes);
|
|
||||||
} else {
|
} else {
|
||||||
// unknown dependency
|
// unknown dependency
|
||||||
// this may occur if dependency is not an npm package
|
// this may occur if dependency is not an npm package
|
||||||
// but rather symlinked in node_modules or it's pointing to a remote git repo
|
// but rather symlinked in node_modules or it's pointing to a remote git repo
|
||||||
// in this case we have no information about the versioning of the given package
|
// in this case we have no information about the versioning of the given package
|
||||||
partialHash = {
|
partialHashes.add({
|
||||||
value: `__${externalNodeName}__`,
|
value: `__${externalNodeName}__`,
|
||||||
details: {
|
details: {
|
||||||
[externalNodeName]: `__${externalNodeName}__`,
|
[externalNodeName]: `__${externalNodeName}__`,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
this.externalDependencyHashes.set(externalNodeName, partialHash);
|
const partialHashArray = Array.from(partialHashes);
|
||||||
return partialHash;
|
this.externalDependencyHashes.set(externalNodeName, partialHashArray);
|
||||||
|
return partialHashArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private hashTarget(
|
private hashTarget(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user