@atlaspack/core 2.12.1-canary.3430 → 2.12.1-canary.3432
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/lib/Atlaspack.js +3 -0
- package/lib/RequestTracker.js +81 -26
- package/package.json +16 -16
- package/src/Atlaspack.js +4 -0
- package/src/RequestTracker.js +116 -35
- package/test/RequestTracker.test.js +94 -1
package/lib/Atlaspack.js
CHANGED
package/lib/RequestTracker.js
CHANGED
|
@@ -465,18 +465,32 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
465
465
|
return node;
|
|
466
466
|
});
|
|
467
467
|
}
|
|
468
|
-
invalidateFileNameNode(node, filePath, matchNodes) {
|
|
468
|
+
invalidateFileNameNode(node, filePath, matchNodes, invalidateNode) {
|
|
469
469
|
// If there is an edge between this file_name node and one of the original file nodes pointed to
|
|
470
470
|
// by the original file_name node, and the matched node is inside the current directory, invalidate
|
|
471
471
|
// all connected requests pointed to by the file node.
|
|
472
|
-
|
|
472
|
+
|
|
473
473
|
let nodeId = this.getNodeIdByContentKey(node.id);
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
474
|
+
let dirname = _path2().default.dirname((0, _projectPath.fromProjectPathRelative)(filePath));
|
|
475
|
+
if ((0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation')) {
|
|
476
|
+
while (dirname !== '/') {
|
|
477
|
+
if (!this.hasContentKey(dirname)) break;
|
|
478
|
+
const matchNodeId = this.getNodeIdByContentKey(dirname);
|
|
479
|
+
if (!this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) break;
|
|
480
|
+
const connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
|
|
478
481
|
for (let connectedNode of connectedNodes) {
|
|
479
|
-
|
|
482
|
+
invalidateNode(connectedNode, _constants.FILE_CREATE);
|
|
483
|
+
}
|
|
484
|
+
dirname = _path2().default.dirname(dirname);
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
for (let matchNode of matchNodes) {
|
|
488
|
+
let matchNodeId = this.getNodeIdByContentKey(matchNode.id);
|
|
489
|
+
if (this.hasEdge(nodeId, matchNodeId, requestGraphEdgeTypes.invalidated_by_create_above) && (0, _utils().isDirectoryInside)((0, _projectPath.fromProjectPathRelative)((0, _projectPath.toProjectPathUnsafe)(matchNode.id)), dirname)) {
|
|
490
|
+
let connectedNodes = this.getNodeIdsConnectedTo(matchNodeId, requestGraphEdgeTypes.invalidated_by_create);
|
|
491
|
+
for (let connectedNode of connectedNodes) {
|
|
492
|
+
this.invalidateNode(connectedNode, _constants.FILE_CREATE);
|
|
493
|
+
}
|
|
480
494
|
}
|
|
481
495
|
}
|
|
482
496
|
}
|
|
@@ -489,7 +503,7 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
489
503
|
if (this.hasEdge(nodeId, this.getNodeIdByContentKey(contentKey), requestGraphEdgeTypes.dirname)) {
|
|
490
504
|
let parent = (0, _nullthrows().default)(this.getNodeByContentKey(contentKey));
|
|
491
505
|
(0, _assert().default)(parent.type === FILE_NAME);
|
|
492
|
-
this.invalidateFileNameNode(parent, (0, _projectPath.toProjectPathUnsafe)(dirname), matchNodes);
|
|
506
|
+
this.invalidateFileNameNode(parent, (0, _projectPath.toProjectPathUnsafe)(dirname), matchNodes, invalidateNode);
|
|
493
507
|
}
|
|
494
508
|
}
|
|
495
509
|
}
|
|
@@ -498,12 +512,38 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
498
512
|
let count = 0;
|
|
499
513
|
let predictedTime = 0;
|
|
500
514
|
let startTime = Date.now();
|
|
501
|
-
const
|
|
515
|
+
const enableOptimization = (0, _featureFlags().getFeatureFlag)('fixQuadraticCacheInvalidation');
|
|
516
|
+
const removeOrphans = !enableOptimization;
|
|
517
|
+
const invalidatedNodes = new Set();
|
|
518
|
+
const invalidateNode = (nodeId, reason) => {
|
|
519
|
+
if (enableOptimization && invalidatedNodes.has(nodeId)) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
invalidatedNodes.add(nodeId);
|
|
523
|
+
this.invalidateNode(nodeId, reason);
|
|
524
|
+
};
|
|
525
|
+
const aboveCache = new Map();
|
|
526
|
+
const getAbove = fileNameNodeId => {
|
|
527
|
+
const cachedResult = aboveCache.get(fileNameNodeId);
|
|
528
|
+
if (enableOptimization && cachedResult) {
|
|
529
|
+
return cachedResult;
|
|
530
|
+
}
|
|
531
|
+
let above = [];
|
|
532
|
+
const children = this.getNodeIdsConnectedTo(fileNameNodeId, requestGraphEdgeTypes.invalidated_by_create_above);
|
|
533
|
+
for (const nodeId of children) {
|
|
534
|
+
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
535
|
+
if (node.type === FILE) {
|
|
536
|
+
above.push(node);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
aboveCache.set(fileNameNodeId, above);
|
|
540
|
+
return above;
|
|
541
|
+
};
|
|
502
542
|
for (let {
|
|
503
543
|
path: _path,
|
|
504
544
|
type
|
|
505
545
|
} of events) {
|
|
506
|
-
if (++count === 256) {
|
|
546
|
+
if (!enableOptimization && process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' && ++count === 256) {
|
|
507
547
|
let duration = Date.now() - startTime;
|
|
508
548
|
predictedTime = duration * (events.length >> 8);
|
|
509
549
|
if (predictedTime > threshold) {
|
|
@@ -550,13 +590,13 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
550
590
|
let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update);
|
|
551
591
|
for (let connectedNode of nodes) {
|
|
552
592
|
didInvalidate = true;
|
|
553
|
-
|
|
593
|
+
invalidateNode(connectedNode, _constants.FILE_UPDATE);
|
|
554
594
|
}
|
|
555
595
|
if (type === 'create') {
|
|
556
596
|
let nodes = this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_create);
|
|
557
597
|
for (let connectedNode of nodes) {
|
|
558
598
|
didInvalidate = true;
|
|
559
|
-
|
|
599
|
+
invalidateNode(connectedNode, _constants.FILE_CREATE);
|
|
560
600
|
}
|
|
561
601
|
}
|
|
562
602
|
} else if (type === 'create') {
|
|
@@ -566,17 +606,10 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
566
606
|
let fileNameNodeId = this.getNodeIdByContentKey('file_name:' + basename);
|
|
567
607
|
|
|
568
608
|
// Find potential file nodes to be invalidated if this file name pattern matches
|
|
569
|
-
let above =
|
|
570
|
-
for (const nodeId of this.getNodeIdsConnectedTo(fileNameNodeId, requestGraphEdgeTypes.invalidated_by_create_above)) {
|
|
571
|
-
let node = (0, _nullthrows().default)(this.getNode(nodeId));
|
|
572
|
-
// these might also be `glob` nodes which get handled below, we only care about files here.
|
|
573
|
-
if (node.type === FILE) {
|
|
574
|
-
above.push(node);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
609
|
+
let above = getAbove(fileNameNodeId);
|
|
577
610
|
if (above.length > 0) {
|
|
578
611
|
didInvalidate = true;
|
|
579
|
-
this.invalidateFileNameNode(fileNameNode, _filePath, above);
|
|
612
|
+
this.invalidateFileNameNode(fileNameNode, _filePath, above, invalidateNode);
|
|
580
613
|
}
|
|
581
614
|
}
|
|
582
615
|
for (let globeNodeId of this.globNodeIds) {
|
|
@@ -586,7 +619,7 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
586
619
|
let connectedNodes = this.getNodeIdsConnectedTo(globeNodeId, requestGraphEdgeTypes.invalidated_by_create);
|
|
587
620
|
for (let connectedNode of connectedNodes) {
|
|
588
621
|
didInvalidate = true;
|
|
589
|
-
|
|
622
|
+
invalidateNode(connectedNode, _constants.FILE_CREATE);
|
|
590
623
|
}
|
|
591
624
|
}
|
|
592
625
|
}
|
|
@@ -594,7 +627,7 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
594
627
|
let nodeId = this.getNodeIdByContentKey(filePath);
|
|
595
628
|
for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_delete)) {
|
|
596
629
|
didInvalidate = true;
|
|
597
|
-
|
|
630
|
+
invalidateNode(connectedNode, _constants.FILE_DELETE);
|
|
598
631
|
}
|
|
599
632
|
|
|
600
633
|
// Delete the file node since it doesn't exist anymore.
|
|
@@ -614,7 +647,7 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
614
647
|
}
|
|
615
648
|
if (isInvalid) {
|
|
616
649
|
for (let connectedNode of this.getNodeIdsConnectedTo(nodeId, requestGraphEdgeTypes.invalidated_by_update)) {
|
|
617
|
-
|
|
650
|
+
invalidateNode(connectedNode, type === 'delete' ? _constants.FILE_DELETE : _constants.FILE_UPDATE);
|
|
618
651
|
}
|
|
619
652
|
didInvalidate = true;
|
|
620
653
|
this.removeNode(nodeId, removeOrphans);
|
|
@@ -632,7 +665,9 @@ class RequestGraph extends _graph().ContentGraph {
|
|
|
632
665
|
meta: {
|
|
633
666
|
trackableEvent: 'fsevent_response_time',
|
|
634
667
|
duration,
|
|
635
|
-
predictedTime
|
|
668
|
+
predictedTime,
|
|
669
|
+
numberOfEvents: events.length,
|
|
670
|
+
numberOfInvalidatedNodes: invalidatedNodes.size
|
|
636
671
|
}
|
|
637
672
|
});
|
|
638
673
|
return didInvalidate && this.invalidNodeIds.size > 0;
|
|
@@ -1035,7 +1070,16 @@ async function loadRequestGraph(options) {
|
|
|
1035
1070
|
let cacheKey = getCacheKey(options);
|
|
1036
1071
|
let requestGraphKey = `requestGraph-${cacheKey}`;
|
|
1037
1072
|
let timeout;
|
|
1038
|
-
const
|
|
1073
|
+
const snapshotKey = `snapshot-${cacheKey}`;
|
|
1074
|
+
const snapshotPath = _path2().default.join(options.cacheDir, snapshotKey + '.txt');
|
|
1075
|
+
_logger().default.verbose({
|
|
1076
|
+
origin: '@atlaspack/core',
|
|
1077
|
+
message: 'Loading request graph',
|
|
1078
|
+
meta: {
|
|
1079
|
+
cacheKey,
|
|
1080
|
+
snapshotKey
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1039
1083
|
if (await options.cache.hasLargeBlob(requestGraphKey)) {
|
|
1040
1084
|
try {
|
|
1041
1085
|
let {
|
|
@@ -1075,6 +1119,14 @@ async function loadRequestGraph(options) {
|
|
|
1075
1119
|
return new RequestGraph();
|
|
1076
1120
|
}
|
|
1077
1121
|
}
|
|
1122
|
+
_logger().default.verbose({
|
|
1123
|
+
origin: '@atlaspack/core',
|
|
1124
|
+
message: 'Cache entry for request tracker was not found, initializing a clean cache.',
|
|
1125
|
+
meta: {
|
|
1126
|
+
cacheKey,
|
|
1127
|
+
snapshotKey
|
|
1128
|
+
}
|
|
1129
|
+
});
|
|
1078
1130
|
return new RequestGraph();
|
|
1079
1131
|
}
|
|
1080
1132
|
function logErrorOnBailout(options, snapshotPath, e) {
|
|
@@ -1101,6 +1153,9 @@ function logErrorOnBailout(options, snapshotPath, e) {
|
|
|
1101
1153
|
}
|
|
1102
1154
|
}
|
|
1103
1155
|
function cleanUpOrphans(graph) {
|
|
1156
|
+
if (graph.rootNodeId == null) {
|
|
1157
|
+
return [];
|
|
1158
|
+
}
|
|
1104
1159
|
const reachableNodes = new Set();
|
|
1105
1160
|
graph.traverse(nodeId => {
|
|
1106
1161
|
reachableNodes.add(nodeId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/core",
|
|
3
|
-
"version": "2.12.1-canary.
|
|
3
|
+
"version": "2.12.1-canary.3432+415929ab6",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -20,20 +20,20 @@
|
|
|
20
20
|
"check-ts": "tsc --noEmit index.d.ts"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@atlaspack/cache": "2.12.1-canary.
|
|
24
|
-
"@atlaspack/diagnostic": "2.12.1-canary.
|
|
25
|
-
"@atlaspack/events": "2.12.1-canary.
|
|
26
|
-
"@atlaspack/feature-flags": "2.12.1-canary.
|
|
27
|
-
"@atlaspack/fs": "2.12.1-canary.
|
|
28
|
-
"@atlaspack/graph": "3.2.1-canary.
|
|
29
|
-
"@atlaspack/logger": "2.12.1-canary.
|
|
30
|
-
"@atlaspack/package-manager": "2.12.1-canary.
|
|
31
|
-
"@atlaspack/plugin": "2.12.1-canary.
|
|
32
|
-
"@atlaspack/profiler": "2.12.1-canary.
|
|
33
|
-
"@atlaspack/rust": "2.12.1-canary.
|
|
34
|
-
"@atlaspack/types": "2.12.1-canary.
|
|
35
|
-
"@atlaspack/utils": "2.12.1-canary.
|
|
36
|
-
"@atlaspack/workers": "2.12.1-canary.
|
|
23
|
+
"@atlaspack/cache": "2.12.1-canary.3432+415929ab6",
|
|
24
|
+
"@atlaspack/diagnostic": "2.12.1-canary.3432+415929ab6",
|
|
25
|
+
"@atlaspack/events": "2.12.1-canary.3432+415929ab6",
|
|
26
|
+
"@atlaspack/feature-flags": "2.12.1-canary.3432+415929ab6",
|
|
27
|
+
"@atlaspack/fs": "2.12.1-canary.3432+415929ab6",
|
|
28
|
+
"@atlaspack/graph": "3.2.1-canary.3432+415929ab6",
|
|
29
|
+
"@atlaspack/logger": "2.12.1-canary.3432+415929ab6",
|
|
30
|
+
"@atlaspack/package-manager": "2.12.1-canary.3432+415929ab6",
|
|
31
|
+
"@atlaspack/plugin": "2.12.1-canary.3432+415929ab6",
|
|
32
|
+
"@atlaspack/profiler": "2.12.1-canary.3432+415929ab6",
|
|
33
|
+
"@atlaspack/rust": "2.12.1-canary.3432+415929ab6",
|
|
34
|
+
"@atlaspack/types": "2.12.1-canary.3432+415929ab6",
|
|
35
|
+
"@atlaspack/utils": "2.12.1-canary.3432+415929ab6",
|
|
36
|
+
"@atlaspack/workers": "2.12.1-canary.3432+415929ab6",
|
|
37
37
|
"@mischnic/json-sourcemap": "^0.1.0",
|
|
38
38
|
"@parcel/source-map": "^2.1.1",
|
|
39
39
|
"base-x": "^3.0.8",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"browser": {
|
|
58
58
|
"./src/serializerCore.js": "./src/serializerCore.browser.js"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "415929ab63f5314913c27d3dfdb965f2e76bedf2"
|
|
61
61
|
}
|
package/src/Atlaspack.js
CHANGED
|
@@ -544,6 +544,10 @@ export default class Atlaspack {
|
|
|
544
544
|
return this.#farm.takeHeapSnapshot();
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
+
async unstable_invalidate(): Promise<void> {
|
|
548
|
+
await this._init();
|
|
549
|
+
}
|
|
550
|
+
|
|
547
551
|
async unstable_transform(
|
|
548
552
|
options: AtlaspackTransformOptions,
|
|
549
553
|
): Promise<Array<Asset>> {
|
package/src/RequestTracker.js
CHANGED
|
@@ -818,32 +818,59 @@ export class RequestGraph extends ContentGraph<
|
|
|
818
818
|
node: FileNameNode,
|
|
819
819
|
filePath: ProjectPath,
|
|
820
820
|
matchNodes: Array<FileNode>,
|
|
821
|
+
invalidateNode: (NodeId, InvalidateReason) => void,
|
|
821
822
|
) {
|
|
822
823
|
// If there is an edge between this file_name node and one of the original file nodes pointed to
|
|
823
824
|
// by the original file_name node, and the matched node is inside the current directory, invalidate
|
|
824
825
|
// all connected requests pointed to by the file node.
|
|
825
|
-
let dirname = path.dirname(fromProjectPathRelative(filePath));
|
|
826
826
|
|
|
827
827
|
let nodeId = this.getNodeIdByContentKey(node.id);
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
828
|
+
let dirname = path.dirname(fromProjectPathRelative(filePath));
|
|
829
|
+
|
|
830
|
+
if (getFeatureFlag('fixQuadraticCacheInvalidation')) {
|
|
831
|
+
while (dirname !== '/') {
|
|
832
|
+
if (!this.hasContentKey(dirname)) break;
|
|
833
|
+
const matchNodeId = this.getNodeIdByContentKey(dirname);
|
|
834
|
+
if (
|
|
835
|
+
!this.hasEdge(
|
|
836
|
+
nodeId,
|
|
837
|
+
matchNodeId,
|
|
838
|
+
requestGraphEdgeTypes.invalidated_by_create_above,
|
|
839
|
+
)
|
|
839
840
|
)
|
|
840
|
-
|
|
841
|
-
|
|
841
|
+
break;
|
|
842
|
+
|
|
843
|
+
const connectedNodes = this.getNodeIdsConnectedTo(
|
|
842
844
|
matchNodeId,
|
|
843
845
|
requestGraphEdgeTypes.invalidated_by_create,
|
|
844
846
|
);
|
|
845
847
|
for (let connectedNode of connectedNodes) {
|
|
846
|
-
|
|
848
|
+
invalidateNode(connectedNode, FILE_CREATE);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
dirname = path.dirname(dirname);
|
|
852
|
+
}
|
|
853
|
+
} else {
|
|
854
|
+
for (let matchNode of matchNodes) {
|
|
855
|
+
let matchNodeId = this.getNodeIdByContentKey(matchNode.id);
|
|
856
|
+
if (
|
|
857
|
+
this.hasEdge(
|
|
858
|
+
nodeId,
|
|
859
|
+
matchNodeId,
|
|
860
|
+
requestGraphEdgeTypes.invalidated_by_create_above,
|
|
861
|
+
) &&
|
|
862
|
+
isDirectoryInside(
|
|
863
|
+
fromProjectPathRelative(toProjectPathUnsafe(matchNode.id)),
|
|
864
|
+
dirname,
|
|
865
|
+
)
|
|
866
|
+
) {
|
|
867
|
+
let connectedNodes = this.getNodeIdsConnectedTo(
|
|
868
|
+
matchNodeId,
|
|
869
|
+
requestGraphEdgeTypes.invalidated_by_create,
|
|
870
|
+
);
|
|
871
|
+
for (let connectedNode of connectedNodes) {
|
|
872
|
+
this.invalidateNode(connectedNode, FILE_CREATE);
|
|
873
|
+
}
|
|
847
874
|
}
|
|
848
875
|
}
|
|
849
876
|
}
|
|
@@ -866,6 +893,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
866
893
|
parent,
|
|
867
894
|
toProjectPathUnsafe(dirname),
|
|
868
895
|
matchNodes,
|
|
896
|
+
invalidateNode,
|
|
869
897
|
);
|
|
870
898
|
}
|
|
871
899
|
}
|
|
@@ -880,10 +908,45 @@ export class RequestGraph extends ContentGraph<
|
|
|
880
908
|
let count = 0;
|
|
881
909
|
let predictedTime = 0;
|
|
882
910
|
let startTime = Date.now();
|
|
883
|
-
const
|
|
911
|
+
const enableOptimization = getFeatureFlag('fixQuadraticCacheInvalidation');
|
|
912
|
+
const removeOrphans = !enableOptimization;
|
|
913
|
+
|
|
914
|
+
const invalidatedNodes = new Set();
|
|
915
|
+
const invalidateNode = (nodeId, reason) => {
|
|
916
|
+
if (enableOptimization && invalidatedNodes.has(nodeId)) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
invalidatedNodes.add(nodeId);
|
|
920
|
+
this.invalidateNode(nodeId, reason);
|
|
921
|
+
};
|
|
922
|
+
const aboveCache = new Map();
|
|
923
|
+
const getAbove = fileNameNodeId => {
|
|
924
|
+
const cachedResult = aboveCache.get(fileNameNodeId);
|
|
925
|
+
if (enableOptimization && cachedResult) {
|
|
926
|
+
return cachedResult;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
let above = [];
|
|
930
|
+
const children = this.getNodeIdsConnectedTo(
|
|
931
|
+
fileNameNodeId,
|
|
932
|
+
requestGraphEdgeTypes.invalidated_by_create_above,
|
|
933
|
+
);
|
|
934
|
+
for (const nodeId of children) {
|
|
935
|
+
let node = nullthrows(this.getNode(nodeId));
|
|
936
|
+
if (node.type === FILE) {
|
|
937
|
+
above.push(node);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
aboveCache.set(fileNameNodeId, above);
|
|
941
|
+
return above;
|
|
942
|
+
};
|
|
884
943
|
|
|
885
944
|
for (let {path: _path, type} of events) {
|
|
886
|
-
if (
|
|
945
|
+
if (
|
|
946
|
+
!enableOptimization &&
|
|
947
|
+
process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' &&
|
|
948
|
+
++count === 256
|
|
949
|
+
) {
|
|
887
950
|
let duration = Date.now() - startTime;
|
|
888
951
|
predictedTime = duration * (events.length >> 8);
|
|
889
952
|
if (predictedTime > threshold) {
|
|
@@ -939,7 +1002,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
939
1002
|
|
|
940
1003
|
for (let connectedNode of nodes) {
|
|
941
1004
|
didInvalidate = true;
|
|
942
|
-
|
|
1005
|
+
invalidateNode(connectedNode, FILE_UPDATE);
|
|
943
1006
|
}
|
|
944
1007
|
|
|
945
1008
|
if (type === 'create') {
|
|
@@ -949,7 +1012,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
949
1012
|
);
|
|
950
1013
|
for (let connectedNode of nodes) {
|
|
951
1014
|
didInvalidate = true;
|
|
952
|
-
|
|
1015
|
+
invalidateNode(connectedNode, FILE_CREATE);
|
|
953
1016
|
}
|
|
954
1017
|
}
|
|
955
1018
|
} else if (type === 'create') {
|
|
@@ -961,21 +1024,15 @@ export class RequestGraph extends ContentGraph<
|
|
|
961
1024
|
);
|
|
962
1025
|
|
|
963
1026
|
// Find potential file nodes to be invalidated if this file name pattern matches
|
|
964
|
-
let above: Array<FileNode> =
|
|
965
|
-
for (const nodeId of this.getNodeIdsConnectedTo(
|
|
966
|
-
fileNameNodeId,
|
|
967
|
-
requestGraphEdgeTypes.invalidated_by_create_above,
|
|
968
|
-
)) {
|
|
969
|
-
let node = nullthrows(this.getNode(nodeId));
|
|
970
|
-
// these might also be `glob` nodes which get handled below, we only care about files here.
|
|
971
|
-
if (node.type === FILE) {
|
|
972
|
-
above.push(node);
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
|
|
1027
|
+
let above: Array<FileNode> = getAbove(fileNameNodeId);
|
|
976
1028
|
if (above.length > 0) {
|
|
977
1029
|
didInvalidate = true;
|
|
978
|
-
this.invalidateFileNameNode(
|
|
1030
|
+
this.invalidateFileNameNode(
|
|
1031
|
+
fileNameNode,
|
|
1032
|
+
_filePath,
|
|
1033
|
+
above,
|
|
1034
|
+
invalidateNode,
|
|
1035
|
+
);
|
|
979
1036
|
}
|
|
980
1037
|
}
|
|
981
1038
|
|
|
@@ -990,7 +1047,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
990
1047
|
);
|
|
991
1048
|
for (let connectedNode of connectedNodes) {
|
|
992
1049
|
didInvalidate = true;
|
|
993
|
-
|
|
1050
|
+
invalidateNode(connectedNode, FILE_CREATE);
|
|
994
1051
|
}
|
|
995
1052
|
}
|
|
996
1053
|
}
|
|
@@ -1001,7 +1058,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
1001
1058
|
requestGraphEdgeTypes.invalidated_by_delete,
|
|
1002
1059
|
)) {
|
|
1003
1060
|
didInvalidate = true;
|
|
1004
|
-
|
|
1061
|
+
invalidateNode(connectedNode, FILE_DELETE);
|
|
1005
1062
|
}
|
|
1006
1063
|
|
|
1007
1064
|
// Delete the file node since it doesn't exist anymore.
|
|
@@ -1033,7 +1090,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
1033
1090
|
nodeId,
|
|
1034
1091
|
requestGraphEdgeTypes.invalidated_by_update,
|
|
1035
1092
|
)) {
|
|
1036
|
-
|
|
1093
|
+
invalidateNode(
|
|
1037
1094
|
connectedNode,
|
|
1038
1095
|
type === 'delete' ? FILE_DELETE : FILE_UPDATE,
|
|
1039
1096
|
);
|
|
@@ -1057,6 +1114,8 @@ export class RequestGraph extends ContentGraph<
|
|
|
1057
1114
|
trackableEvent: 'fsevent_response_time',
|
|
1058
1115
|
duration,
|
|
1059
1116
|
predictedTime,
|
|
1117
|
+
numberOfEvents: events.length,
|
|
1118
|
+
numberOfInvalidatedNodes: invalidatedNodes.size,
|
|
1060
1119
|
},
|
|
1061
1120
|
});
|
|
1062
1121
|
|
|
@@ -1615,6 +1674,15 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1615
1674
|
let timeout;
|
|
1616
1675
|
const snapshotKey = `snapshot-${cacheKey}`;
|
|
1617
1676
|
const snapshotPath = path.join(options.cacheDir, snapshotKey + '.txt');
|
|
1677
|
+
|
|
1678
|
+
logger.verbose({
|
|
1679
|
+
origin: '@atlaspack/core',
|
|
1680
|
+
message: 'Loading request graph',
|
|
1681
|
+
meta: {
|
|
1682
|
+
cacheKey,
|
|
1683
|
+
snapshotKey,
|
|
1684
|
+
},
|
|
1685
|
+
});
|
|
1618
1686
|
if (await options.cache.hasLargeBlob(requestGraphKey)) {
|
|
1619
1687
|
try {
|
|
1620
1688
|
let {requestGraph} = await readAndDeserializeRequestGraph(
|
|
@@ -1670,6 +1738,15 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1670
1738
|
}
|
|
1671
1739
|
}
|
|
1672
1740
|
|
|
1741
|
+
logger.verbose({
|
|
1742
|
+
origin: '@atlaspack/core',
|
|
1743
|
+
message:
|
|
1744
|
+
'Cache entry for request tracker was not found, initializing a clean cache.',
|
|
1745
|
+
meta: {
|
|
1746
|
+
cacheKey,
|
|
1747
|
+
snapshotKey,
|
|
1748
|
+
},
|
|
1749
|
+
});
|
|
1673
1750
|
return new RequestGraph();
|
|
1674
1751
|
}
|
|
1675
1752
|
|
|
@@ -1705,6 +1782,10 @@ function logErrorOnBailout(
|
|
|
1705
1782
|
}
|
|
1706
1783
|
|
|
1707
1784
|
export function cleanUpOrphans<N, E: number>(graph: Graph<N, E>): NodeId[] {
|
|
1785
|
+
if (graph.rootNodeId == null) {
|
|
1786
|
+
return [];
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1708
1789
|
const reachableNodes = new Set();
|
|
1709
1790
|
graph.traverse(nodeId => {
|
|
1710
1791
|
reachableNodes.add(nodeId);
|
|
@@ -9,8 +9,10 @@ import RequestTracker, {
|
|
|
9
9
|
import {Graph} from '@atlaspack/graph';
|
|
10
10
|
import WorkerFarm from '@atlaspack/workers';
|
|
11
11
|
import {DEFAULT_OPTIONS} from './test-utils';
|
|
12
|
-
import {INITIAL_BUILD} from '../src/constants';
|
|
12
|
+
import {FILE_CREATE, FILE_UPDATE, INITIAL_BUILD} from '../src/constants';
|
|
13
13
|
import {makeDeferredWithPromise} from '@atlaspack/utils';
|
|
14
|
+
import {toProjectPath} from '../src/projectPath';
|
|
15
|
+
import {DEFAULT_FEATURE_FLAGS, setFeatureFlags} from '../../feature-flags/src';
|
|
14
16
|
|
|
15
17
|
const options = DEFAULT_OPTIONS;
|
|
16
18
|
const farm = new WorkerFarm({workerPath: require.resolve('../src/worker.js')});
|
|
@@ -449,6 +451,97 @@ describe('RequestTracker', () => {
|
|
|
449
451
|
|
|
450
452
|
assert.equal(tracker.graph.getNode(nodeId)?.invalidateReason, 1);
|
|
451
453
|
});
|
|
454
|
+
|
|
455
|
+
describe('respondToFSEvents', () => {
|
|
456
|
+
[true, false].forEach(value => {
|
|
457
|
+
beforeEach(() => {
|
|
458
|
+
setFeatureFlags({
|
|
459
|
+
...DEFAULT_FEATURE_FLAGS,
|
|
460
|
+
fixQuadraticCacheInvalidation: value === true ? 'NEW' : 'OLD',
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
afterEach(() => {
|
|
465
|
+
setFeatureFlags({
|
|
466
|
+
...DEFAULT_FEATURE_FLAGS,
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
describe(`optimizations feature-flag ${String(value)}`, () => {
|
|
471
|
+
it('should invalidate file requests on file changes', async () => {
|
|
472
|
+
let tracker = new RequestTracker({farm, options});
|
|
473
|
+
await tracker.runRequest({
|
|
474
|
+
id: 'abc',
|
|
475
|
+
type: 7,
|
|
476
|
+
// $FlowFixMe string isn't a valid result
|
|
477
|
+
run: async ({api}: {api: RunAPI<string | void>, ...}) => {
|
|
478
|
+
api.invalidateOnFileUpdate(toProjectPath('', 'my-file'));
|
|
479
|
+
let result = await Promise.resolve('hello');
|
|
480
|
+
api.storeResult(result);
|
|
481
|
+
},
|
|
482
|
+
input: null,
|
|
483
|
+
});
|
|
484
|
+
const requestId = tracker.graph.getNodeIdByContentKey('abc');
|
|
485
|
+
const invalidated = await tracker.respondToFSEvents(
|
|
486
|
+
[
|
|
487
|
+
{
|
|
488
|
+
type: 'update',
|
|
489
|
+
path: 'my-file',
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
Number.MAX_VALUE,
|
|
493
|
+
);
|
|
494
|
+
assert.equal(invalidated, true);
|
|
495
|
+
assert.equal(
|
|
496
|
+
tracker.graph.getNode(requestId)?.invalidateReason,
|
|
497
|
+
FILE_UPDATE,
|
|
498
|
+
);
|
|
499
|
+
assert.deepEqual(Array.from(tracker.graph.invalidNodeIds), [
|
|
500
|
+
requestId,
|
|
501
|
+
]);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should invalidate file name requests with invalidate above invalidations', async () => {
|
|
505
|
+
let tracker = new RequestTracker({farm, options});
|
|
506
|
+
await tracker.runRequest({
|
|
507
|
+
id: 'abc',
|
|
508
|
+
type: 7,
|
|
509
|
+
// $FlowFixMe string isn't a valid result
|
|
510
|
+
run: async ({api}: {api: RunAPI<string | void>, ...}) => {
|
|
511
|
+
api.invalidateOnFileCreate({
|
|
512
|
+
fileName: 'package.json',
|
|
513
|
+
aboveFilePath: toProjectPath(
|
|
514
|
+
'',
|
|
515
|
+
'./node_modules/something/package.json',
|
|
516
|
+
),
|
|
517
|
+
});
|
|
518
|
+
let result = await Promise.resolve('hello');
|
|
519
|
+
api.storeResult(result);
|
|
520
|
+
},
|
|
521
|
+
input: null,
|
|
522
|
+
});
|
|
523
|
+
const requestId = tracker.graph.getNodeIdByContentKey('abc');
|
|
524
|
+
const invalidated = await tracker.respondToFSEvents(
|
|
525
|
+
[
|
|
526
|
+
{
|
|
527
|
+
type: 'create',
|
|
528
|
+
path: './package.json',
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
Number.MAX_VALUE,
|
|
532
|
+
);
|
|
533
|
+
assert.equal(invalidated, true);
|
|
534
|
+
assert.equal(
|
|
535
|
+
tracker.graph.getNode(requestId)?.invalidateReason,
|
|
536
|
+
FILE_CREATE,
|
|
537
|
+
);
|
|
538
|
+
assert.deepEqual(Array.from(tracker.graph.invalidNodeIds), [
|
|
539
|
+
requestId,
|
|
540
|
+
]);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
});
|
|
452
545
|
});
|
|
453
546
|
|
|
454
547
|
describe('cleanUpOrphans', () => {
|