Skip to content

Commit

Permalink
Group Haste-related data under haste in cache structure
Browse files Browse the repository at this point in the history
Summary:
Tidying up after the earlier stack separates out `mocks` from `HasteMap` and encapsulates `map` and `duplicates` within `MutableHasteMap`.

Moves `map` and `duplicates` under a new property `haste` within the cache structure.

This allows `haste` to be made nullable as a whole, and reduces some fragility and redundancy in passing `duplicates` and `map` around together.

Changelog: Internal

Reviewed By: motiz88

Differential Revision: D47129270

fbshipit-source-id: 5673fead30dd8725b01f91568ce3f36c97fd449b
  • Loading branch information
robhogan authored and facebook-github-bot committed Jul 5, 2023
1 parent a6e3dd0 commit c939178
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 42 deletions.
74 changes: 39 additions & 35 deletions packages/metro-file-map/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ describe('FileMap', () => {
}),
);

expect(cacheContent.map).toEqual(
expect(cacheContent.haste.map).toEqual(
createMap({
Banana: {
[H.GENERIC_PLATFORM]: [path.join('fruits', 'Banana.js'), H.MODULE],
Expand Down Expand Up @@ -707,7 +707,7 @@ describe('FileMap', () => {
const {fileSystem} = await fileMap.build();
const data = cacheContent;

expect(data.map.get('IRequireAVideo')).toBeDefined();
expect(data.haste.map.get('IRequireAVideo')).toBeDefined();
expect(fileSystem.linkStats(path.join('video', 'video.mp4'))).toEqual({
fileType: 'f',
modifiedTime: 32,
Expand Down Expand Up @@ -740,7 +740,7 @@ describe('FileMap', () => {
),
).toEqual({fileType: 'f', modifiedTime: 32});

expect(cacheContent.map.get('fbjs')).not.toBeDefined();
expect(cacheContent.haste.map.get('fbjs')).not.toBeDefined();

// 5 modules - the node_module
expect(fs.readFileSync.mock.calls.length).toBe(5);
Expand Down Expand Up @@ -797,7 +797,7 @@ describe('FileMap', () => {

// Duplicate modules are removed so that it doesn't cause
// non-determinism later on.
expect(cacheContent.map.get('Strawberry')).not.toBeDefined();
expect(cacheContent.haste.map.get('Strawberry')).not.toBeDefined();

expect(
console.warn.mock.calls[0][0].replaceAll('\\', '/'),
Expand Down Expand Up @@ -884,7 +884,7 @@ describe('FileMap', () => {
}),
);

expect(cacheContent.map).toEqual(
expect(cacheContent.haste.map).toEqual(
createMap({
Strawberry: {
[H.GENERIC_PLATFORM]: [
Expand Down Expand Up @@ -933,7 +933,7 @@ describe('FileMap', () => {
expect(serialize(data.fileSystem)).toEqual(
serialize(initialData.fileSystem),
);
expect(deepNormalize(data.map)).toEqual(initialData.map);
expect(deepNormalize(data.haste.map)).toEqual(initialData.haste.map);
});

it('only does minimal file system access when files change', async () => {
Expand Down Expand Up @@ -978,8 +978,8 @@ describe('FileMap', () => {
fileSystem.getDependencies(path.join('fruits', 'Banana.js')),
).toEqual(['Kiwi']);

const map = new Map(initialData.map);
expect(deepNormalize(data.map)).toEqual(map);
const map = new Map(initialData.haste.map);
expect(deepNormalize(data.haste.map)).toEqual(map);
});

it('correctly handles file deletions', async () => {
Expand All @@ -1003,9 +1003,9 @@ describe('FileMap', () => {

expect(fileSystem.exists(path.join('fruits', 'Banana.js'))).toEqual(false);

const map = new Map(initialData.map);
const map = new Map(initialData.haste.map);
map.delete('Banana');
expect(deepNormalize(cacheContent.map)).toEqual(map);
expect(deepNormalize(cacheContent.haste.map)).toEqual(map);
});

it('correctly handles platform-specific file additions', async () => {
Expand All @@ -1014,7 +1014,7 @@ describe('FileMap', () => {
const Banana = require("Banana");
`;
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), 0],
});

Expand All @@ -1026,7 +1026,7 @@ describe('FileMap', () => {
});
mockClocks = createMap({fruits: 'c:fake-clock:3'});
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), 0],
ios: [path.join('fruits', 'Strawberry.ios.js'), 0],
});
Expand All @@ -1041,7 +1041,7 @@ describe('FileMap', () => {
const Raspberry = require("Raspberry");
`;
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), 0],
ios: [path.join('fruits', 'Strawberry.ios.js'), 0],
});
Expand All @@ -1052,7 +1052,7 @@ describe('FileMap', () => {
});
mockClocks = createMap({fruits: 'c:fake-clock:3'});
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), 0],
});

Expand All @@ -1062,7 +1062,7 @@ describe('FileMap', () => {
});
mockClocks = createMap({fruits: 'c:fake-clock:4'});
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).not.toBeDefined();
expect(cacheContent.haste.map.get('Strawberry')).not.toBeDefined();
});

it('correctly handles platform-specific file renames', async () => {
Expand All @@ -1071,7 +1071,7 @@ describe('FileMap', () => {
const Raspberry = require("Raspberry");
`;
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
ios: [path.join('fruits', 'Strawberry.ios.js'), 0],
});

Expand All @@ -1084,7 +1084,7 @@ describe('FileMap', () => {
});
mockClocks = createMap({fruits: 'c:fake-clock:3'});
await new FileMap(defaultConfig).build();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), 0],
});
});
Expand All @@ -1102,7 +1102,7 @@ describe('FileMap', () => {
'//';

await new FileMap(defaultConfig).build();
expect(deepNormalize(cacheContent.duplicates)).toEqual(
expect(deepNormalize(cacheContent.haste.duplicates)).toEqual(
createMap({
Strawberry: createMap({
g: createMap({
Expand All @@ -1118,11 +1118,13 @@ describe('FileMap', () => {
}),
}),
);
expect(cacheContent.map.get('Strawberry')).not.toBeDefined();
expect(cacheContent.haste.map.get('Strawberry')).not.toBeDefined();

expect(cacheContent.map.get('Banana')).toBeDefined();
expect(cacheContent.map.get('Banana')[H.GENERIC_PLATFORM]).toBeDefined();
expect(cacheContent.map.get('Banana')['ios']).not.toBeDefined();
expect(cacheContent.haste.map.get('Banana')).toBeDefined();
expect(
cacheContent.haste.map.get('Banana')[H.GENERIC_PLATFORM],
).toBeDefined();
expect(cacheContent.haste.map.get('Banana')['ios']).not.toBeDefined();
});

it('recovers when a duplicate file is deleted', async () => {
Expand All @@ -1139,13 +1141,13 @@ describe('FileMap', () => {

await new FileMap(defaultConfig).build();
expect(
deepNormalize(cacheContent.duplicates.get('Strawberry')),
deepNormalize(cacheContent.haste.duplicates.get('Strawberry')),
).not.toBeDefined();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), H.MODULE],
});
// Make sure the other files are not affected.
expect(cacheContent.map.get('Banana')).toEqual({
expect(cacheContent.haste.map.get('Banana')).toEqual({
g: [path.join('fruits', 'Banana.js'), H.MODULE],
});
});
Expand All @@ -1164,14 +1166,14 @@ describe('FileMap', () => {

await new FileMap(defaultConfig).build();
expect(
deepNormalize(cacheContent.duplicates.get('Banana')),
deepNormalize(cacheContent.haste.duplicates.get('Banana')),
).not.toBeDefined();
expect(cacheContent.map.get('Banana')).toEqual({
expect(cacheContent.haste.map.get('Banana')).toEqual({
g: [path.join('fruits', 'Banana.js'), H.MODULE],
ios: [path.join('fruits', 'Banana.ios.js'), H.MODULE],
});
// Make sure the other files are not affected.
expect(cacheContent.map.get('Melon')).toEqual({
expect(cacheContent.haste.map.get('Melon')).toEqual({
g: [path.join('vegetables', 'Melon.js'), H.MODULE],
});
});
Expand All @@ -1185,7 +1187,9 @@ describe('FileMap', () => {

await new FileMap(defaultConfig).build();

expect(deepNormalize(cacheContent.duplicates.get('Strawberry'))).toEqual(
expect(
deepNormalize(cacheContent.haste.duplicates.get('Strawberry')),
).toEqual(
createMap({
g: createMap({
[path.join('fruits', 'Strawberry.js')]: H.MODULE,
Expand Down Expand Up @@ -1220,9 +1224,9 @@ describe('FileMap', () => {
await new FileMap(defaultConfig).build();

expect(
deepNormalize(cacheContent.duplicates.get('Strawberry')),
deepNormalize(cacheContent.haste.duplicates.get('Strawberry')),
).not.toBeDefined();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), H.MODULE],
});
});
Expand All @@ -1241,16 +1245,16 @@ describe('FileMap', () => {

await new FileMap(defaultConfig).build();
expect(
deepNormalize(cacheContent.duplicates.get('Strawberry')),
deepNormalize(cacheContent.haste.duplicates.get('Strawberry')),
).not.toBeDefined();
expect(cacheContent.map.get('Strawberry')).toEqual({
expect(cacheContent.haste.map.get('Strawberry')).toEqual({
g: [path.join('fruits', 'Strawberry.js'), H.MODULE],
});
expect(cacheContent.map.get('Pineapple')).toEqual({
expect(cacheContent.haste.map.get('Pineapple')).toEqual({
g: [path.join('fruits', 'another', 'Pineapple.js'), H.MODULE],
});
// Make sure the other files are not affected.
expect(cacheContent.map.get('Banana')).toEqual({
expect(cacheContent.haste.map.get('Banana')).toEqual({
g: [path.join('fruits', 'Banana.js'), H.MODULE],
});
});
Expand Down
3 changes: 1 addition & 2 deletions packages/metro-file-map/src/flow-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ export type BuildResult = {

export type CacheData = $ReadOnly<{
clocks: WatchmanClocks,
map: RawHasteMap['map'],
haste: RawHasteMap,
mocks: RawMockMap,
duplicates: RawHasteMap['duplicates'],
fileSystemData: mixed,
}>;

Expand Down
8 changes: 3 additions & 5 deletions packages/metro-file-map/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export type {
// This should be bumped whenever a code change to `metro-file-map` itself
// would cause a change to the cache data structure and/or content (for a given
// filesystem state and build parameters).
const CACHE_BREAKER = '5';
const CACHE_BREAKER = '6';

const CHANGE_INTERVAL = 30;
const NODE_MODULES = path.sep + 'node_modules' + path.sep;
Expand Down Expand Up @@ -372,7 +372,7 @@ export default class FileMap extends EventEmitter {
const hasteMap =
initialData != null
? MutableHasteMap.fromDeserializedSnapshot(
{duplicates: initialData.duplicates, map: initialData.map},
initialData.haste,
hasteOptions,
)
: new MutableHasteMap(hasteOptions);
Expand Down Expand Up @@ -754,13 +754,11 @@ export default class FileMap extends EventEmitter {
removed: Set<CanonicalPath>,
) {
this._startupPerfLogger?.point('persist_start');
const {map, duplicates} = hasteMap.getSerializableSnapshot();
await this._cacheManager.write(
{
fileSystemData: fileSystem.getSerializableSnapshot(),
map,
haste: hasteMap.getSerializableSnapshot(),
clocks: new Map(clocks),
duplicates,
mocks: new Map(mockMap),
},
{changed, removed},
Expand Down

0 comments on commit c939178

Please sign in to comment.