Browse Source

fs,module: add module-loader-only realpath cache

Reintroduce a realpath cache with the same mechanisms which existed
before b488b19eaf
(`fs: optimize realpath using uv_fs_realpath()`), but only for
the synchronous version and with the cache being passed as a
hidden option to make sure it is only used internally.

The cache is hidden from userland applications because it has been
decided that fully reintroducing as part of the public API might stand
in the way of future optimizations.

PR-URL: https://github.com/nodejs/node/pull/8100
Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
v6.x
Anna Henningsen 9 years ago
committed by Jeremiah Senkpiel
parent
commit
980c1edf63
  1. 62
      lib/fs.js
  2. 18
      lib/module.js

62
lib/fs.js

@ -1585,6 +1585,10 @@ function encodeRealpathResult(result, options, err) {
}
}
// This is removed from the fs exports in lib/module.js in order to make
// sure that this stays internal.
const realpathCacheKey = fs.realpathCacheKey = Symbol('realpathCacheKey');
fs.realpathSync = function realpathSync(p, options) {
if (!options)
options = {};
@ -1599,6 +1603,13 @@ fs.realpathSync = function realpathSync(p, options) {
const seenLinks = {};
const knownHard = {};
const cache = options[realpathCacheKey];
const original = p;
const maybeCachedResult = cache && cache.get(p);
if (maybeCachedResult) {
return maybeCachedResult;
}
// current character position in p
var pos;
@ -1639,39 +1650,47 @@ fs.realpathSync = function realpathSync(p, options) {
pos = nextPartRe.lastIndex;
// continue if not a symlink
if (knownHard[base]) {
if (knownHard[base] || (cache && cache.get(base) === base)) {
continue;
}
var resolvedLink;
var stat = fs.lstatSync(base);
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
continue;
}
const maybeCachedResolved = cache && cache.get(base);
if (maybeCachedResolved) {
resolvedLink = maybeCachedResolved;
} else {
var stat = fs.lstatSync(base);
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
continue;
}
// read the link if it wasn't read before
// dev/ino always return 0 on windows, so skip the check.
var linkTarget = null;
if (!isWindows) {
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
if (seenLinks.hasOwnProperty(id)) {
linkTarget = seenLinks[id];
// read the link if it wasn't read before
// dev/ino always return 0 on windows, so skip the check.
let linkTarget = null;
let id;
if (!isWindows) {
id = `${stat.dev.toString(32)}:${stat.ino.toString(32)}`;
if (seenLinks.hasOwnProperty(id)) {
linkTarget = seenLinks[id];
}
}
}
if (linkTarget === null) {
fs.statSync(base);
linkTarget = fs.readlinkSync(base);
}
resolvedLink = pathModule.resolve(previous, linkTarget);
if (linkTarget === null) {
fs.statSync(base);
linkTarget = fs.readlinkSync(base);
}
resolvedLink = pathModule.resolve(previous, linkTarget);
if (!isWindows) seenLinks[id] = linkTarget;
if (cache) cache.set(base, resolvedLink);
if (!isWindows) seenLinks[id] = linkTarget;
}
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
start();
}
if (cache) cache.set(original, p);
return encodeRealpathResult(p, options);
};
@ -1767,8 +1786,9 @@ fs.realpath = function realpath(p, options, callback) {
// stat & read the link if not read before
// call gotTarget as soon as the link target is known
// dev/ino always return 0 on windows, so skip the check.
let id;
if (!isWindows) {
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
id = `${stat.dev.toString(32)}:${stat.ino.toString(32)}`;
if (seenLinks.hasOwnProperty(id)) {
return gotTarget(null, seenLinks[id], base);
}

18
lib/module.js

@ -109,6 +109,14 @@ function tryPackage(requestPath, exts, isMain) {
tryExtensions(path.resolve(filename, 'index'), exts, isMain);
}
// In order to minimize unnecessary lstat() calls,
// this cache is a list of known-real paths.
// Set to an empty Map to reset.
const realpathCache = new Map();
const realpathCacheKey = fs.realpathCacheKey;
delete fs.realpathCacheKey;
// check if the file exists and is not a directory
// if using --preserve-symlinks and isMain is false,
// keep symlinks intact, otherwise resolve to the
@ -118,7 +126,13 @@ function tryFile(requestPath, isMain) {
if (preserveSymlinks && !isMain) {
return rc === 0 && path.resolve(requestPath);
}
return rc === 0 && fs.realpathSync(requestPath);
return rc === 0 && toRealPath(requestPath);
}
function toRealPath(requestPath) {
return fs.realpathSync(requestPath, {
[realpathCacheKey]: realpathCache
});
}
// given a path check a the file exists with any of the set extensions
@ -164,7 +178,7 @@ Module._findPath = function(request, paths, isMain) {
if (preserveSymlinks && !isMain) {
filename = path.resolve(basePath);
} else {
filename = fs.realpathSync(basePath);
filename = toRealPath(basePath);
}
} else if (rc === 1) { // Directory.
if (exts === undefined)

Loading…
Cancel
Save