@atlaspack/core 2.16.2-dev.14 → 2.16.2-dev.1c70d50f9.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +196 -0
- package/lib/AssetGraph.js +27 -7
- package/lib/Atlaspack.js +10 -2
- package/lib/BundleGraph.js +6 -105
- package/lib/Dependency.js +6 -2
- package/lib/Environment.js +5 -3
- package/lib/EnvironmentManager.js +137 -0
- package/lib/InternalConfig.js +3 -2
- package/lib/PackagerRunner.js +52 -15
- package/lib/RequestTracker.js +313 -94
- package/lib/UncommittedAsset.js +20 -2
- package/lib/applyRuntimes.js +2 -1
- package/lib/assetUtils.js +2 -1
- package/lib/atlaspack-v3/worker/worker.js +8 -0
- package/lib/index.js +29 -1
- package/lib/public/Asset.js +3 -2
- package/lib/public/Bundle.js +2 -1
- package/lib/public/BundleGraph.js +21 -8
- package/lib/public/Config.js +91 -3
- package/lib/public/Dependency.js +2 -1
- package/lib/public/MutableBundleGraph.js +2 -1
- package/lib/public/Target.js +2 -1
- package/lib/requests/AssetGraphRequest.js +13 -1
- package/lib/requests/AssetGraphRequestRust.js +17 -2
- package/lib/requests/AssetRequest.js +2 -1
- package/lib/requests/BundleGraphRequest.js +13 -1
- package/lib/requests/ConfigRequest.js +27 -4
- package/lib/requests/DevDepRequest.js +21 -1
- package/lib/requests/PathRequest.js +10 -0
- package/lib/requests/TargetRequest.js +18 -16
- package/lib/requests/WriteBundleRequest.js +15 -3
- package/lib/requests/WriteBundlesRequest.js +1 -0
- package/lib/resolveOptions.js +4 -2
- package/package.json +18 -25
- package/src/AssetGraph.js +30 -7
- package/src/Atlaspack.js +13 -5
- package/src/BundleGraph.js +13 -175
- package/src/Dependency.js +13 -5
- package/src/Environment.js +9 -6
- package/src/EnvironmentManager.js +145 -0
- package/src/InternalConfig.js +6 -5
- package/src/PackagerRunner.js +72 -20
- package/src/RequestTracker.js +532 -150
- package/src/UncommittedAsset.js +23 -3
- package/src/applyRuntimes.js +6 -1
- package/src/assetUtils.js +4 -3
- package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
- package/src/atlaspack-v3/worker/worker.js +7 -0
- package/src/index.js +5 -1
- package/src/public/Asset.js +9 -2
- package/src/public/Bundle.js +2 -1
- package/src/public/BundleGraph.js +22 -15
- package/src/public/Config.js +128 -14
- package/src/public/Dependency.js +2 -1
- package/src/public/MutableBundleGraph.js +5 -2
- package/src/public/Target.js +2 -1
- package/src/requests/AssetGraphRequest.js +13 -3
- package/src/requests/AssetGraphRequestRust.js +14 -2
- package/src/requests/AssetRequest.js +2 -1
- package/src/requests/BundleGraphRequest.js +13 -3
- package/src/requests/ConfigRequest.js +33 -9
- package/src/requests/DevDepRequest.js +44 -12
- package/src/requests/PathRequest.js +4 -0
- package/src/requests/TargetRequest.js +19 -25
- package/src/requests/WriteBundleRequest.js +14 -8
- package/src/requests/WriteBundlesRequest.js +1 -0
- package/src/resolveOptions.js +4 -2
- package/src/types.js +10 -7
- package/test/Environment.test.js +43 -34
- package/test/EnvironmentManager.test.js +192 -0
- package/test/PublicEnvironment.test.js +10 -7
- package/test/RequestTracker.test.js +115 -3
- package/test/public/Config.test.js +108 -0
- package/test/requests/ConfigRequest.test.js +187 -3
- package/test/test-utils.js +4 -9
package/lib/RequestTracker.js
CHANGED
|
@@ -6,9 +6,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.RequestGraph = void 0;
|
|
7
7
|
exports.cleanUpOrphans = cleanUpOrphans;
|
|
8
8
|
exports.default = void 0;
|
|
9
|
+
exports.getBiggestFSEventsInvalidations = getBiggestFSEventsInvalidations;
|
|
9
10
|
exports.getWatcherOptions = getWatcherOptions;
|
|
11
|
+
exports.invalidateRequestGraph = invalidateRequestGraph;
|
|
12
|
+
exports.invalidateRequestGraphFSEvents = invalidateRequestGraphFSEvents;
|
|
10
13
|
exports.readAndDeserializeRequestGraph = readAndDeserializeRequestGraph;
|
|
11
14
|
exports.requestTypes = exports.requestGraphEdgeTypes = void 0;
|
|
15
|
+
exports.runInvalidation = runInvalidation;
|
|
12
16
|
function _assert() {
|
|
13
17
|
const data = _interopRequireWildcard(require("assert"));
|
|
14
18
|
_assert = function () {
|
|
@@ -84,6 +88,14 @@ var _projectPath = require("./projectPath");
|
|
|
84
88
|
var _ReporterRunner = require("./ReporterRunner");
|
|
85
89
|
var _ConfigRequest = require("./requests/ConfigRequest");
|
|
86
90
|
var _utils2 = require("./utils");
|
|
91
|
+
function _perf_hooks() {
|
|
92
|
+
const data = require("perf_hooks");
|
|
93
|
+
_perf_hooks = function () {
|
|
94
|
+
return data;
|
|
95
|
+
};
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
var _EnvironmentManager = require("./EnvironmentManager");
|
|
87
99
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
88
100
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
89
101
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -151,7 +163,7 @@ const nodeFromOption = (option, value) => ({
|
|
|
151
163
|
hash: (0, _utils2.hashFromOption)(value)
|
|
152
164
|
});
|
|
153
165
|
const nodeFromConfigKey = (fileName, configKey, contentHash) => ({
|
|
154
|
-
id: `config_key:${(0, _projectPath.fromProjectPathRelative)(fileName)}:${configKey}`,
|
|
166
|
+
id: `config_key:${(0, _projectPath.fromProjectPathRelative)(fileName)}:${JSON.stringify(configKey)}`,
|
|
155
167
|
type: CONFIG_KEY,
|
|
156
168
|
configKey,
|
|
157
169
|
contentHash
|
|
@@ -279,6 +291,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
279
291
|
// If the node is invalidated, the cached request chunk on disk needs to be re-written
|
|
280
292
|
this.removeCachedRequestChunkForNode(nodeId);
|
|
281
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Nodes that are invalidated on start-up, such as JavaScript babel configuration files which are
|
|
297
|
+
* imported when the build kicks-off and might doing arbitrary work such as reading from the file
|
|
298
|
+
* system.
|
|
299
|
+
*/
|
|
282
300
|
invalidateUnpredictableNodes() {
|
|
283
301
|
for (let nodeId of this.unpredicatableNodeIds) {
|
|
284
302
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -286,6 +304,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
286
304
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
287
305
|
}
|
|
288
306
|
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Effectively uncacheable nodes.
|
|
310
|
+
*/
|
|
289
311
|
invalidateOnBuildNodes() {
|
|
290
312
|
for (let nodeId of this.invalidateOnBuildNodeIds) {
|
|
291
313
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -293,29 +315,45 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
293
315
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
294
316
|
}
|
|
295
317
|
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Nodes invalidated by environment changes, corresponds to `env: ...` inputs.
|
|
321
|
+
*/
|
|
296
322
|
invalidateEnvNodes(env) {
|
|
323
|
+
const invalidatedKeys = [];
|
|
297
324
|
for (let nodeId of this.envNodeIds) {
|
|
298
325
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
299
326
|
(0, _assert().default)(node.type === ENV);
|
|
300
|
-
|
|
327
|
+
const key = keyFromEnvContentKey(node.id);
|
|
328
|
+
if (env[key] !== node.value) {
|
|
329
|
+
invalidatedKeys.push(key);
|
|
301
330
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
302
331
|
for (let parentNode of parentNodes) {
|
|
303
332
|
this.invalidateNode(parentNode, _constants.ENV_CHANGE);
|
|
304
333
|
}
|
|
305
334
|
}
|
|
306
335
|
}
|
|
336
|
+
return invalidatedKeys;
|
|
307
337
|
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Nodes invalidated by option changes.
|
|
341
|
+
*/
|
|
308
342
|
invalidateOptionNodes(options) {
|
|
343
|
+
const invalidatedKeys = [];
|
|
309
344
|
for (let nodeId of this.optionNodeIds) {
|
|
310
345
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
311
346
|
(0, _assert().default)(node.type === OPTION);
|
|
312
|
-
|
|
347
|
+
const key = keyFromOptionContentKey(node.id);
|
|
348
|
+
if ((0, _utils2.hashFromOption)(options[key]) !== node.hash) {
|
|
349
|
+
invalidatedKeys.push(key);
|
|
313
350
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
314
351
|
for (let parentNode of parentNodes) {
|
|
315
352
|
this.invalidateNode(parentNode, _constants.OPTION_CHANGE);
|
|
316
353
|
}
|
|
317
354
|
}
|
|
318
355
|
}
|
|
356
|
+
return invalidatedKeys;
|
|
319
357
|
}
|
|
320
358
|
invalidateOnConfigKeyChange(requestNodeId, filePath, configKey, contentHash) {
|
|
321
359
|
let configKeyNodeId = this.addNode(nodeFromConfigKey(filePath, configKey, contentHash));
|
|
@@ -408,8 +446,8 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
408
446
|
this.invalidateOnBuildNodeIds.add(requestNodeId);
|
|
409
447
|
}
|
|
410
448
|
invalidateOnEnvChange(requestNodeId, env, value) {
|
|
411
|
-
|
|
412
|
-
|
|
449
|
+
const envNode = nodeFromEnv(env, value);
|
|
450
|
+
const envNodeId = this.addNode(envNode);
|
|
413
451
|
if (!this.hasEdge(requestNodeId, envNodeId, requestGraphEdgeTypes.invalidated_by_update)) {
|
|
414
452
|
this.addEdge(requestNodeId, envNodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
415
453
|
}
|
|
@@ -556,10 +594,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
556
594
|
aboveCache.set(fileNameNodeId, above);
|
|
557
595
|
return above;
|
|
558
596
|
};
|
|
597
|
+
const invalidationsByPath = new Map();
|
|
559
598
|
for (let {
|
|
560
599
|
path: _path,
|
|
561
600
|
type
|
|
562
601
|
} of events) {
|
|
602
|
+
const invalidationsBefore = this.getInvalidNodeCount();
|
|
563
603
|
if (!enableOptimization && process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' && ++count === 256) {
|
|
564
604
|
let duration = Date.now() - startTime;
|
|
565
605
|
predictedTime = duration * (events.length >> 8);
|
|
@@ -596,7 +636,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
596
636
|
this.invalidNodeIds.add(id);
|
|
597
637
|
}
|
|
598
638
|
}
|
|
599
|
-
return
|
|
639
|
+
return {
|
|
640
|
+
didInvalidate: true,
|
|
641
|
+
invalidationsByPath: new Map()
|
|
642
|
+
};
|
|
600
643
|
}
|
|
601
644
|
|
|
602
645
|
// sometimes mac os reports update events as create events.
|
|
@@ -653,10 +696,17 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
653
696
|
this.removeNode(nodeId, removeOrphans);
|
|
654
697
|
}
|
|
655
698
|
let configKeyNodes = this.configKeyNodes.get(_filePath);
|
|
656
|
-
|
|
699
|
+
|
|
700
|
+
// With granular invalidations we will always run this block,
|
|
701
|
+
// so even if we get a create event (for whatever reason), we will still
|
|
702
|
+
// try to limit invalidations from config key changes through hashing.
|
|
703
|
+
//
|
|
704
|
+
// Currently create events can invalidate a large number of nodes due to
|
|
705
|
+
// "create above" invalidations.
|
|
706
|
+
if (configKeyNodes) {
|
|
657
707
|
for (let nodeId of configKeyNodes) {
|
|
658
708
|
let isInvalid = type === 'delete';
|
|
659
|
-
if (type
|
|
709
|
+
if (type !== 'delete') {
|
|
660
710
|
let node = this.getNode(nodeId);
|
|
661
711
|
(0, _assert().default)(node && node.type === CONFIG_KEY);
|
|
662
712
|
let contentHash = await (0, _ConfigRequest.getConfigKeyContentHash)(_filePath, node.configKey, options);
|
|
@@ -671,6 +721,8 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
671
721
|
}
|
|
672
722
|
}
|
|
673
723
|
}
|
|
724
|
+
const invalidationsAfter = this.getInvalidNodeCount();
|
|
725
|
+
invalidationsByPath.set(_path, (invalidationsByPath.get(_path) ?? 0) + (invalidationsAfter - invalidationsBefore));
|
|
674
726
|
}
|
|
675
727
|
if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
|
|
676
728
|
cleanUpOrphans(this);
|
|
@@ -688,7 +740,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
688
740
|
numberOfInvalidatedNodes: invalidatedNodes.size
|
|
689
741
|
}
|
|
690
742
|
});
|
|
691
|
-
return
|
|
743
|
+
return {
|
|
744
|
+
didInvalidate,
|
|
745
|
+
invalidationsByPath
|
|
746
|
+
};
|
|
692
747
|
}
|
|
693
748
|
hasCachedRequestChunk(index) {
|
|
694
749
|
return this.cachedRequestChunks.has(index);
|
|
@@ -699,6 +754,13 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
699
754
|
removeCachedRequestChunkForNode(nodeId) {
|
|
700
755
|
this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
|
|
701
756
|
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Returns the number of invalidated nodes in the graph.
|
|
760
|
+
*/
|
|
761
|
+
getInvalidNodeCount() {
|
|
762
|
+
return this.invalidNodeIds.size;
|
|
763
|
+
}
|
|
702
764
|
}
|
|
703
765
|
exports.RequestGraph = RequestGraph;
|
|
704
766
|
class RequestTracker {
|
|
@@ -717,6 +779,9 @@ class RequestTracker {
|
|
|
717
779
|
|
|
718
780
|
// TODO: refactor (abortcontroller should be created by RequestTracker)
|
|
719
781
|
setSignal(signal) {
|
|
782
|
+
if ((0, _featureFlags().getFeatureFlag)('fixBuildAbortCorruption')) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
720
785
|
this.signal = signal;
|
|
721
786
|
}
|
|
722
787
|
startRequest(request) {
|
|
@@ -857,7 +922,9 @@ class RequestTracker {
|
|
|
857
922
|
options: this.options,
|
|
858
923
|
rustAtlaspack: this.rustAtlaspack
|
|
859
924
|
});
|
|
860
|
-
(0,
|
|
925
|
+
if (!(0, _featureFlags().getFeatureFlag)('fixBuildAbortCorruption')) {
|
|
926
|
+
(0, _utils2.assertSignalNotAborted)(this.signal);
|
|
927
|
+
}
|
|
861
928
|
this.completeRequest(requestNodeId);
|
|
862
929
|
deferred.resolve(true);
|
|
863
930
|
return result;
|
|
@@ -944,84 +1011,88 @@ class RequestTracker {
|
|
|
944
1011
|
return result;
|
|
945
1012
|
}
|
|
946
1013
|
}
|
|
947
|
-
await runCacheImprovements(async cache => {
|
|
948
|
-
await cache.getNativeRef().startWriteTransaction();
|
|
949
|
-
}, () => Promise.resolve());
|
|
950
1014
|
let cacheKey = getCacheKey(this.options);
|
|
951
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1015
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1016
|
+
let snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
952
1017
|
if (this.options.shouldDisableCache) {
|
|
953
1018
|
return;
|
|
954
1019
|
}
|
|
955
1020
|
let total = 0;
|
|
956
|
-
(
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
size: this.graph.nodes.length
|
|
961
|
-
});
|
|
962
|
-
let serialisedGraph = this.graph.serialize();
|
|
963
|
-
|
|
964
|
-
// Delete an existing request graph cache, to prevent invalid states
|
|
965
|
-
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
966
|
-
const serialiseAndSet = async (key, contents) => {
|
|
967
|
-
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
968
|
-
throw new Error('Serialization was aborted');
|
|
969
|
-
}
|
|
970
|
-
await runCacheImprovements(cache => {
|
|
971
|
-
(0, _logger().instrument)(`cache.put(${key})`, () => {
|
|
972
|
-
cache.getNativeRef().putNoConfirm(key, (0, _buildCache().serialize)(contents));
|
|
973
|
-
});
|
|
974
|
-
return Promise.resolve();
|
|
975
|
-
}, async () => {
|
|
976
|
-
await this.options.cache.setLargeBlob(key, (0, _buildCache().serialize)(contents), signal ? {
|
|
977
|
-
signal: signal
|
|
978
|
-
} : undefined);
|
|
979
|
-
});
|
|
980
|
-
total += 1;
|
|
1021
|
+
await runCacheImprovements(async cache => {
|
|
1022
|
+
await cache.getNativeRef().startWriteTransaction();
|
|
1023
|
+
}, () => Promise.resolve());
|
|
1024
|
+
try {
|
|
981
1025
|
(0, _ReporterRunner.report)({
|
|
982
1026
|
type: 'cache',
|
|
983
|
-
phase: '
|
|
1027
|
+
phase: 'start',
|
|
984
1028
|
total,
|
|
985
1029
|
size: this.graph.nodes.length
|
|
986
1030
|
});
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1031
|
+
if ((0, _featureFlags().getFeatureFlag)('environmentDeduplication')) {
|
|
1032
|
+
await (0, _EnvironmentManager.writeEnvironmentsToCache)(options.cache);
|
|
1033
|
+
}
|
|
1034
|
+
let serialisedGraph = this.graph.serialize();
|
|
991
1035
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1036
|
+
// Delete an existing request graph cache, to prevent invalid states
|
|
1037
|
+
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
1038
|
+
const serialiseAndSet = async (key, contents) => {
|
|
1039
|
+
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
1040
|
+
throw new Error('Serialization was aborted');
|
|
1041
|
+
}
|
|
1042
|
+
await runCacheImprovements(cache => {
|
|
1043
|
+
(0, _logger().instrument)(`RequestTracker::writeToCache::cache.put(${key})`, () => {
|
|
1044
|
+
cache.getNativeRef().putNoConfirm(key, (0, _buildCache().serialize)(contents));
|
|
1045
|
+
});
|
|
1046
|
+
return Promise.resolve();
|
|
1047
|
+
}, async () => {
|
|
1048
|
+
await this.options.cache.setLargeBlob(key, (0, _buildCache().serialize)(contents), signal ? {
|
|
1049
|
+
signal: signal
|
|
1050
|
+
} : undefined);
|
|
1051
|
+
});
|
|
1052
|
+
total += 1;
|
|
1053
|
+
(0, _ReporterRunner.report)({
|
|
1054
|
+
type: 'cache',
|
|
1055
|
+
phase: 'write',
|
|
1056
|
+
total,
|
|
1057
|
+
size: this.graph.nodes.length
|
|
1058
|
+
});
|
|
1059
|
+
};
|
|
1060
|
+
let queue = new (_utils().PromiseQueue)({
|
|
1061
|
+
maxConcurrent: 32
|
|
1062
|
+
});
|
|
999
1063
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1064
|
+
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1065
|
+
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1066
|
+
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1067
|
+
let node = serialisedGraph.nodes[i];
|
|
1068
|
+
let resultCacheKey = node === null || node === void 0 ? void 0 : node.resultCacheKey;
|
|
1069
|
+
if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST && resultCacheKey != null && (node === null || node === void 0 ? void 0 : node.result) != null) {
|
|
1070
|
+
queue.add(() => serialiseAndSet(resultCacheKey, node.result));
|
|
1071
|
+
|
|
1072
|
+
// eslint-disable-next-line no-unused-vars
|
|
1073
|
+
let {
|
|
1074
|
+
result: _,
|
|
1075
|
+
...newNode
|
|
1076
|
+
} = node;
|
|
1077
|
+
cacheableNodes[i] = newNode;
|
|
1078
|
+
} else {
|
|
1079
|
+
cacheableNodes[i] = node;
|
|
1080
|
+
}
|
|
1008
1081
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
}
|
|
1082
|
+
let nodeCountsPerBlob = [];
|
|
1083
|
+
for (let i = 0; i * this.graph.nodesPerBlob < cacheableNodes.length; i += 1) {
|
|
1084
|
+
let nodesStartIndex = i * this.graph.nodesPerBlob;
|
|
1085
|
+
let nodesEndIndex = Math.min((i + 1) * this.graph.nodesPerBlob, cacheableNodes.length);
|
|
1086
|
+
nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
|
|
1087
|
+
if (!this.graph.hasCachedRequestChunk(i)) {
|
|
1088
|
+
// We assume the request graph nodes are immutable and won't change
|
|
1089
|
+
let nodesToCache = cacheableNodes.slice(nodesStartIndex, nodesEndIndex);
|
|
1090
|
+
queue.add(() => serialiseAndSet(getRequestGraphNodeKey(i, cacheKey), nodesToCache).then(() => {
|
|
1091
|
+
// Succeeded in writing to disk, save that we have completed this chunk
|
|
1092
|
+
this.graph.setCachedRequestChunk(i);
|
|
1093
|
+
}));
|
|
1094
|
+
}
|
|
1022
1095
|
}
|
|
1023
|
-
}
|
|
1024
|
-
try {
|
|
1025
1096
|
await queue.run();
|
|
1026
1097
|
|
|
1027
1098
|
// Set the request graph after the queue is flushed to avoid writing an invalid state
|
|
@@ -1030,7 +1101,7 @@ class RequestTracker {
|
|
|
1030
1101
|
nodeCountsPerBlob,
|
|
1031
1102
|
nodes: undefined
|
|
1032
1103
|
});
|
|
1033
|
-
await runCacheImprovements(() => serialiseAndSet(
|
|
1104
|
+
await runCacheImprovements(() => serialiseAndSet(`${cacheKey}/cache_metadata`, {
|
|
1034
1105
|
version: _constants.ATLASPACK_VERSION,
|
|
1035
1106
|
entries: this.options.entries,
|
|
1036
1107
|
mode: this.options.mode,
|
|
@@ -1038,15 +1109,16 @@ class RequestTracker {
|
|
|
1038
1109
|
watchBackend: this.options.watchBackend
|
|
1039
1110
|
}), () => Promise.resolve());
|
|
1040
1111
|
let opts = getWatcherOptions(this.options);
|
|
1041
|
-
let snapshotPath = _path2().default.join(this.options.cacheDir,
|
|
1112
|
+
let snapshotPath = _path2().default.join(this.options.cacheDir, snapshotKey + '.txt');
|
|
1042
1113
|
await this.options.outputFS.writeSnapshot(this.options.watchDir, snapshotPath, opts);
|
|
1043
1114
|
} catch (err) {
|
|
1044
1115
|
// If we have aborted, ignore the error and continue
|
|
1045
1116
|
if (!(signal !== null && signal !== void 0 && signal.aborted)) throw err;
|
|
1117
|
+
} finally {
|
|
1118
|
+
await runCacheImprovements(async cache => {
|
|
1119
|
+
await cache.getNativeRef().commitWriteTransaction();
|
|
1120
|
+
}, () => Promise.resolve());
|
|
1046
1121
|
}
|
|
1047
|
-
await runCacheImprovements(async cache => {
|
|
1048
|
-
await cache.getNativeRef().commitWriteTransaction();
|
|
1049
|
-
}, () => Promise.resolve());
|
|
1050
1122
|
(0, _ReporterRunner.report)({
|
|
1051
1123
|
type: 'cache',
|
|
1052
1124
|
phase: 'end',
|
|
@@ -1083,17 +1155,30 @@ function getWatcherOptions({
|
|
|
1083
1155
|
};
|
|
1084
1156
|
}
|
|
1085
1157
|
function getCacheKey(options) {
|
|
1158
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1159
|
+
const hash = (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1160
|
+
return `RequestTracker/${_constants.ATLASPACK_VERSION}/${hash}`;
|
|
1161
|
+
}
|
|
1086
1162
|
return (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1087
1163
|
}
|
|
1088
1164
|
function getRequestGraphNodeKey(index, cacheKey) {
|
|
1165
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1166
|
+
return `${cacheKey}/RequestGraph/nodes/${index}`;
|
|
1167
|
+
}
|
|
1089
1168
|
return `requestGraph-nodes-${index}-${cacheKey}`;
|
|
1090
1169
|
}
|
|
1091
1170
|
async function readAndDeserializeRequestGraph(cache, requestGraphKey, cacheKey) {
|
|
1092
1171
|
let bufferLength = 0;
|
|
1093
1172
|
const getAndDeserialize = async key => {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1173
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1174
|
+
const buffer = await cache.getBlob(key);
|
|
1175
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1176
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1177
|
+
} else {
|
|
1178
|
+
const buffer = await cache.getLargeBlob(key);
|
|
1179
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1180
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1181
|
+
}
|
|
1097
1182
|
};
|
|
1098
1183
|
let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
|
|
1099
1184
|
let nodePromises = serializedRequestGraph.nodeCountsPerBlob.map(async (nodesCount, i) => {
|
|
@@ -1115,19 +1200,33 @@ async function loadRequestGraph(options) {
|
|
|
1115
1200
|
return new RequestGraph();
|
|
1116
1201
|
}
|
|
1117
1202
|
let cacheKey = getCacheKey(options);
|
|
1118
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1203
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1119
1204
|
let timeout;
|
|
1120
|
-
const snapshotKey = `snapshot-${cacheKey}`;
|
|
1205
|
+
const snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
1121
1206
|
const snapshotPath = _path2().default.join(options.cacheDir, snapshotKey + '.txt');
|
|
1207
|
+
const commonMeta = {
|
|
1208
|
+
cacheKey,
|
|
1209
|
+
snapshotKey,
|
|
1210
|
+
cacheKeyOptions: {
|
|
1211
|
+
version: _constants.ATLASPACK_VERSION,
|
|
1212
|
+
entries: options.entries,
|
|
1213
|
+
mode: options.mode,
|
|
1214
|
+
shouldBuildLazily: options.shouldBuildLazily,
|
|
1215
|
+
watchBackend: options.watchBackend
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1122
1218
|
_logger().default.verbose({
|
|
1123
1219
|
origin: '@atlaspack/core',
|
|
1124
1220
|
message: 'Loading request graph',
|
|
1125
1221
|
meta: {
|
|
1126
|
-
|
|
1127
|
-
snapshotKey
|
|
1222
|
+
...commonMeta
|
|
1128
1223
|
}
|
|
1129
1224
|
});
|
|
1130
|
-
if (
|
|
1225
|
+
if ((0, _featureFlags().getFeatureFlag)('environmentDeduplication')) {
|
|
1226
|
+
await (0, _EnvironmentManager.loadEnvironmentsFromCache)(options.cache);
|
|
1227
|
+
}
|
|
1228
|
+
const hasRequestGraphInCache = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.has(requestGraphKey) : await options.cache.hasLargeBlob(requestGraphKey);
|
|
1229
|
+
if (hasRequestGraphInCache) {
|
|
1131
1230
|
try {
|
|
1132
1231
|
let {
|
|
1133
1232
|
requestGraph
|
|
@@ -1146,16 +1245,29 @@ async function loadRequestGraph(options) {
|
|
|
1146
1245
|
origin: '@atlaspack/core',
|
|
1147
1246
|
message: `File system event count: ${events.length}`,
|
|
1148
1247
|
meta: {
|
|
1248
|
+
...commonMeta,
|
|
1149
1249
|
trackableEvent: 'watcher_events_count',
|
|
1150
1250
|
watcherEventCount: events.length,
|
|
1151
1251
|
duration: Date.now() - startTime
|
|
1152
1252
|
}
|
|
1153
1253
|
});
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1254
|
+
if ((0, _featureFlags().getFeatureFlag)('verboseRequestInvalidationStats')) {
|
|
1255
|
+
const invalidationStats = await invalidateRequestGraph(requestGraph, options, events);
|
|
1256
|
+
_logger().default.verbose({
|
|
1257
|
+
origin: '@atlaspack/core',
|
|
1258
|
+
message: 'Request track loaded from cache',
|
|
1259
|
+
meta: {
|
|
1260
|
+
...commonMeta,
|
|
1261
|
+
trackableEvent: 'request_tracker_cache_key_hit',
|
|
1262
|
+
invalidationStats
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
} else {
|
|
1266
|
+
requestGraph.invalidateUnpredictableNodes();
|
|
1267
|
+
requestGraph.invalidateOnBuildNodes();
|
|
1268
|
+
requestGraph.invalidateEnvNodes(options.env);
|
|
1269
|
+
requestGraph.invalidateOptionNodes(options);
|
|
1270
|
+
}
|
|
1159
1271
|
return requestGraph;
|
|
1160
1272
|
} catch (e) {
|
|
1161
1273
|
// Prevent logging fs events took too long warning
|
|
@@ -1170,12 +1282,104 @@ async function loadRequestGraph(options) {
|
|
|
1170
1282
|
origin: '@atlaspack/core',
|
|
1171
1283
|
message: 'Cache entry for request tracker was not found, initializing a clean cache.',
|
|
1172
1284
|
meta: {
|
|
1173
|
-
|
|
1174
|
-
|
|
1285
|
+
...commonMeta,
|
|
1286
|
+
trackableEvent: 'request_tracker_cache_key_miss'
|
|
1175
1287
|
}
|
|
1176
1288
|
});
|
|
1177
1289
|
return new RequestGraph();
|
|
1178
1290
|
}
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* A wrapper around an invalidation type / method
|
|
1294
|
+
*/
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* Details about an invalidation.
|
|
1298
|
+
*
|
|
1299
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1300
|
+
* by path.
|
|
1301
|
+
*
|
|
1302
|
+
* If this is a env or option invalidation, this key will contain the list of changed environment
|
|
1303
|
+
* variables or options.
|
|
1304
|
+
*/
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Number of invalidations for a given file-system event.
|
|
1308
|
+
*/
|
|
1309
|
+
|
|
1310
|
+
/**
|
|
1311
|
+
* Information about a certain cache invalidation type.
|
|
1312
|
+
*/
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Respond to unpredictable, build, environment changes, option changes and file-system events
|
|
1316
|
+
* invalidating RequestGraph nodes.
|
|
1317
|
+
*
|
|
1318
|
+
* Returns the count of nodes invalidated by each invalidation type.
|
|
1319
|
+
*/
|
|
1320
|
+
async function invalidateRequestGraph(requestGraph, options, events) {
|
|
1321
|
+
const invalidationFns = [{
|
|
1322
|
+
key: 'unpredictable',
|
|
1323
|
+
fn: () => requestGraph.invalidateUnpredictableNodes()
|
|
1324
|
+
}, {
|
|
1325
|
+
key: 'onBuild',
|
|
1326
|
+
fn: () => requestGraph.invalidateOnBuildNodes()
|
|
1327
|
+
}, {
|
|
1328
|
+
key: 'env',
|
|
1329
|
+
fn: () => requestGraph.invalidateEnvNodes(options.env)
|
|
1330
|
+
}, {
|
|
1331
|
+
key: 'option',
|
|
1332
|
+
fn: () => requestGraph.invalidateOptionNodes(options)
|
|
1333
|
+
}, {
|
|
1334
|
+
key: 'fsEvents',
|
|
1335
|
+
fn: () => invalidateRequestGraphFSEvents(requestGraph, options, events)
|
|
1336
|
+
}];
|
|
1337
|
+
const invalidations = [];
|
|
1338
|
+
for (const invalidation of invalidationFns) {
|
|
1339
|
+
invalidations.push(await runInvalidation(requestGraph, invalidation));
|
|
1340
|
+
}
|
|
1341
|
+
const invalidatedCount = invalidations.reduce((acc, invalidation) => acc + invalidation.count, 0);
|
|
1342
|
+
const requestCount = requestGraph.nodes.reduce((acc, node) => acc + ((node === null || node === void 0 ? void 0 : node.type) === REQUEST ? 1 : 0), 0);
|
|
1343
|
+
const nodeCount = requestGraph.nodes.length;
|
|
1344
|
+
return {
|
|
1345
|
+
invalidations,
|
|
1346
|
+
nodeCount,
|
|
1347
|
+
requestCount,
|
|
1348
|
+
invalidatedCount,
|
|
1349
|
+
nodeInvalidationRatio: invalidatedCount / nodeCount,
|
|
1350
|
+
requestInvalidationRatio: invalidatedCount / requestCount
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Invalidate the request graph based on file-system events.
|
|
1355
|
+
*
|
|
1356
|
+
* Returns statistics about the invalidations.
|
|
1357
|
+
*/
|
|
1358
|
+
async function invalidateRequestGraphFSEvents(requestGraph, options, events) {
|
|
1359
|
+
const {
|
|
1360
|
+
invalidationsByPath
|
|
1361
|
+
} = await requestGraph.respondToFSEvents(options.unstableFileInvalidations || events, options, 10000, true);
|
|
1362
|
+
const biggestInvalidations = getBiggestFSEventsInvalidations(invalidationsByPath);
|
|
1363
|
+
return {
|
|
1364
|
+
biggestInvalidations
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Runs an invalidation function and reports metrics.
|
|
1369
|
+
*/
|
|
1370
|
+
async function runInvalidation(requestGraph, invalidationFn) {
|
|
1371
|
+
const start = _perf_hooks().performance.now();
|
|
1372
|
+
const startInvalidationCount = requestGraph.getInvalidNodeCount();
|
|
1373
|
+
const result = await invalidationFn.fn();
|
|
1374
|
+
const count = requestGraph.getInvalidNodeCount() - startInvalidationCount;
|
|
1375
|
+
const duration = _perf_hooks().performance.now() - start;
|
|
1376
|
+
return {
|
|
1377
|
+
key: invalidationFn.key,
|
|
1378
|
+
count,
|
|
1379
|
+
detail: result ?? null,
|
|
1380
|
+
duration
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1179
1383
|
function logErrorOnBailout(options, snapshotPath, e) {
|
|
1180
1384
|
if (e.message && e.message.includes('invalid clockspec')) {
|
|
1181
1385
|
const snapshotContents = options.inputFS.readFileSync(snapshotPath, 'utf-8');
|
|
@@ -1215,4 +1419,19 @@ function cleanUpOrphans(graph) {
|
|
|
1215
1419
|
}
|
|
1216
1420
|
});
|
|
1217
1421
|
return removedNodeIds;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/**
|
|
1425
|
+
* Returns paths that invalidated the most nodes
|
|
1426
|
+
*/
|
|
1427
|
+
function getBiggestFSEventsInvalidations(invalidationsByPath, limit = 10) {
|
|
1428
|
+
const invalidations = [];
|
|
1429
|
+
for (const [path, count] of invalidationsByPath) {
|
|
1430
|
+
invalidations.push({
|
|
1431
|
+
path,
|
|
1432
|
+
count
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
invalidations.sort((a, b) => b.count - a.count);
|
|
1436
|
+
return invalidations.slice(0, limit);
|
|
1218
1437
|
}
|