Fix concurrent renaming.

We stock the renaming promise in cache to ensure that there is not concurrent renaming.
This commit is contained in:
Greg Bergé
2014-01-27 23:42:19 +01:00
parent 703ac13185
commit 3ecc389e66
2 changed files with 41 additions and 5 deletions

View File

@@ -124,7 +124,18 @@ ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
})
// Move the canonical to sourceId/target
.then(function () {
return Q.nfcall(fs.rename, canonicalDir, dir)
// We store the renaming in cache.
var key = 'moving:' + dir;
var promise;
if (that._cache.has(key)) {
promise = that._cache.get(key);
}
else {
promise = Q.nfcall(fs.rename, canonicalDir, dir);
that._cache.set(key, promise);
}
return promise
.fail(function (err) {
// If error is EXDEV it means that we are trying to rename
// across different drives, so we copy and remove it instead
@@ -132,10 +143,11 @@ ResolveCache.prototype.store = function (canonicalDir, pkgMeta) {
throw err;
}
return copy.copyDir(canonicalDir, dir)
.then(function () {
return Q.nfcall(rimraf, canonicalDir);
});
return copy.copyDir(canonicalDir, dir);
})
// To match all case, we remove the directory.
.then(function () {
return Q.nfcall(rimraf, canonicalDir);
});
});
})

View File

@@ -310,6 +310,30 @@ describe('ResolveCache', function () {
})
.done();
});
it('should be possible to store two package at same time', function (next) {
var store = resolveCache.store.bind(resolveCache, tempPackage, {
name: 'foo',
_source: 'foo',
_target: 'foo/bar'
});
var store2 = resolveCache.store.bind(resolveCache, tempPackage2, {
name: 'foo',
_source: 'foo',
_target: 'foo/bar'
});
Q.all([store(), store2()]).then(function (dirs) {
var dir = dirs[0];
expect(dir).to.equal(path.join(cacheDir, md5('foo'), 'foo%2Fbar'));
expect(fs.existsSync(dir)).to.be(true);
expect(fs.existsSync(path.join(dir, 'baz'))).to.be(true);
expect(fs.existsSync(tempPackage)).to.be(false);
expect(fs.existsSync(tempPackage2)).to.be(false);
next();
}).done();
});
});
describe('.versions', function () {