Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,34 @@ describe('cacheManager', () => {
);
});

test('serialises the snapshot before anything can change it', async () => {
const cacheManager = new DiskCacheManager({buildParameters}, defaultConfig);
// The file map's own state, which it changes once control returns to the
// event loop.
const fileSystemData = new Map<string, unknown>();
const snapshot: CacheData = {
clocks: new Map(),
fileSystemData,
plugins: new Map(),
};
const written = serialize(snapshot);
const getSnapshot = () => {
queueMicrotask(() => {
fileSystemData.set('later.js', [0, 0, 0, null, 0]);
});
return snapshot;
};
await cacheManager.write(getSnapshot, {
changedSinceCacheRead: true,
eventSource: {onChange: () => () => {}},
onWriteError: () => {},
});
expect(mockWriteFile).toHaveBeenCalledWith(
cacheManager.getCacheFilePath(),
written,
);
});

test('creates the cache directory if it does not exist', async () => {
const cacheManager = new DiskCacheManager({buildParameters}, defaultConfig);
const getSnapshot = jest.fn(
Expand Down
5 changes: 4 additions & 1 deletion packages/metro-file-map/src/flow-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ export interface CacheManager {
* crawler - i.e. internal state reflects the current file system state.
*
* getSnapshot may be retained and called at any time before end(), such as
* in response to eventSource 'change' events.
* in response to eventSource 'change' events. What it returns is the file
* map's own state, not a copy, and changes once control returns to the
* event loop. Serialize it before then, or copy it to keep it.
*/
write(
getSnapshot: () => CacheData,
Expand Down Expand Up @@ -392,6 +394,7 @@ export interface FileSystem {
removedFiles: Set<string>,
filesToStat: Map<string, number>,
};
// The file system's own data, not a copy (see `CacheManager.write`).
getSerializableSnapshot(): CacheData['fileSystemData'];
getSha1(file: Path): ?string;
getOrComputeSha1(file: Path): Promise<?{sha1: string, content?: Buffer}>;
Expand Down
14 changes: 1 addition & 13 deletions packages/metro-file-map/src/lib/TreeFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export default class TreeFS implements MutableFileSystem {
}

getSerializableSnapshot(): CacheData['fileSystemData'] {
return this.#cloneTree(this.#rootNode);
return this.#rootNode;
}

static fromDeserializedSnapshot(args: DeserializedSnapshotInput): TreeFS {
Expand Down Expand Up @@ -1490,16 +1490,4 @@ export default class TreeFS implements MutableFileSystem {
}
return result.node;
}

#cloneTree(root: DirectoryNode): DirectoryNode {
const clone: DirectoryNode = new Map();
for (const [name, node] of root) {
if (isDirectory(node)) {
clone.set(name, this.#cloneTree(node));
} else {
clone.set(name, [...node]);
}
}
return clone;
}
}
Loading