@atlaspack/core 2.16.2-dev.14 → 2.16.2-dev.55
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 +86 -0
- package/lib/Atlaspack.js +10 -2
- package/lib/AtlaspackConfig.schema.js +7 -1
- package/lib/BundleGraph.js +2 -100
- package/lib/PackagerRunner.js +44 -9
- package/lib/RequestTracker.js +326 -121
- package/lib/Transformation.js +2 -2
- package/lib/UncommittedAsset.js +17 -0
- package/lib/atlaspack-v3/worker/compat/environment.js +2 -2
- package/lib/atlaspack-v3/worker/compat/mutable-asset.js +6 -6
- package/lib/atlaspack-v3/worker/compat/plugin-config.js +5 -5
- package/lib/atlaspack-v3/worker/index.js +3 -0
- package/lib/atlaspack-v3/worker/worker.js +8 -0
- package/lib/dumpGraphToGraphViz.js +1 -1
- package/lib/public/BundleGraph.js +21 -8
- package/lib/public/Config.js +28 -0
- package/lib/requests/AssetGraphRequest.js +13 -1
- package/lib/requests/BundleGraphRequest.js +13 -1
- package/lib/requests/WriteBundleRequest.js +11 -2
- package/lib/resolveOptions.js +7 -4
- package/lib/worker.js +18 -1
- package/package.json +23 -19
- package/src/Atlaspack.js +13 -5
- package/src/BundleGraph.js +0 -167
- package/src/PackagerRunner.js +60 -9
- package/src/RequestTracker.js +491 -137
- package/src/UncommittedAsset.js +16 -1
- package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
- package/src/atlaspack-v3/worker/worker.js +7 -0
- package/src/public/BundleGraph.js +22 -15
- package/src/public/Config.js +39 -5
- package/src/requests/AssetGraphRequest.js +13 -3
- package/src/requests/BundleGraphRequest.js +13 -3
- package/src/requests/WriteBundleRequest.js +9 -2
- package/src/resolveOptions.js +4 -2
- package/test/RequestTracker.test.js +120 -5
- package/test/test-utils.js +1 -7
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,13 @@ 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
|
+
}
|
|
87
98
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
88
99
|
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
100
|
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; }
|
|
@@ -279,6 +290,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
279
290
|
// If the node is invalidated, the cached request chunk on disk needs to be re-written
|
|
280
291
|
this.removeCachedRequestChunkForNode(nodeId);
|
|
281
292
|
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Nodes that are invalidated on start-up, such as JavaScript babel configuration files which are
|
|
296
|
+
* imported when the build kicks-off and might doing arbitrary work such as reading from the file
|
|
297
|
+
* system.
|
|
298
|
+
*/
|
|
282
299
|
invalidateUnpredictableNodes() {
|
|
283
300
|
for (let nodeId of this.unpredicatableNodeIds) {
|
|
284
301
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -286,6 +303,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
286
303
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
287
304
|
}
|
|
288
305
|
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Effectively uncacheable nodes.
|
|
309
|
+
*/
|
|
289
310
|
invalidateOnBuildNodes() {
|
|
290
311
|
for (let nodeId of this.invalidateOnBuildNodeIds) {
|
|
291
312
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
@@ -293,29 +314,45 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
293
314
|
this.invalidateNode(nodeId, _constants.STARTUP);
|
|
294
315
|
}
|
|
295
316
|
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Nodes invalidated by environment changes, corresponds to `env: ...` inputs.
|
|
320
|
+
*/
|
|
296
321
|
invalidateEnvNodes(env) {
|
|
322
|
+
const invalidatedKeys = [];
|
|
297
323
|
for (let nodeId of this.envNodeIds) {
|
|
298
324
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
299
325
|
(0, _assert().default)(node.type === ENV);
|
|
300
|
-
|
|
326
|
+
const key = keyFromEnvContentKey(node.id);
|
|
327
|
+
if (env[key] !== node.value) {
|
|
328
|
+
invalidatedKeys.push(key);
|
|
301
329
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
302
330
|
for (let parentNode of parentNodes) {
|
|
303
331
|
this.invalidateNode(parentNode, _constants.ENV_CHANGE);
|
|
304
332
|
}
|
|
305
333
|
}
|
|
306
334
|
}
|
|
335
|
+
return invalidatedKeys;
|
|
307
336
|
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Nodes invalidated by option changes.
|
|
340
|
+
*/
|
|
308
341
|
invalidateOptionNodes(options) {
|
|
342
|
+
const invalidatedKeys = [];
|
|
309
343
|
for (let nodeId of this.optionNodeIds) {
|
|
310
344
|
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
311
345
|
(0, _assert().default)(node.type === OPTION);
|
|
312
|
-
|
|
346
|
+
const key = keyFromOptionContentKey(node.id);
|
|
347
|
+
if ((0, _utils2.hashFromOption)(options[key]) !== node.hash) {
|
|
348
|
+
invalidatedKeys.push(key);
|
|
313
349
|
let parentNodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
314
350
|
for (let parentNode of parentNodes) {
|
|
315
351
|
this.invalidateNode(parentNode, _constants.OPTION_CHANGE);
|
|
316
352
|
}
|
|
317
353
|
}
|
|
318
354
|
}
|
|
355
|
+
return invalidatedKeys;
|
|
319
356
|
}
|
|
320
357
|
invalidateOnConfigKeyChange(requestNodeId, filePath, configKey, contentHash) {
|
|
321
358
|
let configKeyNodeId = this.addNode(nodeFromConfigKey(filePath, configKey, contentHash));
|
|
@@ -556,10 +593,12 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
556
593
|
aboveCache.set(fileNameNodeId, above);
|
|
557
594
|
return above;
|
|
558
595
|
};
|
|
596
|
+
const invalidationsByPath = new Map();
|
|
559
597
|
for (let {
|
|
560
598
|
path: _path,
|
|
561
599
|
type
|
|
562
600
|
} of events) {
|
|
601
|
+
const invalidationsBefore = this.getInvalidNodeCount();
|
|
563
602
|
if (!enableOptimization && process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' && ++count === 256) {
|
|
564
603
|
let duration = Date.now() - startTime;
|
|
565
604
|
predictedTime = duration * (events.length >> 8);
|
|
@@ -596,7 +635,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
596
635
|
this.invalidNodeIds.add(id);
|
|
597
636
|
}
|
|
598
637
|
}
|
|
599
|
-
return
|
|
638
|
+
return {
|
|
639
|
+
didInvalidate: true,
|
|
640
|
+
invalidationsByPath: new Map()
|
|
641
|
+
};
|
|
600
642
|
}
|
|
601
643
|
|
|
602
644
|
// sometimes mac os reports update events as create events.
|
|
@@ -671,6 +713,9 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
671
713
|
}
|
|
672
714
|
}
|
|
673
715
|
}
|
|
716
|
+
const invalidationsAfter = this.getInvalidNodeCount();
|
|
717
|
+
const invalidationsForEvent = invalidationsAfter - invalidationsBefore;
|
|
718
|
+
invalidationsByPath.set(_path, (invalidationsByPath.get(_path) ?? 0) + invalidationsForEvent);
|
|
674
719
|
}
|
|
675
720
|
if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
|
|
676
721
|
cleanUpOrphans(this);
|
|
@@ -688,7 +733,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
688
733
|
numberOfInvalidatedNodes: invalidatedNodes.size
|
|
689
734
|
}
|
|
690
735
|
});
|
|
691
|
-
return
|
|
736
|
+
return {
|
|
737
|
+
didInvalidate,
|
|
738
|
+
invalidationsByPath
|
|
739
|
+
};
|
|
692
740
|
}
|
|
693
741
|
hasCachedRequestChunk(index) {
|
|
694
742
|
return this.cachedRequestChunks.has(index);
|
|
@@ -699,6 +747,13 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
699
747
|
removeCachedRequestChunkForNode(nodeId) {
|
|
700
748
|
this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
|
|
701
749
|
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Returns the number of invalidated nodes in the graph.
|
|
753
|
+
*/
|
|
754
|
+
getInvalidNodeCount() {
|
|
755
|
+
return this.invalidNodeIds.size;
|
|
756
|
+
}
|
|
702
757
|
}
|
|
703
758
|
exports.RequestGraph = RequestGraph;
|
|
704
759
|
class RequestTracker {
|
|
@@ -895,40 +950,41 @@ class RequestTracker {
|
|
|
895
950
|
}
|
|
896
951
|
createAPI(requestId, previousInvalidations) {
|
|
897
952
|
let subRequestContentKeys = new Set();
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
storeResult
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
return true;
|
|
924
|
-
}
|
|
925
|
-
return false;
|
|
926
|
-
},
|
|
927
|
-
runRequest: (subRequest, opts) => {
|
|
928
|
-
subRequestContentKeys.add(subRequest.id);
|
|
929
|
-
return this.runRequest(subRequest, opts);
|
|
953
|
+
let api = {
|
|
954
|
+
invalidateOnFileCreate: input => this.graph.invalidateOnFileCreate(requestId, input),
|
|
955
|
+
invalidateOnConfigKeyChange: (filePath, configKey, contentHash) => this.graph.invalidateOnConfigKeyChange(requestId, filePath, configKey, contentHash),
|
|
956
|
+
invalidateOnFileDelete: filePath => this.graph.invalidateOnFileDelete(requestId, filePath),
|
|
957
|
+
invalidateOnFileUpdate: filePath => this.graph.invalidateOnFileUpdate(requestId, filePath),
|
|
958
|
+
invalidateOnStartup: () => this.graph.invalidateOnStartup(requestId),
|
|
959
|
+
invalidateOnBuild: () => this.graph.invalidateOnBuild(requestId),
|
|
960
|
+
invalidateOnEnvChange: env => this.graph.invalidateOnEnvChange(requestId, env, this.options.env[env]),
|
|
961
|
+
invalidateOnOptionChange: option => this.graph.invalidateOnOptionChange(requestId, option, this.options[option]),
|
|
962
|
+
getInvalidations: () => previousInvalidations,
|
|
963
|
+
storeResult: (result, cacheKey) => {
|
|
964
|
+
this.storeResult(requestId, result, cacheKey);
|
|
965
|
+
},
|
|
966
|
+
getSubRequests: () => this.graph.getSubRequests(requestId),
|
|
967
|
+
getInvalidSubRequests: () => this.graph.getInvalidSubRequests(requestId),
|
|
968
|
+
getPreviousResult: ifMatch => {
|
|
969
|
+
var _this$graph$getNode;
|
|
970
|
+
let contentKey = (0, _nullthrows().default)((_this$graph$getNode = this.graph.getNode(requestId)) === null || _this$graph$getNode === void 0 ? void 0 : _this$graph$getNode.id);
|
|
971
|
+
return this.getRequestResult(contentKey, ifMatch);
|
|
972
|
+
},
|
|
973
|
+
getRequestResult: id => this.getRequestResult(id),
|
|
974
|
+
canSkipSubrequest: contentKey => {
|
|
975
|
+
if (this.graph.hasContentKey(contentKey) && this.hasValidResult(this.graph.getNodeIdByContentKey(contentKey))) {
|
|
976
|
+
subRequestContentKeys.add(contentKey);
|
|
977
|
+
return true;
|
|
930
978
|
}
|
|
979
|
+
return false;
|
|
931
980
|
},
|
|
981
|
+
runRequest: (subRequest, opts) => {
|
|
982
|
+
subRequestContentKeys.add(subRequest.id);
|
|
983
|
+
return this.runRequest(subRequest, opts);
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
return {
|
|
987
|
+
api,
|
|
932
988
|
subRequestContentKeys
|
|
933
989
|
};
|
|
934
990
|
}
|
|
@@ -944,84 +1000,85 @@ class RequestTracker {
|
|
|
944
1000
|
return result;
|
|
945
1001
|
}
|
|
946
1002
|
}
|
|
947
|
-
await runCacheImprovements(async cache => {
|
|
948
|
-
await cache.getNativeRef().startWriteTransaction();
|
|
949
|
-
}, () => Promise.resolve());
|
|
950
1003
|
let cacheKey = getCacheKey(this.options);
|
|
951
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1004
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1005
|
+
let snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
952
1006
|
if (this.options.shouldDisableCache) {
|
|
953
1007
|
return;
|
|
954
1008
|
}
|
|
955
1009
|
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;
|
|
1010
|
+
await runCacheImprovements(async cache => {
|
|
1011
|
+
await cache.getNativeRef().startWriteTransaction();
|
|
1012
|
+
}, () => Promise.resolve());
|
|
1013
|
+
try {
|
|
981
1014
|
(0, _ReporterRunner.report)({
|
|
982
1015
|
type: 'cache',
|
|
983
|
-
phase: '
|
|
1016
|
+
phase: 'start',
|
|
984
1017
|
total,
|
|
985
1018
|
size: this.graph.nodes.length
|
|
986
1019
|
});
|
|
987
|
-
|
|
988
|
-
let queue = new (_utils().PromiseQueue)({
|
|
989
|
-
maxConcurrent: 32
|
|
990
|
-
});
|
|
1020
|
+
let serialisedGraph = this.graph.serialize();
|
|
991
1021
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1022
|
+
// Delete an existing request graph cache, to prevent invalid states
|
|
1023
|
+
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
1024
|
+
const serialiseAndSet = async (key, contents) => {
|
|
1025
|
+
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
1026
|
+
throw new Error('Serialization was aborted');
|
|
1027
|
+
}
|
|
1028
|
+
await runCacheImprovements(cache => {
|
|
1029
|
+
(0, _logger().instrument)(`RequestTracker::writeToCache::cache.put(${key})`, () => {
|
|
1030
|
+
cache.getNativeRef().putNoConfirm(key, (0, _buildCache().serialize)(contents));
|
|
1031
|
+
});
|
|
1032
|
+
return Promise.resolve();
|
|
1033
|
+
}, async () => {
|
|
1034
|
+
await this.options.cache.setLargeBlob(key, (0, _buildCache().serialize)(contents), signal ? {
|
|
1035
|
+
signal: signal
|
|
1036
|
+
} : undefined);
|
|
1037
|
+
});
|
|
1038
|
+
total += 1;
|
|
1039
|
+
(0, _ReporterRunner.report)({
|
|
1040
|
+
type: 'cache',
|
|
1041
|
+
phase: 'write',
|
|
1042
|
+
total,
|
|
1043
|
+
size: this.graph.nodes.length
|
|
1044
|
+
});
|
|
1045
|
+
};
|
|
1046
|
+
let queue = new (_utils().PromiseQueue)({
|
|
1047
|
+
maxConcurrent: 32
|
|
1048
|
+
});
|
|
999
1049
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1050
|
+
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1051
|
+
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1052
|
+
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1053
|
+
let node = serialisedGraph.nodes[i];
|
|
1054
|
+
let resultCacheKey = node === null || node === void 0 ? void 0 : node.resultCacheKey;
|
|
1055
|
+
if ((node === null || node === void 0 ? void 0 : node.type) === REQUEST && resultCacheKey != null && (node === null || node === void 0 ? void 0 : node.result) != null) {
|
|
1056
|
+
queue.add(() => serialiseAndSet(resultCacheKey, node.result));
|
|
1057
|
+
|
|
1058
|
+
// eslint-disable-next-line no-unused-vars
|
|
1059
|
+
let {
|
|
1060
|
+
result: _,
|
|
1061
|
+
...newNode
|
|
1062
|
+
} = node;
|
|
1063
|
+
cacheableNodes[i] = newNode;
|
|
1064
|
+
} else {
|
|
1065
|
+
cacheableNodes[i] = node;
|
|
1066
|
+
}
|
|
1008
1067
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
}
|
|
1068
|
+
let nodeCountsPerBlob = [];
|
|
1069
|
+
for (let i = 0; i * this.graph.nodesPerBlob < cacheableNodes.length; i += 1) {
|
|
1070
|
+
let nodesStartIndex = i * this.graph.nodesPerBlob;
|
|
1071
|
+
let nodesEndIndex = Math.min((i + 1) * this.graph.nodesPerBlob, cacheableNodes.length);
|
|
1072
|
+
nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
|
|
1073
|
+
if (!this.graph.hasCachedRequestChunk(i)) {
|
|
1074
|
+
// We assume the request graph nodes are immutable and won't change
|
|
1075
|
+
let nodesToCache = cacheableNodes.slice(nodesStartIndex, nodesEndIndex);
|
|
1076
|
+
queue.add(() => serialiseAndSet(getRequestGraphNodeKey(i, cacheKey), nodesToCache).then(() => {
|
|
1077
|
+
// Succeeded in writing to disk, save that we have completed this chunk
|
|
1078
|
+
this.graph.setCachedRequestChunk(i);
|
|
1079
|
+
}));
|
|
1080
|
+
}
|
|
1022
1081
|
}
|
|
1023
|
-
}
|
|
1024
|
-
try {
|
|
1025
1082
|
await queue.run();
|
|
1026
1083
|
|
|
1027
1084
|
// Set the request graph after the queue is flushed to avoid writing an invalid state
|
|
@@ -1030,7 +1087,7 @@ class RequestTracker {
|
|
|
1030
1087
|
nodeCountsPerBlob,
|
|
1031
1088
|
nodes: undefined
|
|
1032
1089
|
});
|
|
1033
|
-
await runCacheImprovements(() => serialiseAndSet(
|
|
1090
|
+
await runCacheImprovements(() => serialiseAndSet(`${cacheKey}/cache_metadata`, {
|
|
1034
1091
|
version: _constants.ATLASPACK_VERSION,
|
|
1035
1092
|
entries: this.options.entries,
|
|
1036
1093
|
mode: this.options.mode,
|
|
@@ -1038,15 +1095,16 @@ class RequestTracker {
|
|
|
1038
1095
|
watchBackend: this.options.watchBackend
|
|
1039
1096
|
}), () => Promise.resolve());
|
|
1040
1097
|
let opts = getWatcherOptions(this.options);
|
|
1041
|
-
let snapshotPath = _path2().default.join(this.options.cacheDir,
|
|
1098
|
+
let snapshotPath = _path2().default.join(this.options.cacheDir, snapshotKey + '.txt');
|
|
1042
1099
|
await this.options.outputFS.writeSnapshot(this.options.watchDir, snapshotPath, opts);
|
|
1043
1100
|
} catch (err) {
|
|
1044
1101
|
// If we have aborted, ignore the error and continue
|
|
1045
1102
|
if (!(signal !== null && signal !== void 0 && signal.aborted)) throw err;
|
|
1103
|
+
} finally {
|
|
1104
|
+
await runCacheImprovements(async cache => {
|
|
1105
|
+
await cache.getNativeRef().commitWriteTransaction();
|
|
1106
|
+
}, () => Promise.resolve());
|
|
1046
1107
|
}
|
|
1047
|
-
await runCacheImprovements(async cache => {
|
|
1048
|
-
await cache.getNativeRef().commitWriteTransaction();
|
|
1049
|
-
}, () => Promise.resolve());
|
|
1050
1108
|
(0, _ReporterRunner.report)({
|
|
1051
1109
|
type: 'cache',
|
|
1052
1110
|
phase: 'end',
|
|
@@ -1075,7 +1133,8 @@ function getWatcherOptions({
|
|
|
1075
1133
|
watchDir,
|
|
1076
1134
|
watchBackend
|
|
1077
1135
|
}) {
|
|
1078
|
-
const
|
|
1136
|
+
const vcsDirs = ['.git', '.hg'];
|
|
1137
|
+
const uniqueDirs = [...new Set([...watchIgnore, ...vcsDirs, cacheDir])];
|
|
1079
1138
|
const ignore = uniqueDirs.map(dir => _path2().default.resolve(watchDir, dir));
|
|
1080
1139
|
return {
|
|
1081
1140
|
ignore,
|
|
@@ -1083,17 +1142,30 @@ function getWatcherOptions({
|
|
|
1083
1142
|
};
|
|
1084
1143
|
}
|
|
1085
1144
|
function getCacheKey(options) {
|
|
1145
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1146
|
+
const hash = (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1147
|
+
return `RequestTracker/${_constants.ATLASPACK_VERSION}/${hash}`;
|
|
1148
|
+
}
|
|
1086
1149
|
return (0, _rust().hashString)(`${_constants.ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${options.watchBackend ?? ''}`);
|
|
1087
1150
|
}
|
|
1088
1151
|
function getRequestGraphNodeKey(index, cacheKey) {
|
|
1152
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1153
|
+
return `${cacheKey}/RequestGraph/nodes/${index}`;
|
|
1154
|
+
}
|
|
1089
1155
|
return `requestGraph-nodes-${index}-${cacheKey}`;
|
|
1090
1156
|
}
|
|
1091
1157
|
async function readAndDeserializeRequestGraph(cache, requestGraphKey, cacheKey) {
|
|
1092
1158
|
let bufferLength = 0;
|
|
1093
1159
|
const getAndDeserialize = async key => {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1160
|
+
if ((0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
1161
|
+
const buffer = await cache.getBlob(key);
|
|
1162
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1163
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1164
|
+
} else {
|
|
1165
|
+
const buffer = await cache.getLargeBlob(key);
|
|
1166
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1167
|
+
return (0, _buildCache().deserialize)(buffer);
|
|
1168
|
+
}
|
|
1097
1169
|
};
|
|
1098
1170
|
let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
|
|
1099
1171
|
let nodePromises = serializedRequestGraph.nodeCountsPerBlob.map(async (nodesCount, i) => {
|
|
@@ -1115,19 +1187,30 @@ async function loadRequestGraph(options) {
|
|
|
1115
1187
|
return new RequestGraph();
|
|
1116
1188
|
}
|
|
1117
1189
|
let cacheKey = getCacheKey(options);
|
|
1118
|
-
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1190
|
+
let requestGraphKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/RequestGraph` : `requestGraph-${cacheKey}`;
|
|
1119
1191
|
let timeout;
|
|
1120
|
-
const snapshotKey = `snapshot-${cacheKey}`;
|
|
1192
|
+
const snapshotKey = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? `${cacheKey}/snapshot` : `snapshot-${cacheKey}`;
|
|
1121
1193
|
const snapshotPath = _path2().default.join(options.cacheDir, snapshotKey + '.txt');
|
|
1194
|
+
const commonMeta = {
|
|
1195
|
+
cacheKey,
|
|
1196
|
+
snapshotKey,
|
|
1197
|
+
cacheKeyOptions: {
|
|
1198
|
+
version: _constants.ATLASPACK_VERSION,
|
|
1199
|
+
entries: options.entries,
|
|
1200
|
+
mode: options.mode,
|
|
1201
|
+
shouldBuildLazily: options.shouldBuildLazily,
|
|
1202
|
+
watchBackend: options.watchBackend
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1122
1205
|
_logger().default.verbose({
|
|
1123
1206
|
origin: '@atlaspack/core',
|
|
1124
1207
|
message: 'Loading request graph',
|
|
1125
1208
|
meta: {
|
|
1126
|
-
|
|
1127
|
-
snapshotKey
|
|
1209
|
+
...commonMeta
|
|
1128
1210
|
}
|
|
1129
1211
|
});
|
|
1130
|
-
|
|
1212
|
+
const hasRequestGraphInCache = (0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements') ? await options.cache.has(requestGraphKey) : await options.cache.hasLargeBlob(requestGraphKey);
|
|
1213
|
+
if (hasRequestGraphInCache) {
|
|
1131
1214
|
try {
|
|
1132
1215
|
let {
|
|
1133
1216
|
requestGraph
|
|
@@ -1146,16 +1229,29 @@ async function loadRequestGraph(options) {
|
|
|
1146
1229
|
origin: '@atlaspack/core',
|
|
1147
1230
|
message: `File system event count: ${events.length}`,
|
|
1148
1231
|
meta: {
|
|
1232
|
+
...commonMeta,
|
|
1149
1233
|
trackableEvent: 'watcher_events_count',
|
|
1150
1234
|
watcherEventCount: events.length,
|
|
1151
1235
|
duration: Date.now() - startTime
|
|
1152
1236
|
}
|
|
1153
1237
|
});
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1238
|
+
if ((0, _featureFlags().getFeatureFlag)('verboseRequestInvalidationStats')) {
|
|
1239
|
+
const invalidationStats = await invalidateRequestGraph(requestGraph, options, events);
|
|
1240
|
+
_logger().default.verbose({
|
|
1241
|
+
origin: '@atlaspack/core',
|
|
1242
|
+
message: 'Request track loaded from cache',
|
|
1243
|
+
meta: {
|
|
1244
|
+
...commonMeta,
|
|
1245
|
+
trackableEvent: 'request_tracker_cache_key_hit',
|
|
1246
|
+
invalidationStats
|
|
1247
|
+
}
|
|
1248
|
+
});
|
|
1249
|
+
} else {
|
|
1250
|
+
requestGraph.invalidateUnpredictableNodes();
|
|
1251
|
+
requestGraph.invalidateOnBuildNodes();
|
|
1252
|
+
requestGraph.invalidateEnvNodes(options.env);
|
|
1253
|
+
requestGraph.invalidateOptionNodes(options);
|
|
1254
|
+
}
|
|
1159
1255
|
return requestGraph;
|
|
1160
1256
|
} catch (e) {
|
|
1161
1257
|
// Prevent logging fs events took too long warning
|
|
@@ -1170,12 +1266,106 @@ async function loadRequestGraph(options) {
|
|
|
1170
1266
|
origin: '@atlaspack/core',
|
|
1171
1267
|
message: 'Cache entry for request tracker was not found, initializing a clean cache.',
|
|
1172
1268
|
meta: {
|
|
1173
|
-
|
|
1174
|
-
|
|
1269
|
+
...commonMeta,
|
|
1270
|
+
trackableEvent: 'request_tracker_cache_key_miss'
|
|
1175
1271
|
}
|
|
1176
1272
|
});
|
|
1177
1273
|
return new RequestGraph();
|
|
1178
1274
|
}
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* A wrapper around an invalidation type / method
|
|
1278
|
+
*/
|
|
1279
|
+
|
|
1280
|
+
/**
|
|
1281
|
+
* Details about an invalidation.
|
|
1282
|
+
*
|
|
1283
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1284
|
+
* by path.
|
|
1285
|
+
*
|
|
1286
|
+
* If this is a env or option invalidation, this key will contain the list of changed environment
|
|
1287
|
+
* variables or options.
|
|
1288
|
+
*/
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* Number of invalidations for a given file-system event.
|
|
1292
|
+
*/
|
|
1293
|
+
|
|
1294
|
+
/**
|
|
1295
|
+
* Information about a certain cache invalidation type.
|
|
1296
|
+
*/
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* Respond to unpredictable, build, environment changes, option changes and file-system events
|
|
1300
|
+
* invalidating RequestGraph nodes.
|
|
1301
|
+
*
|
|
1302
|
+
* Returns the count of nodes invalidated by each invalidation type.
|
|
1303
|
+
*/
|
|
1304
|
+
async function invalidateRequestGraph(requestGraph, options, events) {
|
|
1305
|
+
const invalidationFns = [{
|
|
1306
|
+
key: 'unpredictable',
|
|
1307
|
+
fn: () => requestGraph.invalidateUnpredictableNodes()
|
|
1308
|
+
}, {
|
|
1309
|
+
key: 'onBuild',
|
|
1310
|
+
fn: () => requestGraph.invalidateOnBuildNodes()
|
|
1311
|
+
}, {
|
|
1312
|
+
key: 'env',
|
|
1313
|
+
fn: () => requestGraph.invalidateEnvNodes(options.env)
|
|
1314
|
+
}, {
|
|
1315
|
+
key: 'option',
|
|
1316
|
+
fn: () => requestGraph.invalidateOptionNodes(options)
|
|
1317
|
+
}, {
|
|
1318
|
+
key: 'fsEvents',
|
|
1319
|
+
fn: () => invalidateRequestGraphFSEvents(requestGraph, options, events)
|
|
1320
|
+
}];
|
|
1321
|
+
const invalidations = [];
|
|
1322
|
+
for (const invalidation of invalidationFns) {
|
|
1323
|
+
invalidations.push(await runInvalidation(requestGraph, invalidation));
|
|
1324
|
+
}
|
|
1325
|
+
const invalidatedCount = invalidations.reduce((acc, invalidation) => acc + invalidation.count, 0);
|
|
1326
|
+
const requestCount = requestGraph.nodes.reduce((acc, node) => acc + ((node === null || node === void 0 ? void 0 : node.type) === REQUEST ? 1 : 0), 0);
|
|
1327
|
+
const nodeCount = requestGraph.nodes.length;
|
|
1328
|
+
const nodeInvalidationRatio = invalidatedCount / nodeCount;
|
|
1329
|
+
const requestInvalidationRatio = invalidatedCount / requestCount;
|
|
1330
|
+
return {
|
|
1331
|
+
invalidations,
|
|
1332
|
+
nodeCount,
|
|
1333
|
+
requestCount,
|
|
1334
|
+
invalidatedCount,
|
|
1335
|
+
nodeInvalidationRatio,
|
|
1336
|
+
requestInvalidationRatio
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* Invalidate the request graph based on file-system events.
|
|
1341
|
+
*
|
|
1342
|
+
* Returns statistics about the invalidations.
|
|
1343
|
+
*/
|
|
1344
|
+
async function invalidateRequestGraphFSEvents(requestGraph, options, events) {
|
|
1345
|
+
const {
|
|
1346
|
+
invalidationsByPath
|
|
1347
|
+
} = await requestGraph.respondToFSEvents(options.unstableFileInvalidations || events, options, 10000, true);
|
|
1348
|
+
const biggestInvalidations = getBiggestFSEventsInvalidations(invalidationsByPath);
|
|
1349
|
+
return {
|
|
1350
|
+
biggestInvalidations
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Runs an invalidation function and reports metrics.
|
|
1355
|
+
*/
|
|
1356
|
+
async function runInvalidation(requestGraph, invalidationFn) {
|
|
1357
|
+
const start = _perf_hooks().performance.now();
|
|
1358
|
+
const startInvalidationCount = requestGraph.getInvalidNodeCount();
|
|
1359
|
+
const result = await invalidationFn.fn();
|
|
1360
|
+
const count = requestGraph.getInvalidNodeCount() - startInvalidationCount;
|
|
1361
|
+
const duration = _perf_hooks().performance.now() - start;
|
|
1362
|
+
return {
|
|
1363
|
+
key: invalidationFn.key,
|
|
1364
|
+
count,
|
|
1365
|
+
detail: result ?? null,
|
|
1366
|
+
duration
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1179
1369
|
function logErrorOnBailout(options, snapshotPath, e) {
|
|
1180
1370
|
if (e.message && e.message.includes('invalid clockspec')) {
|
|
1181
1371
|
const snapshotContents = options.inputFS.readFileSync(snapshotPath, 'utf-8');
|
|
@@ -1215,4 +1405,19 @@ function cleanUpOrphans(graph) {
|
|
|
1215
1405
|
}
|
|
1216
1406
|
});
|
|
1217
1407
|
return removedNodeIds;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Returns paths that invalidated the most nodes
|
|
1412
|
+
*/
|
|
1413
|
+
function getBiggestFSEventsInvalidations(invalidationsByPath, limit = 10) {
|
|
1414
|
+
const invalidations = [];
|
|
1415
|
+
for (const [path, count] of invalidationsByPath) {
|
|
1416
|
+
invalidations.push({
|
|
1417
|
+
path,
|
|
1418
|
+
count
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
invalidations.sort((a, b) => b.count - a.count);
|
|
1422
|
+
return invalidations.slice(0, limit);
|
|
1218
1423
|
}
|
package/lib/Transformation.js
CHANGED
|
@@ -173,12 +173,12 @@ class Transformation {
|
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
// Prefer `isSource` originating from the AssetRequest.
|
|
176
|
-
|
|
176
|
+
let isSource = isSourceOverride ?? summarizedIsSource;
|
|
177
177
|
return new _UncommittedAsset.default({
|
|
178
178
|
value: (0, _assetUtils.createAsset)(this.options.projectRoot, {
|
|
179
179
|
code,
|
|
180
180
|
filePath,
|
|
181
|
-
isSource
|
|
181
|
+
isSource,
|
|
182
182
|
type: _path().default.extname((0, _projectPath.fromProjectPathRelative)(filePath)).slice(1),
|
|
183
183
|
pipeline,
|
|
184
184
|
env,
|