mirror of https://github.com/status-im/metro.git
packager: TransformCache: store last cache collection time
Summary: Oftentimes packager stalls for several seconds after requiring a bundle, because it's busy cleaning up old cache files. We shouldn't do that when, for example, we just restarted packager. This changeset stores the micro-timestamp of the last collection so that we don't waste time next time. Reviewed By: cpojer Differential Revision: D4969832 fbshipit-source-id: 3aa0495b18d5a8efa1b8f87dbf7a40b0673fd9fd
This commit is contained in:
parent
2818bf2347
commit
e379a077ce
|
@ -20,8 +20,6 @@ const rimraf = require('rimraf');
|
||||||
const terminal = require('../lib/terminal');
|
const terminal = require('../lib/terminal');
|
||||||
const writeFileAtomicSync = require('write-file-atomic').sync;
|
const writeFileAtomicSync = require('write-file-atomic').sync;
|
||||||
|
|
||||||
const CACHE_NAME = 'react-native-packager-cache';
|
|
||||||
|
|
||||||
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
|
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
|
||||||
import type {SourceMap} from './SourceMap';
|
import type {SourceMap} from './SourceMap';
|
||||||
import type {Reporter} from './reporting';
|
import type {Reporter} from './reporting';
|
||||||
|
@ -29,6 +27,9 @@ import type {Reporter} from './reporting';
|
||||||
type CacheFilePaths = {transformedCode: string, metadata: string};
|
type CacheFilePaths = {transformedCode: string, metadata: string};
|
||||||
export type GetTransformCacheKey = (sourceCode: string, filename: string, options: {}) => string;
|
export type GetTransformCacheKey = (sourceCode: string, filename: string, options: {}) => string;
|
||||||
|
|
||||||
|
const CACHE_NAME = 'react-native-packager-cache';
|
||||||
|
const CACHE_SUB_DIR = 'cache';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If packager is running for two different directories, we don't want the
|
* If packager is running for two different directories, we don't want the
|
||||||
* caches to conflict with each other. `__dirname` carries that because packager
|
* caches to conflict with each other. `__dirname` carries that because packager
|
||||||
|
@ -84,7 +85,7 @@ function getCacheFilePaths(props: {
|
||||||
const hash = hasher.digest('hex');
|
const hash = hasher.digest('hex');
|
||||||
const prefix = hash.substr(0, 2);
|
const prefix = hash.substr(0, 2);
|
||||||
const fileName = `${hash.substr(2)}`;
|
const fileName = `${hash.substr(2)}`;
|
||||||
const base = path.join(getCacheDirPath(), prefix, fileName);
|
const base = path.join(getCacheDirPath(), CACHE_SUB_DIR, prefix, fileName);
|
||||||
return {transformedCode: base, metadata: base + '.meta'};
|
return {transformedCode: base, metadata: base + '.meta'};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,34 +182,13 @@ const GARBAGE_COLLECTOR = new (class GarbageCollector {
|
||||||
this._cacheWasReset = false;
|
this._cacheWasReset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_collectSync() {
|
|
||||||
const cacheDirPath = getCacheDirPath();
|
|
||||||
mkdirp.sync(cacheDirPath);
|
|
||||||
const prefixDirs = fs.readdirSync(cacheDirPath);
|
|
||||||
for (let i = 0; i < prefixDirs.length; ++i) {
|
|
||||||
const prefixDir = path.join(cacheDirPath, prefixDirs[i]);
|
|
||||||
const cacheFileNames = fs.readdirSync(prefixDir);
|
|
||||||
for (let j = 0; j < cacheFileNames.length; ++j) {
|
|
||||||
const cacheFilePath = path.join(prefixDir, cacheFileNames[j]);
|
|
||||||
const stats = fs.lstatSync(cacheFilePath);
|
|
||||||
const timeSinceLastAccess = Date.now() - stats.atime.getTime();
|
|
||||||
if (
|
|
||||||
stats.isFile() &&
|
|
||||||
timeSinceLastAccess > CACHE_FILE_MAX_LAST_ACCESS_TIME
|
|
||||||
) {
|
|
||||||
fs.unlinkSync(cacheFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We want to avoid preventing tool use if the cleanup fails for some reason,
|
* We want to avoid preventing tool use if the cleanup fails for some reason,
|
||||||
* but still provide some chance for people to report/fix things.
|
* but still provide some chance for people to report/fix things.
|
||||||
*/
|
*/
|
||||||
_collectSyncNoThrow() {
|
_collectSyncNoThrow() {
|
||||||
try {
|
try {
|
||||||
this._collectSync();
|
collectCacheIfOldSync();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
terminal.log(error.stack);
|
terminal.log(error.stack);
|
||||||
terminal.log(
|
terminal.log(
|
||||||
|
@ -242,6 +222,57 @@ const GARBAGE_COLLECTOR = new (class GarbageCollector {
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When restarting packager we want to avoid running the collection over again, so we store
|
||||||
|
* the last collection time in a file and we check that first.
|
||||||
|
*/
|
||||||
|
function collectCacheIfOldSync() {
|
||||||
|
const cacheDirPath = getCacheDirPath();
|
||||||
|
mkdirp.sync(cacheDirPath);
|
||||||
|
const cacheCollectionFilePath = path.join(cacheDirPath, 'last_collected');
|
||||||
|
const lastCollected = Number.parseInt(tryReadFileSync(cacheCollectionFilePath, 'utf8'), 10);
|
||||||
|
if (Number.isInteger(lastCollected) && Date.now() - lastCollected > GARBAGE_COLLECTION_PERIOD) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const effectiveCacheDirPath = path.join(cacheDirPath, CACHE_SUB_DIR);
|
||||||
|
mkdirp.sync(effectiveCacheDirPath);
|
||||||
|
collectCacheSync(effectiveCacheDirPath);
|
||||||
|
fs.writeFileSync(cacheCollectionFilePath, Date.now().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all the cache files from the specified folder that are older than a certain duration.
|
||||||
|
*/
|
||||||
|
function collectCacheSync(dirPath: string) {
|
||||||
|
const prefixDirs = fs.readdirSync(dirPath);
|
||||||
|
for (let i = 0; i < prefixDirs.length; ++i) {
|
||||||
|
const prefixDir = path.join(dirPath, prefixDirs[i]);
|
||||||
|
const cacheFileNames = fs.readdirSync(prefixDir);
|
||||||
|
for (let j = 0; j < cacheFileNames.length; ++j) {
|
||||||
|
const cacheFilePath = path.join(prefixDir, cacheFileNames[j]);
|
||||||
|
const stats = fs.lstatSync(cacheFilePath);
|
||||||
|
const timeSinceLastAccess = Date.now() - stats.atime.getTime();
|
||||||
|
if (
|
||||||
|
stats.isFile() &&
|
||||||
|
timeSinceLastAccess > CACHE_FILE_MAX_LAST_ACCESS_TIME
|
||||||
|
) {
|
||||||
|
fs.unlinkSync(cacheFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryReadFileSync(filePath: string): string {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filePath, 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== 'ENOENT') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function readMetadataFileSync(
|
function readMetadataFileSync(
|
||||||
metadataFilePath: string,
|
metadataFilePath: string,
|
||||||
): ?{
|
): ?{
|
||||||
|
|
Loading…
Reference in New Issue