@atlaspack/core 2.17.3 → 2.18.0
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 +52 -0
- package/lib/AssetGraph.js +17 -6
- package/lib/Atlaspack.js +3 -1
- package/lib/BundleGraph.js +6 -5
- package/lib/Dependency.js +6 -2
- package/lib/Environment.js +4 -3
- package/lib/EnvironmentManager.js +137 -0
- package/lib/InternalConfig.js +3 -2
- package/lib/PackagerRunner.js +52 -15
- package/lib/RequestTracker.js +191 -89
- 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/public/Asset.js +3 -2
- package/lib/public/Bundle.js +2 -1
- package/lib/public/BundleGraph.js +21 -5
- package/lib/public/Config.js +98 -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/AssetRequest.js +2 -1
- package/lib/requests/BundleGraphRequest.js +13 -1
- package/lib/requests/ConfigRequest.js +27 -4
- 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 +13 -13
- package/src/AssetGraph.js +12 -6
- package/src/Atlaspack.js +5 -4
- package/src/BundleGraph.js +13 -8
- package/src/Dependency.js +13 -5
- package/src/Environment.js +8 -5
- package/src/EnvironmentManager.js +145 -0
- package/src/InternalConfig.js +6 -5
- package/src/PackagerRunner.js +72 -20
- package/src/RequestTracker.js +330 -146
- 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/public/Asset.js +9 -2
- package/src/public/Bundle.js +2 -1
- package/src/public/BundleGraph.js +22 -5
- package/src/public/Config.js +129 -14
- package/src/public/Dependency.js +2 -1
- package/src/public/MutableBundleGraph.js +2 -1
- package/src/public/Target.js +2 -1
- package/src/requests/AssetGraphRequest.js +13 -3
- package/src/requests/AssetRequest.js +2 -1
- package/src/requests/BundleGraphRequest.js +13 -3
- package/src/requests/ConfigRequest.js +33 -9
- 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 +9 -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/src/RequestTracker.js
CHANGED
|
@@ -30,15 +30,15 @@ import nullthrows from 'nullthrows';
|
|
|
30
30
|
|
|
31
31
|
import {
|
|
32
32
|
ATLASPACK_VERSION,
|
|
33
|
-
VALID,
|
|
34
|
-
INITIAL_BUILD,
|
|
35
33
|
FILE_CREATE,
|
|
36
|
-
FILE_UPDATE,
|
|
37
34
|
FILE_DELETE,
|
|
35
|
+
FILE_UPDATE,
|
|
38
36
|
ENV_CHANGE,
|
|
37
|
+
ERROR,
|
|
38
|
+
INITIAL_BUILD,
|
|
39
39
|
OPTION_CHANGE,
|
|
40
40
|
STARTUP,
|
|
41
|
-
|
|
41
|
+
VALID,
|
|
42
42
|
} from './constants';
|
|
43
43
|
import type {AtlaspackV3} from './atlaspack-v3/AtlaspackV3';
|
|
44
44
|
import {
|
|
@@ -69,6 +69,12 @@ import type {
|
|
|
69
69
|
InternalGlob,
|
|
70
70
|
} from './types';
|
|
71
71
|
import {BuildAbortError, assertSignalNotAborted, hashFromOption} from './utils';
|
|
72
|
+
import {performance} from 'perf_hooks';
|
|
73
|
+
|
|
74
|
+
import {
|
|
75
|
+
loadEnvironmentsFromCache,
|
|
76
|
+
writeEnvironmentsToCache,
|
|
77
|
+
} from './EnvironmentManager';
|
|
72
78
|
|
|
73
79
|
export const requestGraphEdgeTypes = {
|
|
74
80
|
subrequest: 2,
|
|
@@ -143,7 +149,7 @@ type OptionNode = {|
|
|
|
143
149
|
type ConfigKeyNode = {|
|
|
144
150
|
id: ContentKey,
|
|
145
151
|
+type: typeof CONFIG_KEY,
|
|
146
|
-
configKey: string,
|
|
152
|
+
configKey: string[],
|
|
147
153
|
contentHash: string,
|
|
148
154
|
|};
|
|
149
155
|
|
|
@@ -215,7 +221,7 @@ export type RunAPI<TResult: RequestResult> = {|
|
|
|
215
221
|
invalidateOnFileUpdate: (ProjectPath) => void,
|
|
216
222
|
invalidateOnConfigKeyChange: (
|
|
217
223
|
filePath: ProjectPath,
|
|
218
|
-
configKey: string,
|
|
224
|
+
configKey: string[],
|
|
219
225
|
contentHash: string,
|
|
220
226
|
) => void,
|
|
221
227
|
invalidateOnStartup: () => void,
|
|
@@ -282,10 +288,12 @@ const nodeFromOption = (option: string, value: mixed): RequestGraphNode => ({
|
|
|
282
288
|
|
|
283
289
|
const nodeFromConfigKey = (
|
|
284
290
|
fileName: ProjectPath,
|
|
285
|
-
configKey: string,
|
|
291
|
+
configKey: string[],
|
|
286
292
|
contentHash: string,
|
|
287
293
|
): RequestGraphNode => ({
|
|
288
|
-
id: `config_key:${fromProjectPathRelative(fileName)}:${
|
|
294
|
+
id: `config_key:${fromProjectPathRelative(fileName)}:${JSON.stringify(
|
|
295
|
+
configKey,
|
|
296
|
+
)}`,
|
|
289
297
|
type: CONFIG_KEY,
|
|
290
298
|
configKey,
|
|
291
299
|
contentHash,
|
|
@@ -526,7 +534,7 @@ export class RequestGraph extends ContentGraph<
|
|
|
526
534
|
invalidateOnConfigKeyChange(
|
|
527
535
|
requestNodeId: NodeId,
|
|
528
536
|
filePath: ProjectPath,
|
|
529
|
-
configKey: string,
|
|
537
|
+
configKey: string[],
|
|
530
538
|
contentHash: string,
|
|
531
539
|
) {
|
|
532
540
|
let configKeyNodeId = this.addNode(
|
|
@@ -713,8 +721,8 @@ export class RequestGraph extends ContentGraph<
|
|
|
713
721
|
env: string,
|
|
714
722
|
value: string | void,
|
|
715
723
|
) {
|
|
716
|
-
|
|
717
|
-
|
|
724
|
+
const envNode = nodeFromEnv(env, value);
|
|
725
|
+
const envNodeId = this.addNode(envNode);
|
|
718
726
|
|
|
719
727
|
if (
|
|
720
728
|
!this.hasEdge(
|
|
@@ -934,7 +942,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
934
942
|
* True if this is the start-up (loading phase) invalidation.
|
|
935
943
|
*/
|
|
936
944
|
isInitialBuild: boolean = false,
|
|
937
|
-
):
|
|
945
|
+
): Promise<{|
|
|
946
|
+
didInvalidate: boolean,
|
|
947
|
+
invalidationsByPath: Map<string, number>,
|
|
948
|
+
|}> {
|
|
938
949
|
let didInvalidate = false;
|
|
939
950
|
let count = 0;
|
|
940
951
|
let predictedTime = 0;
|
|
@@ -972,7 +983,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
972
983
|
return above;
|
|
973
984
|
};
|
|
974
985
|
|
|
986
|
+
const invalidationsByPath = new Map();
|
|
975
987
|
for (let {path: _path, type} of events) {
|
|
988
|
+
const invalidationsBefore = this.getInvalidNodeCount();
|
|
989
|
+
|
|
976
990
|
if (
|
|
977
991
|
!enableOptimization &&
|
|
978
992
|
process.env.ATLASPACK_DISABLE_CACHE_TIMEOUT !== 'true' &&
|
|
@@ -1018,7 +1032,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
1018
1032
|
this.invalidNodeIds.add(id);
|
|
1019
1033
|
}
|
|
1020
1034
|
}
|
|
1021
|
-
return
|
|
1035
|
+
return {
|
|
1036
|
+
didInvalidate: true,
|
|
1037
|
+
invalidationsByPath: new Map(),
|
|
1038
|
+
};
|
|
1022
1039
|
}
|
|
1023
1040
|
|
|
1024
1041
|
// sometimes mac os reports update events as create events.
|
|
@@ -1099,11 +1116,22 @@ export class RequestGraph extends ContentGraph<
|
|
|
1099
1116
|
}
|
|
1100
1117
|
|
|
1101
1118
|
let configKeyNodes = this.configKeyNodes.get(_filePath);
|
|
1102
|
-
|
|
1119
|
+
|
|
1120
|
+
// With granular invalidations we will always run this block,
|
|
1121
|
+
// so even if we get a create event (for whatever reason), we will still
|
|
1122
|
+
// try to limit invalidations from config key changes through hashing.
|
|
1123
|
+
//
|
|
1124
|
+
// Currently create events can invalidate a large number of nodes due to
|
|
1125
|
+
// "create above" invalidations.
|
|
1126
|
+
const isConfigKeyChange =
|
|
1127
|
+
getFeatureFlag('granularTsConfigInvalidation') ||
|
|
1128
|
+
type === 'delete' ||
|
|
1129
|
+
type === 'update';
|
|
1130
|
+
if (configKeyNodes && isConfigKeyChange) {
|
|
1103
1131
|
for (let nodeId of configKeyNodes) {
|
|
1104
1132
|
let isInvalid = type === 'delete';
|
|
1105
1133
|
|
|
1106
|
-
if (type
|
|
1134
|
+
if (type !== 'delete') {
|
|
1107
1135
|
let node = this.getNode(nodeId);
|
|
1108
1136
|
invariant(node && node.type === CONFIG_KEY);
|
|
1109
1137
|
|
|
@@ -1131,6 +1159,13 @@ export class RequestGraph extends ContentGraph<
|
|
|
1131
1159
|
}
|
|
1132
1160
|
}
|
|
1133
1161
|
}
|
|
1162
|
+
|
|
1163
|
+
const invalidationsAfter = this.getInvalidNodeCount();
|
|
1164
|
+
const invalidationsForEvent = invalidationsAfter - invalidationsBefore;
|
|
1165
|
+
invalidationsByPath.set(
|
|
1166
|
+
_path,
|
|
1167
|
+
(invalidationsByPath.get(_path) ?? 0) + invalidationsForEvent,
|
|
1168
|
+
);
|
|
1134
1169
|
}
|
|
1135
1170
|
|
|
1136
1171
|
if (getFeatureFlag('fixQuadraticCacheInvalidation')) {
|
|
@@ -1151,7 +1186,10 @@ export class RequestGraph extends ContentGraph<
|
|
|
1151
1186
|
},
|
|
1152
1187
|
});
|
|
1153
1188
|
|
|
1154
|
-
return
|
|
1189
|
+
return {
|
|
1190
|
+
didInvalidate,
|
|
1191
|
+
invalidationsByPath,
|
|
1192
|
+
};
|
|
1155
1193
|
}
|
|
1156
1194
|
|
|
1157
1195
|
hasCachedRequestChunk(index: number): boolean {
|
|
@@ -1165,6 +1203,13 @@ export class RequestGraph extends ContentGraph<
|
|
|
1165
1203
|
removeCachedRequestChunkForNode(nodeId: number): void {
|
|
1166
1204
|
this.cachedRequestChunks.delete(Math.floor(nodeId / this.nodesPerBlob));
|
|
1167
1205
|
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Returns the number of invalidated nodes in the graph.
|
|
1209
|
+
*/
|
|
1210
|
+
getInvalidNodeCount(): number {
|
|
1211
|
+
return this.invalidNodeIds.size;
|
|
1212
|
+
}
|
|
1168
1213
|
}
|
|
1169
1214
|
|
|
1170
1215
|
export default class RequestTracker {
|
|
@@ -1288,7 +1333,13 @@ export default class RequestTracker {
|
|
|
1288
1333
|
}
|
|
1289
1334
|
}
|
|
1290
1335
|
|
|
1291
|
-
respondToFSEvents(
|
|
1336
|
+
respondToFSEvents(
|
|
1337
|
+
events: Array<Event>,
|
|
1338
|
+
threshold: number,
|
|
1339
|
+
): Promise<{|
|
|
1340
|
+
didInvalidate: boolean,
|
|
1341
|
+
invalidationsByPath: Map<string, number>,
|
|
1342
|
+
|}> {
|
|
1292
1343
|
return this.graph.respondToFSEvents(events, this.options, threshold);
|
|
1293
1344
|
}
|
|
1294
1345
|
|
|
@@ -1499,130 +1550,143 @@ export default class RequestTracker {
|
|
|
1499
1550
|
}
|
|
1500
1551
|
}
|
|
1501
1552
|
|
|
1553
|
+
let cacheKey = getCacheKey(this.options);
|
|
1554
|
+
let requestGraphKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1555
|
+
? `${cacheKey}/RequestGraph`
|
|
1556
|
+
: `requestGraph-${cacheKey}`;
|
|
1557
|
+
let snapshotKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1558
|
+
? `${cacheKey}/snapshot`
|
|
1559
|
+
: `snapshot-${cacheKey}`;
|
|
1560
|
+
|
|
1561
|
+
if (this.options.shouldDisableCache) {
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
let total = 0;
|
|
1502
1566
|
await runCacheImprovements(
|
|
1503
1567
|
async (cache) => {
|
|
1504
1568
|
await cache.getNativeRef().startWriteTransaction();
|
|
1505
1569
|
},
|
|
1506
1570
|
() => Promise.resolve(),
|
|
1507
1571
|
);
|
|
1572
|
+
try {
|
|
1573
|
+
report({
|
|
1574
|
+
type: 'cache',
|
|
1575
|
+
phase: 'start',
|
|
1576
|
+
total,
|
|
1577
|
+
size: this.graph.nodes.length,
|
|
1578
|
+
});
|
|
1508
1579
|
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
if (this.options.shouldDisableCache) {
|
|
1514
|
-
return;
|
|
1515
|
-
}
|
|
1580
|
+
if (getFeatureFlag('environmentDeduplication')) {
|
|
1581
|
+
await writeEnvironmentsToCache(options.cache);
|
|
1582
|
+
}
|
|
1516
1583
|
|
|
1517
|
-
|
|
1518
|
-
report({
|
|
1519
|
-
type: 'cache',
|
|
1520
|
-
phase: 'start',
|
|
1521
|
-
total,
|
|
1522
|
-
size: this.graph.nodes.length,
|
|
1523
|
-
});
|
|
1584
|
+
let serialisedGraph = this.graph.serialize();
|
|
1524
1585
|
|
|
1525
|
-
|
|
1586
|
+
// Delete an existing request graph cache, to prevent invalid states
|
|
1587
|
+
await this.options.cache.deleteLargeBlob(requestGraphKey);
|
|
1526
1588
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1589
|
+
const serialiseAndSet = async (
|
|
1590
|
+
key: string,
|
|
1591
|
+
// $FlowFixMe serialise input is any type
|
|
1592
|
+
contents: any,
|
|
1593
|
+
): Promise<void> => {
|
|
1594
|
+
if (signal?.aborted) {
|
|
1595
|
+
throw new Error('Serialization was aborted');
|
|
1596
|
+
}
|
|
1529
1597
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1598
|
+
await runCacheImprovements(
|
|
1599
|
+
(cache) => {
|
|
1600
|
+
instrument(
|
|
1601
|
+
`RequestTracker::writeToCache::cache.put(${key})`,
|
|
1602
|
+
() => {
|
|
1603
|
+
cache.getNativeRef().putNoConfirm(key, serialize(contents));
|
|
1604
|
+
},
|
|
1605
|
+
);
|
|
1606
|
+
return Promise.resolve();
|
|
1607
|
+
},
|
|
1608
|
+
async () => {
|
|
1609
|
+
await this.options.cache.setLargeBlob(
|
|
1610
|
+
key,
|
|
1611
|
+
serialize(contents),
|
|
1612
|
+
signal
|
|
1613
|
+
? {
|
|
1614
|
+
signal: signal,
|
|
1615
|
+
}
|
|
1616
|
+
: undefined,
|
|
1617
|
+
);
|
|
1618
|
+
},
|
|
1619
|
+
);
|
|
1538
1620
|
|
|
1539
|
-
|
|
1540
|
-
(cache) => {
|
|
1541
|
-
instrument(`cache.put(${key})`, () => {
|
|
1542
|
-
cache.getNativeRef().putNoConfirm(key, serialize(contents));
|
|
1543
|
-
});
|
|
1544
|
-
return Promise.resolve();
|
|
1545
|
-
},
|
|
1546
|
-
async () => {
|
|
1547
|
-
await this.options.cache.setLargeBlob(
|
|
1548
|
-
key,
|
|
1549
|
-
serialize(contents),
|
|
1550
|
-
signal
|
|
1551
|
-
? {
|
|
1552
|
-
signal: signal,
|
|
1553
|
-
}
|
|
1554
|
-
: undefined,
|
|
1555
|
-
);
|
|
1556
|
-
},
|
|
1557
|
-
);
|
|
1621
|
+
total += 1;
|
|
1558
1622
|
|
|
1559
|
-
|
|
1623
|
+
report({
|
|
1624
|
+
type: 'cache',
|
|
1625
|
+
phase: 'write',
|
|
1626
|
+
total,
|
|
1627
|
+
size: this.graph.nodes.length,
|
|
1628
|
+
});
|
|
1629
|
+
};
|
|
1560
1630
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
phase: 'write',
|
|
1564
|
-
total,
|
|
1565
|
-
size: this.graph.nodes.length,
|
|
1631
|
+
let queue = new PromiseQueue({
|
|
1632
|
+
maxConcurrent: 32,
|
|
1566
1633
|
});
|
|
1567
|
-
};
|
|
1568
1634
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1574
|
-
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1575
|
-
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1576
|
-
let node = serialisedGraph.nodes[i];
|
|
1635
|
+
// Preallocating a sparse array is faster than pushing when N is high enough
|
|
1636
|
+
let cacheableNodes = new Array(serialisedGraph.nodes.length);
|
|
1637
|
+
for (let i = 0; i < serialisedGraph.nodes.length; i += 1) {
|
|
1638
|
+
let node = serialisedGraph.nodes[i];
|
|
1577
1639
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1640
|
+
let resultCacheKey = node?.resultCacheKey;
|
|
1641
|
+
if (
|
|
1642
|
+
node?.type === REQUEST &&
|
|
1643
|
+
resultCacheKey != null &&
|
|
1644
|
+
node?.result != null
|
|
1645
|
+
) {
|
|
1646
|
+
queue.add(() => serialiseAndSet(resultCacheKey, node.result));
|
|
1585
1647
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1648
|
+
// eslint-disable-next-line no-unused-vars
|
|
1649
|
+
let {result: _, ...newNode} = node;
|
|
1650
|
+
cacheableNodes[i] = newNode;
|
|
1651
|
+
} else {
|
|
1652
|
+
cacheableNodes[i] = node;
|
|
1653
|
+
}
|
|
1591
1654
|
}
|
|
1592
|
-
}
|
|
1593
1655
|
|
|
1594
|
-
|
|
1656
|
+
let nodeCountsPerBlob = [];
|
|
1595
1657
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1658
|
+
for (
|
|
1659
|
+
let i = 0;
|
|
1660
|
+
i * this.graph.nodesPerBlob < cacheableNodes.length;
|
|
1661
|
+
i += 1
|
|
1662
|
+
) {
|
|
1663
|
+
let nodesStartIndex = i * this.graph.nodesPerBlob;
|
|
1664
|
+
let nodesEndIndex = Math.min(
|
|
1665
|
+
(i + 1) * this.graph.nodesPerBlob,
|
|
1666
|
+
cacheableNodes.length,
|
|
1667
|
+
);
|
|
1606
1668
|
|
|
1607
|
-
|
|
1669
|
+
nodeCountsPerBlob.push(nodesEndIndex - nodesStartIndex);
|
|
1608
1670
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1671
|
+
if (!this.graph.hasCachedRequestChunk(i)) {
|
|
1672
|
+
// We assume the request graph nodes are immutable and won't change
|
|
1673
|
+
let nodesToCache = cacheableNodes.slice(
|
|
1674
|
+
nodesStartIndex,
|
|
1675
|
+
nodesEndIndex,
|
|
1676
|
+
);
|
|
1612
1677
|
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1678
|
+
queue.add(() =>
|
|
1679
|
+
serialiseAndSet(
|
|
1680
|
+
getRequestGraphNodeKey(i, cacheKey),
|
|
1681
|
+
nodesToCache,
|
|
1682
|
+
).then(() => {
|
|
1683
|
+
// Succeeded in writing to disk, save that we have completed this chunk
|
|
1684
|
+
this.graph.setCachedRequestChunk(i);
|
|
1685
|
+
}),
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1622
1688
|
}
|
|
1623
|
-
}
|
|
1624
1689
|
|
|
1625
|
-
try {
|
|
1626
1690
|
await queue.run();
|
|
1627
1691
|
|
|
1628
1692
|
// Set the request graph after the queue is flushed to avoid writing an invalid state
|
|
@@ -1634,7 +1698,7 @@ export default class RequestTracker {
|
|
|
1634
1698
|
|
|
1635
1699
|
await runCacheImprovements(
|
|
1636
1700
|
() =>
|
|
1637
|
-
serialiseAndSet(
|
|
1701
|
+
serialiseAndSet(`${cacheKey}/cache_metadata`, {
|
|
1638
1702
|
version: ATLASPACK_VERSION,
|
|
1639
1703
|
entries: this.options.entries,
|
|
1640
1704
|
mode: this.options.mode,
|
|
@@ -1655,15 +1719,15 @@ export default class RequestTracker {
|
|
|
1655
1719
|
} catch (err) {
|
|
1656
1720
|
// If we have aborted, ignore the error and continue
|
|
1657
1721
|
if (!signal?.aborted) throw err;
|
|
1722
|
+
} finally {
|
|
1723
|
+
await runCacheImprovements(
|
|
1724
|
+
async (cache) => {
|
|
1725
|
+
await cache.getNativeRef().commitWriteTransaction();
|
|
1726
|
+
},
|
|
1727
|
+
() => Promise.resolve(),
|
|
1728
|
+
);
|
|
1658
1729
|
}
|
|
1659
1730
|
|
|
1660
|
-
await runCacheImprovements(
|
|
1661
|
-
async (cache) => {
|
|
1662
|
-
await cache.getNativeRef().commitWriteTransaction();
|
|
1663
|
-
},
|
|
1664
|
-
() => Promise.resolve(),
|
|
1665
|
-
);
|
|
1666
|
-
|
|
1667
1731
|
report({type: 'cache', phase: 'end', total, size: this.graph.nodes.length});
|
|
1668
1732
|
}
|
|
1669
1733
|
|
|
@@ -1695,6 +1759,18 @@ export function getWatcherOptions({
|
|
|
1695
1759
|
}
|
|
1696
1760
|
|
|
1697
1761
|
function getCacheKey(options) {
|
|
1762
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1763
|
+
const hash = hashString(
|
|
1764
|
+
`${ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${
|
|
1765
|
+
options.mode
|
|
1766
|
+
}:${options.shouldBuildLazily ? 'lazy' : 'eager'}:${
|
|
1767
|
+
options.watchBackend ?? ''
|
|
1768
|
+
}`,
|
|
1769
|
+
);
|
|
1770
|
+
|
|
1771
|
+
return `RequestTracker/${ATLASPACK_VERSION}/${hash}`;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1698
1774
|
return hashString(
|
|
1699
1775
|
`${ATLASPACK_VERSION}:${JSON.stringify(options.entries)}:${options.mode}:${
|
|
1700
1776
|
options.shouldBuildLazily ? 'lazy' : 'eager'
|
|
@@ -1703,6 +1779,10 @@ function getCacheKey(options) {
|
|
|
1703
1779
|
}
|
|
1704
1780
|
|
|
1705
1781
|
function getRequestGraphNodeKey(index: number, cacheKey: string) {
|
|
1782
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1783
|
+
return `${cacheKey}/RequestGraph/nodes/${index}`;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1706
1786
|
return `requestGraph-nodes-${index}-${cacheKey}`;
|
|
1707
1787
|
}
|
|
1708
1788
|
|
|
@@ -1714,9 +1794,15 @@ export async function readAndDeserializeRequestGraph(
|
|
|
1714
1794
|
let bufferLength = 0;
|
|
1715
1795
|
|
|
1716
1796
|
const getAndDeserialize = async (key: string) => {
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1797
|
+
if (getFeatureFlag('cachePerformanceImprovements')) {
|
|
1798
|
+
const buffer = await cache.getBlob(key);
|
|
1799
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1800
|
+
return deserialize(buffer);
|
|
1801
|
+
} else {
|
|
1802
|
+
const buffer = await cache.getLargeBlob(key);
|
|
1803
|
+
bufferLength += Buffer.byteLength(buffer);
|
|
1804
|
+
return deserialize(buffer);
|
|
1805
|
+
}
|
|
1720
1806
|
};
|
|
1721
1807
|
|
|
1722
1808
|
let serializedRequestGraph = await getAndDeserialize(requestGraphKey);
|
|
@@ -1749,9 +1835,14 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1749
1835
|
}
|
|
1750
1836
|
|
|
1751
1837
|
let cacheKey = getCacheKey(options);
|
|
1752
|
-
let requestGraphKey =
|
|
1838
|
+
let requestGraphKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1839
|
+
? `${cacheKey}/RequestGraph`
|
|
1840
|
+
: `requestGraph-${cacheKey}`;
|
|
1841
|
+
|
|
1753
1842
|
let timeout;
|
|
1754
|
-
const snapshotKey =
|
|
1843
|
+
const snapshotKey = getFeatureFlag('cachePerformanceImprovements')
|
|
1844
|
+
? `${cacheKey}/snapshot`
|
|
1845
|
+
: `snapshot-${cacheKey}`;
|
|
1755
1846
|
const snapshotPath = path.join(options.cacheDir, snapshotKey + '.txt');
|
|
1756
1847
|
|
|
1757
1848
|
const commonMeta = {
|
|
@@ -1774,7 +1865,15 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1774
1865
|
},
|
|
1775
1866
|
});
|
|
1776
1867
|
|
|
1777
|
-
if (
|
|
1868
|
+
if (getFeatureFlag('environmentDeduplication')) {
|
|
1869
|
+
await loadEnvironmentsFromCache(options.cache);
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
const hasRequestGraphInCache = getFeatureFlag('cachePerformanceImprovements')
|
|
1873
|
+
? await options.cache.has(requestGraphKey)
|
|
1874
|
+
: await options.cache.hasLargeBlob(requestGraphKey);
|
|
1875
|
+
|
|
1876
|
+
if (hasRequestGraphInCache) {
|
|
1778
1877
|
try {
|
|
1779
1878
|
let {requestGraph} = await readAndDeserializeRequestGraph(
|
|
1780
1879
|
options.cache,
|
|
@@ -1863,7 +1962,11 @@ async function loadRequestGraph(options): Async<RequestGraph> {
|
|
|
1863
1962
|
*/
|
|
1864
1963
|
type InvalidationFn = {|
|
|
1865
1964
|
key: string,
|
|
1866
|
-
fn: () =>
|
|
1965
|
+
fn: () =>
|
|
1966
|
+
| InvalidationDetail
|
|
1967
|
+
| Promise<InvalidationDetail>
|
|
1968
|
+
| void
|
|
1969
|
+
| Promise<void>,
|
|
1867
1970
|
|};
|
|
1868
1971
|
|
|
1869
1972
|
type InvalidationStats = {|
|
|
@@ -1893,6 +1996,33 @@ type InvalidationStats = {|
|
|
|
1893
1996
|
invalidations: InvalidationFnStats[],
|
|
1894
1997
|
|};
|
|
1895
1998
|
|
|
1999
|
+
/**
|
|
2000
|
+
* Details about an invalidation.
|
|
2001
|
+
*
|
|
2002
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
2003
|
+
* by path.
|
|
2004
|
+
*
|
|
2005
|
+
* If this is a env or option invalidation, this key will contain the list of changed environment
|
|
2006
|
+
* variables or options.
|
|
2007
|
+
*/
|
|
2008
|
+
type InvalidationDetail = string[] | FSInvalidationStats;
|
|
2009
|
+
|
|
2010
|
+
/**
|
|
2011
|
+
* Number of invalidations for a given file-system event.
|
|
2012
|
+
*/
|
|
2013
|
+
type FSInvalidation = {|
|
|
2014
|
+
path: string,
|
|
2015
|
+
count: number,
|
|
2016
|
+
|};
|
|
2017
|
+
|
|
2018
|
+
type FSInvalidationStats = {|
|
|
2019
|
+
/**
|
|
2020
|
+
* This list will be sorted by the number of nodes invalidated and only the top 10 will be
|
|
2021
|
+
* included.
|
|
2022
|
+
*/
|
|
2023
|
+
biggestInvalidations: FSInvalidation[],
|
|
2024
|
+
|};
|
|
2025
|
+
|
|
1896
2026
|
/**
|
|
1897
2027
|
* Information about a certain cache invalidation type.
|
|
1898
2028
|
*/
|
|
@@ -1913,8 +2043,14 @@ type InvalidationFnStats = {|
|
|
|
1913
2043
|
count: number,
|
|
1914
2044
|
/**
|
|
1915
2045
|
* If this is a env or option invalidation, this key will contain the list of changed values.
|
|
2046
|
+
*
|
|
2047
|
+
* If this is a fs events invalidation, this key will contain statistics about invalidations
|
|
1916
2048
|
*/
|
|
1917
|
-
|
|
2049
|
+
detail: null | InvalidationDetail,
|
|
2050
|
+
/**
|
|
2051
|
+
* Time in milliseconds it took to run the invalidation.
|
|
2052
|
+
*/
|
|
2053
|
+
duration: number,
|
|
1918
2054
|
|};
|
|
1919
2055
|
|
|
1920
2056
|
/**
|
|
@@ -1923,7 +2059,7 @@ type InvalidationFnStats = {|
|
|
|
1923
2059
|
*
|
|
1924
2060
|
* Returns the count of nodes invalidated by each invalidation type.
|
|
1925
2061
|
*/
|
|
1926
|
-
async function invalidateRequestGraph(
|
|
2062
|
+
export async function invalidateRequestGraph(
|
|
1927
2063
|
requestGraph: RequestGraph,
|
|
1928
2064
|
options: AtlaspackOptions,
|
|
1929
2065
|
events: Event[],
|
|
@@ -1947,14 +2083,7 @@ async function invalidateRequestGraph(
|
|
|
1947
2083
|
},
|
|
1948
2084
|
{
|
|
1949
2085
|
key: 'fsEvents',
|
|
1950
|
-
fn:
|
|
1951
|
-
await requestGraph.respondToFSEvents(
|
|
1952
|
-
options.unstableFileInvalidations || events,
|
|
1953
|
-
options,
|
|
1954
|
-
10000,
|
|
1955
|
-
true,
|
|
1956
|
-
);
|
|
1957
|
-
},
|
|
2086
|
+
fn: () => invalidateRequestGraphFSEvents(requestGraph, options, events),
|
|
1958
2087
|
},
|
|
1959
2088
|
];
|
|
1960
2089
|
|
|
@@ -1984,22 +2113,61 @@ async function invalidateRequestGraph(
|
|
|
1984
2113
|
};
|
|
1985
2114
|
}
|
|
1986
2115
|
|
|
2116
|
+
interface InvalidateRequestGraphFSEventsInput {
|
|
2117
|
+
respondToFSEvents(
|
|
2118
|
+
events: Event[],
|
|
2119
|
+
options: AtlaspackOptions,
|
|
2120
|
+
timeout: number,
|
|
2121
|
+
shouldLog: boolean,
|
|
2122
|
+
): Promise<{invalidationsByPath: Map<string, number>, ...}>;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* Invalidate the request graph based on file-system events.
|
|
2127
|
+
*
|
|
2128
|
+
* Returns statistics about the invalidations.
|
|
2129
|
+
*/
|
|
2130
|
+
export async function invalidateRequestGraphFSEvents(
|
|
2131
|
+
requestGraph: InvalidateRequestGraphFSEventsInput,
|
|
2132
|
+
options: AtlaspackOptions,
|
|
2133
|
+
events: Event[],
|
|
2134
|
+
): Promise<FSInvalidationStats> {
|
|
2135
|
+
const {invalidationsByPath} = await requestGraph.respondToFSEvents(
|
|
2136
|
+
options.unstableFileInvalidations || events,
|
|
2137
|
+
options,
|
|
2138
|
+
10000,
|
|
2139
|
+
true,
|
|
2140
|
+
);
|
|
2141
|
+
const biggestInvalidations =
|
|
2142
|
+
getBiggestFSEventsInvalidations(invalidationsByPath);
|
|
2143
|
+
|
|
2144
|
+
return {
|
|
2145
|
+
biggestInvalidations,
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
interface RunInvalidationInput {
|
|
2150
|
+
getInvalidNodeCount(): number;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
1987
2153
|
/**
|
|
1988
2154
|
* Runs an invalidation function and reports metrics.
|
|
1989
2155
|
*/
|
|
1990
|
-
async function runInvalidation(
|
|
1991
|
-
requestGraph:
|
|
2156
|
+
export async function runInvalidation(
|
|
2157
|
+
requestGraph: RunInvalidationInput,
|
|
1992
2158
|
invalidationFn: InvalidationFn,
|
|
1993
2159
|
): Promise<InvalidationFnStats> {
|
|
1994
|
-
const
|
|
2160
|
+
const start = performance.now();
|
|
2161
|
+
const startInvalidationCount = requestGraph.getInvalidNodeCount();
|
|
1995
2162
|
const result = await invalidationFn.fn();
|
|
1996
|
-
const count = requestGraph.
|
|
2163
|
+
const count = requestGraph.getInvalidNodeCount() - startInvalidationCount;
|
|
2164
|
+
const duration = performance.now() - start;
|
|
1997
2165
|
|
|
1998
2166
|
return {
|
|
1999
2167
|
key: invalidationFn.key,
|
|
2000
2168
|
count,
|
|
2001
|
-
|
|
2002
|
-
|
|
2169
|
+
detail: result ?? null,
|
|
2170
|
+
duration,
|
|
2003
2171
|
};
|
|
2004
2172
|
}
|
|
2005
2173
|
|
|
@@ -2054,3 +2222,19 @@ export function cleanUpOrphans<N, E: number>(graph: Graph<N, E>): NodeId[] {
|
|
|
2054
2222
|
|
|
2055
2223
|
return removedNodeIds;
|
|
2056
2224
|
}
|
|
2225
|
+
|
|
2226
|
+
/**
|
|
2227
|
+
* Returns paths that invalidated the most nodes
|
|
2228
|
+
*/
|
|
2229
|
+
export function getBiggestFSEventsInvalidations(
|
|
2230
|
+
invalidationsByPath: Map<string, number>,
|
|
2231
|
+
limit: number = 10,
|
|
2232
|
+
): Array<FSInvalidation> {
|
|
2233
|
+
const invalidations = [];
|
|
2234
|
+
for (const [path, count] of invalidationsByPath) {
|
|
2235
|
+
invalidations.push({path, count});
|
|
2236
|
+
}
|
|
2237
|
+
invalidations.sort((a, b) => b.count - a.count);
|
|
2238
|
+
|
|
2239
|
+
return invalidations.slice(0, limit);
|
|
2240
|
+
}
|