Skip to content

Commit ed2ee78

Browse files
committed
More compact storage micro-optimization.
1 parent fbea74b commit ed2ee78

9 files changed

Lines changed: 136 additions & 90 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the BSD-style license found in the
5+
* LICENSE file in the root directory of this source tree. An additional grant
6+
* of patent rights can be found in the PATENTS file in the same directory.
7+
*/
8+
9+
/*
10+
* This file exports a set of constants that are used for Jest's haste map
11+
* serialization. On very large repositories, the haste map cache becomes very
12+
* large to the point where it is the largest overhead in starting up Jest.
13+
*
14+
* This constant key map allows to keep the map smaller without having to build
15+
* a custom serialization library.
16+
*/
17+
module.exports = {
18+
/* shared in file map and module map */
19+
ID: 0,
20+
21+
/* file map attributes */
22+
MTIME: 1,
23+
VISITED: 2,
24+
DEPENDENCIES: 3,
25+
26+
/* module map attributes */
27+
PATH: 1,
28+
TYPE: 2,
29+
30+
/* module types */
31+
MODULE: 0,
32+
PACKAGE: 1,
33+
34+
/* platforms */
35+
GENERIC_PLATFORM: 'g',
36+
};

packages/jest-haste-map/src/crawlers/node.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99

1010
'use strict';
1111

12+
const H = require('../constants');
13+
1214
const fs = require('fs');
1315
const os = require('os');
1416
const path = require('path');
1517
const spawn = require('child_process').spawn;
1618

