Skip to content

Commit 123bdf7

Browse files
mrsharpobluntofacebook-github-bot
authored andcommitted
FileStore now recreates parent cache folders if a write fails (#370)
Summary: **Summary** We were seeing periodic cases of builds failing where a cache write would fail. The cause of this seems to be another process cleaning up the /tmp folder periodically - to reduce the chance of these failures this PR adds some fallback logic where if a filestore write fails it will try to recursively recreate its parent cache paths and try writing again. **Test plan** Run the new unit test and see that it passes after the FileStore change is made Pull Request resolved: #370 Differential Revision: D14434560 Pulled By: cpojer fbshipit-source-id: ff33591b6eb8fb4943d8ea4c4d08d50a0072c04c
1 parent 0af35a3 commit 123bdf7

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

packages/metro-cache/src/stores/FileStore.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,29 @@ class FileStore<T> {
4949
}
5050

5151
set(key: Buffer, value: T): void {
52+
const filePath = this._getFilePath(key);
53+
try {
54+
this._set(filePath, value);
55+
} catch (err) {
56+
if (err.code === 'ENOENT') {
57+
mkdirp.sync(path.dirname(filePath));
58+
this._set(filePath, value);
59+
} else {
60+
throw err;
61+
}
62+
}
63+
}
64+
65+
_set(filePath: string, value: T): void {
5266
if (value instanceof Buffer) {
53-
const fd = fs.openSync(this._getFilePath(key), 'w');
67+
const fd = fs.openSync(filePath, 'w');
5468

5569
fs.writeSync(fd, NULL_BYTE_BUFFER);
5670
fs.writeSync(fd, value);
5771

5872
fs.closeSync(fd);
5973
} else {
60-
fs.writeFileSync(this._getFilePath(key), JSON.stringify(value));
74+
fs.writeFileSync(filePath, JSON.stringify(value));
6175
}
6276
}
6377

packages/metro-cache/src/stores/__tests__/FileStore-test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ describe('FileStore', () => {
4141
expect(fileStore.get(cache)).toEqual(null);
4242
});
4343

44+
it('writes into cache if folder is missing', () => {
45+
const fileStore = new FileStore({root: '/root'});
46+
const cache = Buffer.from([0xfa, 0xce, 0xb0, 0x0c]);
47+
const data = Buffer.from([0xca, 0xc4, 0xe5]);
48+
49+
require('rimraf').sync('/root');
50+
fileStore.set(cache, data);
51+
expect(fileStore.get(cache)).toEqual(data);
52+
});
53+
4454
it('reads and writes binary data', () => {
4555
const fileStore = new FileStore({root: '/root'});
4656
const cache = Buffer.from([0xfa, 0xce, 0xb0, 0x0c]);

packages/metro-memory-fs/src/index.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,23 @@ class MemoryFs {
570570
dirNode.entries.set(basename, this._makeDir(mode));
571571
};
572572

573+
rmdirSync = (dirPath: string | Buffer): void => {
574+
dirPath = pathStr(dirPath);
575+
const {dirNode, node, basename} = this._resolve(dirPath);
576+
if (node == null) {
577+
throw makeError('ENOENT', dirPath, 'directory does not exist');
578+
} else if (node.type === 'file') {
579+
if (this._platform === 'posix') {
580+
throw makeError('ENOTDIR', dirPath, 'cannot rm a file');
581+
} else {
582+
throw makeError('ENOENT', dirPath, 'cannot rm a file');
583+
}
584+
} else if (node.type === 'directory' && node.entries.size) {
585+
throw makeError('ENOTEMPTY', dirPath, 'directory not empty');
586+
}
587+
dirNode.entries.delete(basename);
588+
};
589+
573590
symlinkSync = (
574591
target: string | Buffer,
575592
filePath: FilePath,

0 commit comments

Comments
 (0)