17-
function find(roots, extensions, ignorePattern, callback) {
19+
function find(roots, extensions, ignore, callback) {
1820
const result = [];
1921
let activeCalls = 0;
2022

@@ -28,7 +30,7 @@ function find(roots, extensions, ignorePattern, callback) {
2830
}
2931

3032
names.forEach(file => {
31-
if (ignorePattern.test(file)) {
33+
if (ignore(file)) {
3234
return;
3335
}
3436
activeCalls++;
@@ -61,7 +63,7 @@ function find(roots, extensions, ignorePattern, callback) {
6163
roots.forEach(search);
6264
}
6365

64-
function findNative(roots, extensions, ignorePattern, callback) {
66+
function findNative(roots, extensions, ignore, callback) {
6567
const args = [].concat(roots);
6668
args.push('-type', 'f');
6769
extensions.forEach((ext, index) => {
@@ -80,7 +82,7 @@ function findNative(roots, extensions, ignorePattern, callback) {
8082
child.stdout.on('close', code => {
8183
const lines = stdout.trim()
8284
.split('\n')
83-
.filter(x => !ignorePattern.test(x));
85+
.filter(x => !ignore(x));
8486
const result = [];
8587
let count = lines.length;
8688
lines.forEach(path => {
@@ -96,33 +98,30 @@ function findNative(roots, extensions, ignorePattern, callback) {
9698
});
9799
}
98100

99-
module.exports = function nodeCrawl(roots, extensions, ignorePattern, data) {
101+
module.exports = function nodeCrawl(roots, extensions, ignore, data) {
100102
return new Promise(resolve => {
101103
const callback = list => {
102104
const files = Object.create(null);
103105
list.forEach(fileData => {
104106
const name = fileData[0];
105107
const mtime = fileData[1];
106108
const existingFile = data.files[name];
107-
if (existingFile && existingFile.mtime === mtime) {
109+
if (existingFile && existingFile[H.MTIME] === mtime) {
108110
//console.log('exists', name);
109111
files[name] = existingFile;
110112
} else {
111113
//console.log('add', name);
112-
files[name] = {
113-
mtime,
114-
visited: false,
115-
};
114+
files[name] = [0, mtime, 0, []];
116115
}
117116
});
118117
data.files = files;
119118
resolve(data);
120119
};
121120

122121
if (os.platform() == 'win32') {
123-
find(roots, extensions, ignorePattern, callback);
122+
find(roots, extensions, ignore, callback);
124123
} else {
125-
findNative(roots, extensions, ignorePattern, callback);
124+
findNative(roots, extensions, ignore, callback);
126125
}
127126
});
128127
};

packages/jest-haste-map/src/crawlers/watchman.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
'use strict';
1111

12+
const H = require('../constants');
13+
1214
const denodeify = require('denodeify');
1315
const path = require('../fastpath');
1416
const watchman = require('fb-watchman');
@@ -29,7 +31,7 @@ function WatchmanError(error) {
2931
module.exports = function watchmanCrawl(
3032
roots,
3133
extensions,
32-
ignorePattern,
34+
ignore,
3335
data
3436
) {
3537
const files = data.files;
@@ -80,16 +82,12 @@ module.exports = function watchmanCrawl(
8082
if (!fileData.exists) {
8183
//console.log('remove', name);
8284
delete files[name];
83-
} else if (!ignorePattern.test(name)) {
85+
} else if (!ignore(name)) {
8486
//console.log('add', name);
8587
const mtime = fileData.mtime_ms.toNumber();
86-
const isNew = !files[name] || files[name].mtime !== mtime;
88+
const isNew = !files[name] || files[name][H.MTIME] !== mtime;
8789
if (isNew) {
88-
files[name] = {
89-
id: null,
90-
mtime,
91-
visited: false,
92-
};
90+
files[name] = [0, mtime, 0, []];
9391
}
9492
}
9593
});

packages/jest-haste-map/src/index.js

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
*/
99
'use strict';
1010

11+
const H = require('./constants');
12+
1113
const crypto = require('crypto');
1214
const denodeify = require('denodeify');
1315
const execSync = require('child_process').execSync;
@@ -20,7 +22,6 @@ const watchmanCrawl = require('./crawlers/watchman');
2022
const worker = require('./worker');
2123
const workerFarm = require('worker-farm');
2224

23-
const GENERIC_PLATFORM = 'g';
2425
const NODE_MODULES = path.sep + 'node_modules' + path.sep;
2526
const VERSION = require('../package.json').version;
2627

@@ -42,6 +43,7 @@ class HasteMap {
4243
maxWorkers: options.maxWorkers,
4344
mocksPattern:
4445
options.mocksPattern ? new RegExp(options.mocksPattern) : null,
46+
name: options.name,
4547
platforms: options.platforms,
4648
resetCache: options.resetCache,
4749
roots: options.roots,
@@ -57,6 +59,7 @@ class HasteMap {
5759
this._cachePath = HasteMap.getCacheFilePath(
5860
this._options.cacheDirectory,
5961
VERSION,
62+
this._options.name,
6063
this._options.roots.join(':'),
6164
this._options.extensions.join(':'),
6265
this._options.platforms.join(':'),
@@ -121,17 +124,19 @@ class HasteMap {
121124
const mocksPattern = this._options.mocksPattern;
122125
const promises = [];
123126
const setModule = module => {
124-
if (!map[module.id]) {
125-
map[module.id] = Object.create(null);
127+
if (!map[module[H.ID]]) {
128+
map[module[H.ID]] = Object.create(null);
126129
}
127-
const moduleMap = map[module.id];
128-
const platform = getPlatformExtension(module.path) || GENERIC_PLATFORM;
130+
const moduleMap = map[module[H.ID]];
131+
const platform =
132+
getPlatformExtension(module[H.PATH]) || H.GENERIC_PLATFORM;
129133
const existingModule = moduleMap[platform];
130-
if (existingModule && existingModule.path !== module.path) {
134+
if (existingModule && existingModule[H.PATH] !== module[H.PATH]) {
131135
console.warn(
132136
`@providesModule naming collision:\n` +
133137
` Duplicate module name: ${module.id}\n` +
134-
` Paths: ${module.path} collides with ${existingModule.path}\n\n` +
138+
` Paths: ${module[H.PATH]} collides with ` +
139+
`${existingModule[H.PATH]}\n\n` +
135140
`This warning is caused by a @providesModule declaration ` +
136141
`with the same name accross two different files.`
137142
);
@@ -145,31 +150,29 @@ class HasteMap {
145150
mocks[path.basename(filePath, path.extname(filePath))] = filePath;
146151
}
147152

148-
if (!this._isNodeModulesDir(filePath)) {
149-
const fileData = data.files[filePath];
150-
const moduleData = data.map[fileData.id];
151-
if (fileData.visited) {
152-
if (!fileData.id) {
153-
continue;
154-
} else if (fileData.id && moduleData) {
155-
map[fileData.id] = moduleData;
156-
continue;
157-
}
153+
const fileData = data.files[filePath];
154+
const moduleData = data.map[fileData[H.ID]];
155+
if (fileData[H.VISITED]) {
156+
if (!fileData[H.ID]) {
157+
continue;
158+
} else if (fileData[H.ID] && moduleData) {
159+
map[fileData[H.ID]] = moduleData;
160+
continue;
158161
}
159-
160-
promises.push(
161-
this._getWorker()({filePath}).then(data => {
162-
fileData.visited = true;
163-
if (data.module) {
164-
fileData.id = data.module.id;
165-
setModule(data.module);
166-
}
167-
if (data.dependencies) {
168-
fileData.dependencies = data.dependencies;
169-
}
170-
})
171-
);
172162
}
163+
164+
promises.push(
165+
this._getWorker()({filePath}).then(data => {
166+
fileData[H.VISITED] = 1;
167+
if (data.module) {
168+
fileData[H.ID] = data.module[H.ID];
169+
setModule(data.module);
170+
}
171+
if (data.dependencies) {
172+
fileData[H.DEPENDENCIES] = data[H.DEPENDENCIES];
173+
}
174+
})
175+
);
173176
}
174177

175178
return Promise.all(promises)
@@ -228,11 +231,18 @@ class HasteMap {
228231
return crawl(
229232
this._options.roots,
230233
this._options.extensions,
231-
this._options.ignorePattern,
234+
this._ignore.bind(this),
232235
data
233236
);
234237
}
235238

239+
_ignore(filePath) {
240+
return (
241+
this._options.ignorePattern.test(filePath) ||
242+
this._isNodeModulesDir(filePath)
243+
);
244+
}
245+
236246
_isNodeModulesDir(filePath) {
237247
if (!filePath.includes(NODE_MODULES)) {
238248
return false;
@@ -257,6 +267,4 @@ class HasteMap {
257267

258268
}
259269

260-
HasteMap.GENERIC_PLATFORM = GENERIC_PLATFORM;
261-
262270
module.exports = HasteMap;

packages/jest-haste-map/src/worker.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
*/
88
'use strict';
99

10+
const H = require('./constants');
11+
1012
const docblock = require('./lib/docblock');
1113
const extractRequires = require('./lib/extractRequires');
1214
const fs = require('graceful-fs');
@@ -40,22 +42,14 @@ module.exports = (data, callback) => {
4042
if (filePath.endsWith(PACKAGE_JSON)) {
4143
const fileData = JSON.parse(content);
4244
if (fileData.name) {
43-
module = {
44-
id: fileData.name,
45-
path: filePath,
46-
type: 'package',
47-
};
45+
module = [fileData.name, filePath, H.PACKAGE];
4846
}
4947
} else {
5048
const doc = docblock.parse(docblock.extract(content));
5149
const id = doc.providesModule || doc.provides;
5250
dependencies = extractRequires(content);
5351
if (id) {
54-
module = {
55-
id,
56-
path: filePath,
57-
type: 'module',
58-
};
52+
module = [id, filePath, H.MODULE];
5953
}
6054
}
6155
callback(null, {module, dependencies});

src/Runtime/Runtime.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
'use strict';
1010

11-
const HasteMap = require('jest-haste-map');
11+
const H = require('jest-haste-map/src/constants');
1212

1313
const constants = require('../constants');
1414
const fs = require('graceful-fs');
@@ -456,23 +456,22 @@ class Runtime {
456456

457457
_getModule(name, type) {
458458
if (!type) {
459-
type = 'module';
459+
type = H.MODULE;
460460
}
461461

462462
const map = this._modules[name];
463463
if (map) {
464-
const module =
465-
map[this._defaultPlatform] || map[HasteMap.GENERIC_PLATFORM];
466-
if (module && module.type == type) {
467-
return module.path;
464+
const module = map[this._defaultPlatform] || map[H.GENERIC_PLATFORM];
465+
if (module && module[H.TYPE] == type) {
466+
return module[H.PATH];
468467
}
469468
}
470469

471470
return null;
472471
}
473472

474473
_getPackage(name) {
475-
return this._getModule(name, 'package');
474+
return this._getModule(name, H.PACKAGE);
476475
}
477476

478477
_getMockModule(name) {

0 commit comments

Comments
 (0)