summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/lockfile
diff options
context:
space:
mode:
authorTimothy J Fontaine <tjfontaine@gmail.com>2014-09-16 15:38:50 -0700
committerTimothy J Fontaine <tjfontaine@gmail.com>2014-09-16 15:38:50 -0700
commitdaca803e9e333d85213a334f692e30e556e6e146 (patch)
tree2a541b9f29f966ae0a3ed6c5f6764009cfcd71a2 /deps/npm/node_modules/lockfile
parent1fddc1fee84785d296e37337dcb0dc12c13a049f (diff)
downloadandroid-node-v8-daca803e9e333d85213a334f692e30e556e6e146.tar.gz
android-node-v8-daca803e9e333d85213a334f692e30e556e6e146.tar.bz2
android-node-v8-daca803e9e333d85213a334f692e30e556e6e146.zip
npm: Update to 1.4.28
Diffstat (limited to 'deps/npm/node_modules/lockfile')
-rw-r--r--deps/npm/node_modules/lockfile/README.md11
-rw-r--r--deps/npm/node_modules/lockfile/lockfile.js137
-rw-r--r--deps/npm/node_modules/lockfile/package.json15
-rw-r--r--deps/npm/node_modules/lockfile/test/basic.js75
-rw-r--r--deps/npm/node_modules/lockfile/test/retry-time.js62
-rw-r--r--deps/npm/node_modules/lockfile/test/stale-contention.js85
6 files changed, 289 insertions, 96 deletions
diff --git a/deps/npm/node_modules/lockfile/README.md b/deps/npm/node_modules/lockfile/README.md
index 59e149b3f8..b3adccef1a 100644
--- a/deps/npm/node_modules/lockfile/README.md
+++ b/deps/npm/node_modules/lockfile/README.md
@@ -64,9 +64,14 @@ Callback is called with `cb(error, isLocked)`.
### opts.wait
A number of milliseconds to wait for locks to expire before giving up.
-Only used by lockFile.lock. Relies on fs.watch. If the lock is not
-cleared by the time the wait expires, then it returns with the original
-error.
+Only used by lockFile.lock. Poll for `opts.wait` ms. If the lock is
+not cleared by the time the wait expires, then it returns with the
+original error.
+
+### opts.pollPeriod
+
+When using `opts.wait`, this is the period in ms in which it polls to
+check if the lock has expired. Defaults to `100`.
### opts.stale
diff --git a/deps/npm/node_modules/lockfile/lockfile.js b/deps/npm/node_modules/lockfile/lockfile.js
index b82f1f0d65..0c2c6f597a 100644
--- a/deps/npm/node_modules/lockfile/lockfile.js
+++ b/deps/npm/node_modules/lockfile/lockfile.js
@@ -7,9 +7,9 @@ if (process.version.match(/^v0\.[0-6]/)) {
}
var os = require('os')
-var filetime = 'ctime'
+exports.filetime = 'ctime'
if (os.platform() == "win32") {
- filetime = 'mtime'
+ exports.filetime = 'mtime'
}
var debug
@@ -92,7 +92,7 @@ exports.check = function (path, opts, cb) {
})
fs.close(fd, function (er) {
- var age = Date.now() - st[filetime].getTime()
+ var age = Date.now() - st[exports.filetime].getTime()
return cb(er, age <= opts.stale)
})
})
@@ -125,29 +125,39 @@ exports.checkSync = function (path, opts) {
} finally {
fs.closeSync(fd)
}
- var age = Date.now() - st[filetime].getTime()
+ var age = Date.now() - st[exports.filetime].getTime()
return (age <= opts.stale)
}
}
-var req = 0
+var req = 1
exports.lock = function (path, opts, cb) {
if (typeof opts === 'function') cb = opts, opts = {}
opts.req = opts.req || req++
debug('lock', path, opts)
+ opts.start = opts.start || Date.now()
if (typeof opts.retries === 'number' && opts.retries > 0) {
- cb = (function (orig) { return function (er, fd) {
- if (!er) return orig(er, fd)
- var newRT = opts.retries - 1
- opts_ = Object.create(opts, { retries: { value: newRT }})
- debug('lock retry', path, newRT)
- if (opts.retryWait) setTimeout(function() {
- exports.lock(path, opts_, orig)
- }, opts.retryWait)
- else exports.lock(path, opts_, orig)
+ debug('has retries', opts.retries)
+ var retries = opts.retries
+ opts.retries = 0
+ cb = (function (orig) { return function cb (er, fd) {
+ debug('retry-mutated callback')
+ retries -= 1
+ if (!er || retries < 0) return orig(er, fd)
+
+ debug('lock retry', path, opts)
+
+ if (opts.retryWait) setTimeout(retry, opts.retryWait)
+ else retry()
+
+ function retry () {
+ opts.start = Date.now()
+ debug('retrying', opts.start)
+ exports.lock(path, opts, cb)
+ }
}})(cb)
}
@@ -167,30 +177,57 @@ exports.lock = function (path, opts, cb) {
if (er.code !== 'EEXIST') return cb(er)
// someone's got this one. see if it's valid.
- if (opts.stale) fs.stat(path, function (statEr, st) {
- if (statEr) {
- if (statEr.code === 'ENOENT') {
- // expired already!
- var opts_ = Object.create(opts, { stale: { value: false }})
- debug('lock stale enoent retry', path, opts_)
- exports.lock(path, opts_, cb)
- return
- }
- return cb(statEr)
+ if (!opts.stale) return notStale(er, path, opts, cb)
+
+ return maybeStale(er, path, opts, false, cb)
+ })
+}
+
+
+// Staleness checking algorithm
+// 1. acquire $lock, fail
+// 2. stat $lock, find that it is stale
+// 3. acquire $lock.STALE
+// 4. stat $lock, assert that it is still stale
+// 5. unlink $lock
+// 6. link $lock.STALE $lock
+// 7. unlink $lock.STALE
+// On any failure, clean up whatever we've done, and raise the error.
+function maybeStale (originalEr, path, opts, hasStaleLock, cb) {
+ fs.stat(path, function (statEr, st) {
+ if (statEr) {
+ if (statEr.code === 'ENOENT') {
+ // expired already!
+ opts.stale = false
+ debug('lock stale enoent retry', path, opts)
+ exports.lock(path, opts, cb)
+ return
}
+ return cb(statEr)
+ }
- var age = Date.now() - st[filetime].getTime()
- if (age > opts.stale) {
- debug('lock stale', path, opts_)
- exports.unlock(path, function (er) {
- if (er) return cb(er)
- var opts_ = Object.create(opts, { stale: { value: false }})
- debug('lock stale retry', path, opts_)
- exports.lock(path, opts_, cb)
+ var age = Date.now() - st[exports.filetime].getTime()
+ if (age <= opts.stale) return notStale(originalEr, path, opts, cb)
+
+ debug('lock stale', path, opts)
+ if (hasStaleLock) {
+ exports.unlock(path, function (er) {
+ if (er) return cb(er)
+ debug('lock stale retry', path, opts)
+ fs.link(path + '.STALE', path, function (er) {
+ fs.unlink(path + '.STALE', function () {
+ // best effort. if the unlink fails, oh well.
+ cb(er)
+ })
})
- } else notStale(er, path, opts, cb)
- })
- else notStale(er, path, opts, cb)
+ })
+ } else {
+ debug('acquire .STALE file lock', opts)
+ exports.lock(path + '.STALE', opts, function (er) {
+ if (er) return cb(er)
+ maybeStale(originalEr, path, opts, true, cb)
+ })
+ }
})
}
@@ -201,20 +238,22 @@ function notStale (er, path, opts, cb) {
if (typeof opts.wait !== 'number' || opts.wait <= 0)
return cb(er)
- // console.error('wait', path, opts.wait)
- // wait for some ms for the lock to clear
- var start = Date.now()
+ // poll for some ms for the lock to clear
+ var now = Date.now()
+ var start = opts.start || now
var end = start + opts.wait
- function retry () {
- debug('notStale retry', path, opts)
- var now = Date.now()
- var newWait = end - now
- var newOpts = Object.create(opts, { wait: { value: newWait }})
- exports.lock(path, newOpts, cb)
- }
+ if (end <= now)
+ return cb(er)
- var timer = setTimeout(retry, 100)
+ debug('now=%d, wait until %d (delta=%d)', start, end, end-start)
+ var wait = Math.min(end - start, opts.pollPeriod || 100)
+ var timer = setTimeout(poll, wait)
+
+ function poll () {
+ debug('notStale, polling', path, opts)
+ exports.lock(path, opts, cb)
+ }
}
exports.lockSync = function (path, opts) {
@@ -236,7 +275,7 @@ exports.lockSync = function (path, opts) {
if (opts.stale) {
var st = fs.statSync(path)
- var ct = st[filetime].getTime()
+ var ct = st[exports.filetime].getTime()
if (!(ct % 1000) && (opts.stale % 1000)) {
// probably don't have subsecond resolution.
// round up the staleness indicator.
@@ -264,8 +303,8 @@ function retryThrow (path, opts, er) {
if (typeof opts.retries === 'number' && opts.retries > 0) {
var newRT = opts.retries - 1
debug('retryThrow', path, opts, newRT)
- var opts_ = Object.create(opts, { retries: { value: newRT }})
- return exports.lockSync(path, opts_)
+ opts.retries = newRT
+ return exports.lockSync(path, opts)
}
throw er
}
diff --git a/deps/npm/node_modules/lockfile/package.json b/deps/npm/node_modules/lockfile/package.json
index 39d9a857cd..bf4a90dcfb 100644
--- a/deps/npm/node_modules/lockfile/package.json
+++ b/deps/npm/node_modules/lockfile/package.json
@@ -1,6 +1,6 @@
{
"name": "lockfile",
- "version": "0.4.2",
+ "version": "1.0.0",
"main": "lockfile.js",
"directories": {
"test": "test"
@@ -31,15 +31,14 @@
},
"license": "BSD",
"description": "A very polite lock file utility, which endeavors to not litter, and to wait patiently for others.",
- "readme": "# lockfile\n\nA very polite lock file utility, which endeavors to not litter, and to\nwait patiently for others.\n\n## Usage\n\n```javascript\nvar lockFile = require('lockfile')\n\n// opts is optional, and defaults to {}\nlockFile.lock('some-file.lock', opts, function (er) {\n // if the er happens, then it failed to acquire a lock.\n // if there was not an error, then the file was created,\n // and won't be deleted until we unlock it.\n\n // do my stuff, free of interruptions\n // then, some time later, do:\n lockFile.unlock('some-file.lock', function (er) {\n // er means that an error happened, and is probably bad.\n })\n})\n```\n\n## Methods\n\nSync methods return the value/throw the error, others don't. Standard\nnode fs stuff.\n\nAll known locks are removed when the process exits. Of course, it's\npossible for certain types of failures to cause this to fail, but a best\neffort is made to not be a litterbug.\n\n### lockFile.lock(path, [opts], cb)\n\nAcquire a file lock on the specified path\n\n### lockFile.lockSync(path, [opts])\n\nAcquire a file lock on the specified path\n\n### lockFile.unlock(path, cb)\n\nClose and unlink the lockfile.\n\n### lockFile.unlockSync(path)\n\nClose and unlink the lockfile.\n\n### lockFile.check(path, [opts], cb)\n\nCheck if the lockfile is locked and not stale.\n\nReturns boolean.\n\n### lockFile.checkSync(path, [opts], cb)\n\nCheck if the lockfile is locked and not stale.\n\nCallback is called with `cb(error, isLocked)`.\n\n## Options\n\n### opts.wait\n\nA number of milliseconds to wait for locks to expire before giving up.\nOnly used by lockFile.lock. Relies on fs.watch. If the lock is not\ncleared by the time the wait expires, then it returns with the original\nerror.\n\n### opts.stale\n\nA number of milliseconds before locks are considered to have expired.\n\n### opts.retries\n\nUsed by lock and lockSync. Retry `n` number of times before giving up.\n\n### opts.retryWait\n\nUsed by lock. Wait `n` milliseconds before retrying.\n",
+ "readme": "# lockfile\n\nA very polite lock file utility, which endeavors to not litter, and to\nwait patiently for others.\n\n## Usage\n\n```javascript\nvar lockFile = require('lockfile')\n\n// opts is optional, and defaults to {}\nlockFile.lock('some-file.lock', opts, function (er) {\n // if the er happens, then it failed to acquire a lock.\n // if there was not an error, then the file was created,\n // and won't be deleted until we unlock it.\n\n // do my stuff, free of interruptions\n // then, some time later, do:\n lockFile.unlock('some-file.lock', function (er) {\n // er means that an error happened, and is probably bad.\n })\n})\n```\n\n## Methods\n\nSync methods return the value/throw the error, others don't. Standard\nnode fs stuff.\n\nAll known locks are removed when the process exits. Of course, it's\npossible for certain types of failures to cause this to fail, but a best\neffort is made to not be a litterbug.\n\n### lockFile.lock(path, [opts], cb)\n\nAcquire a file lock on the specified path\n\n### lockFile.lockSync(path, [opts])\n\nAcquire a file lock on the specified path\n\n### lockFile.unlock(path, cb)\n\nClose and unlink the lockfile.\n\n### lockFile.unlockSync(path)\n\nClose and unlink the lockfile.\n\n### lockFile.check(path, [opts], cb)\n\nCheck if the lockfile is locked and not stale.\n\nReturns boolean.\n\n### lockFile.checkSync(path, [opts], cb)\n\nCheck if the lockfile is locked and not stale.\n\nCallback is called with `cb(error, isLocked)`.\n\n## Options\n\n### opts.wait\n\nA number of milliseconds to wait for locks to expire before giving up.\nOnly used by lockFile.lock. Poll for `opts.wait` ms. If the lock is\nnot cleared by the time the wait expires, then it returns with the\noriginal error.\n\n### opts.pollPeriod\n\nWhen using `opts.wait`, this is the period in ms in which it polls to\ncheck if the lock has expired. Defaults to `100`.\n\n### opts.stale\n\nA number of milliseconds before locks are considered to have expired.\n\n### opts.retries\n\nUsed by lock and lockSync. Retry `n` number of times before giving up.\n\n### opts.retryWait\n\nUsed by lock. Wait `n` milliseconds before retrying.\n",
"readmeFilename": "README.md",
+ "gitHead": "9590c6f02521eb1bb154ddc3ca9a7e84ce770c45",
"bugs": {
"url": "https://github.com/isaacs/lockfile/issues"
},
- "_id": "lockfile@0.4.2",
- "dist": {
- "shasum": "ab91f5d3745bc005ae4fa34d078910d1f2b9612d"
- },
- "_from": "lockfile@0.4.2",
- "_resolved": "https://registry.npmjs.org/lockfile/-/lockfile-0.4.2.tgz"
+ "homepage": "https://github.com/isaacs/lockfile",
+ "_id": "lockfile@1.0.0",
+ "_shasum": "b3a7609dda6012060083bacb0ab0ecbca58e9203",
+ "_from": "lockfile@latest"
}
diff --git a/deps/npm/node_modules/lockfile/test/basic.js b/deps/npm/node_modules/lockfile/test/basic.js
index 23e8248796..bc66cc3531 100644
--- a/deps/npm/node_modules/lockfile/test/basic.js
+++ b/deps/npm/node_modules/lockfile/test/basic.js
@@ -4,6 +4,11 @@ var path = require('path')
var fs = require('fs')
var touch = require('touch')
+// On Unix systems, it uses ctime by default for staleness checks, since it's
+// the most reliable. However, because this test artificially sets some locks
+// to an earlier time to simulate staleness, we use mtime here.
+lockFile.filetime = 'mtime'
+
test('setup', function (t) {
try { lockFile.unlockSync('basic-lock') } catch (er) {}
try { lockFile.unlockSync('sync-lock') } catch (er) {}
@@ -127,36 +132,35 @@ test('staleness test', function (t) {
lockFile.lock('stale-lock', function (er) {
if (er) throw er
+ // simulate 2s old
+ touch.sync('stale-lock', { time: new Date(Date.now() - 2000) })
+
var opts = { stale: 1 }
- setTimeout(next, 1000)
- function next () {
- lockFile.check('stale-lock', opts, function (er, locked) {
+ lockFile.check('stale-lock', opts, function (er, locked) {
+ if (er) throw er
+ t.notOk(locked)
+ lockFile.lock('stale-lock', opts, function (er) {
if (er) throw er
- t.notOk(locked)
- lockFile.lock('stale-lock', opts, function (er) {
+ lockFile.unlock('stale-lock', function (er) {
if (er) throw er
- lockFile.unlock('stale-lock', function (er) {
- if (er) throw er
- t.end()
- })
+ t.end()
})
})
- }
+ })
})
})
test('staleness sync test', function (t) {
var opts = { stale: 1 }
lockFile.lockSync('stale-lock')
- setTimeout(next, 1000)
- function next () {
- var locked
- locked = lockFile.checkSync('stale-lock', opts)
- t.notOk(locked)
- lockFile.lockSync('stale-lock', opts)
- lockFile.unlockSync('stale-lock')
- t.end()
- }
+ // simulate 2s old
+ touch.sync('stale-lock', { time: new Date(Date.now() - 2000) })
+ var locked
+ locked = lockFile.checkSync('stale-lock', opts)
+ t.notOk(locked)
+ lockFile.lockSync('stale-lock', opts)
+ lockFile.unlockSync('stale-lock')
+ t.end()
})
test('retries', function (t) {
@@ -238,7 +242,7 @@ test('wait and stale together', function (t) {
}, 10)
// try to get another lock. this must fail!
- var opt = { stale: 1000, wait: 2000 }
+ var opt = { stale: 1000, wait: 2000, pollInterval: 1000 }
lockFile.lock('stale-wait-lock', opt, function (er) {
if (!er)
t.fail('got second lock? that unpossible!')
@@ -256,21 +260,20 @@ test('stale windows file tunneling test', function (t) {
// nt file system tunneling feature will make file creation time not updated
var opts = { stale: 1000 }
lockFile.lockSync('stale-windows-lock')
- setTimeout(next, 2000)
- function next () {
- var locked
- lockFile.unlockSync('stale-windows-lock')
- lockFile.lockSync('stale-windows-lock', opts)
- locked = lockFile.checkSync('stale-windows-lock', opts)
- t.ok(locked, "should be locked and not stale")
- lockFile.lock('stale-windows-lock', opts, function (er) {
- if (!er)
- t.fail('got second lock? impossible, windows file tunneling problem!')
- else
- t.pass('second lock failed, windows file tunneling problem fixed')
- t.end()
- })
- }
+ touch.sync('stale-windows-lock', { time: new Date(Date.now() - 3000) })
+
+ var locked
+ lockFile.unlockSync('stale-windows-lock')
+ lockFile.lockSync('stale-windows-lock', opts)
+ locked = lockFile.checkSync('stale-windows-lock', opts)
+ t.ok(locked, "should be locked and not stale")
+ lockFile.lock('stale-windows-lock', opts, function (er) {
+ if (!er)
+ t.fail('got second lock? impossible, windows file tunneling problem!')
+ else
+ t.pass('second lock failed, windows file tunneling problem fixed')
+ t.end()
+ })
})
@@ -283,7 +286,7 @@ test('cleanup', function (t) {
try { lockFile.unlockSync('retry-lock') } catch (er) {}
try { lockFile.unlockSync('contentious-lock') } catch (er) {}
try { lockFile.unlockSync('stale-wait-lock') } catch (er) {}
- try { lockFile.unlockSync('stale-windows-lock') } catch (er) {}
+ try { lockFile.unlockSync('stale-windows-lock') } catch (er) {}
t.end()
})
diff --git a/deps/npm/node_modules/lockfile/test/retry-time.js b/deps/npm/node_modules/lockfile/test/retry-time.js
new file mode 100644
index 0000000000..160bc1376d
--- /dev/null
+++ b/deps/npm/node_modules/lockfile/test/retry-time.js
@@ -0,0 +1,62 @@
+// In these tests, we do the following:
+// try for 200ms (rt=2)
+// wait for 300ms
+// try for 200ms (rt=1)
+// wait for 300ms
+// try for 200ms (rt=0)
+// fail after 1200
+// Actual time will be more like 1220-ish for setTimeout irregularity
+// But it should NOT be as slow as 2000.
+
+var lockFile = require('../')
+var touch = require('touch')
+var test = require('tap').test
+var fs = require('fs')
+
+var RETRYWAIT = 100
+var WAIT = 100
+var RETRIES = 2
+var EXPECTTIME = (RETRYWAIT * RETRIES) + (WAIT * (RETRIES + 1))
+var TOOLONG = EXPECTTIME * 1.1
+
+test('setup', function (t) {
+ touch.sync('file.lock')
+ t.end()
+})
+
+var pollPeriods = [10, 100, 10000]
+pollPeriods.forEach(function (pp) {
+ test('retry+wait, poll=' + pp, function (t) {
+ var ended = false
+ var timer = setTimeout(function() {
+ t.fail('taking too long!')
+ ended = true
+ t.end()
+ }, 2000)
+ timer.unref()
+
+ var start = Date.now()
+ lockFile.lock('file.lock', {
+ wait: WAIT,
+ retries: RETRIES,
+ retryWait: RETRYWAIT,
+ pollPeriod: pp
+ }, function (er) {
+ if (ended) return
+ var time = Date.now() - start
+ console.error('t=%d', time)
+ t.ok(time >= EXPECTTIME, 'should take at least ' + EXPECTTIME)
+ t.ok(time < TOOLONG, 'should take less than ' + TOOLONG)
+ clearTimeout(timer)
+ t.end()
+ })
+ })
+})
+
+test('cleanup', function (t) {
+ fs.unlinkSync('file.lock')
+ t.end()
+ setTimeout(function() {
+ process.exit(1)
+ }, 500).unref()
+})
diff --git a/deps/npm/node_modules/lockfile/test/stale-contention.js b/deps/npm/node_modules/lockfile/test/stale-contention.js
new file mode 100644
index 0000000000..85cbf92e93
--- /dev/null
+++ b/deps/npm/node_modules/lockfile/test/stale-contention.js
@@ -0,0 +1,85 @@
+var fs = require('fs')
+var lockFile = require('../')
+var test = require('tap').test
+var path = require('path')
+var lock = path.resolve(__dirname, 'stale.lock')
+var touch = require('touch')
+var spawn = require('child_process').spawn
+var node = process.execPath
+
+// We're using a lockfile with an artificially old date,
+// so make it use that instead of ctime.
+// Probably you should never do this in production!
+lockFile.filetime = 'mtime'
+
+if (process.argv[2] === 'child') {
+ return child()
+}
+
+function child () {
+ // Make fs.stat take 100ms to return its data
+ // This is important because, in a test scenario where
+ // we're statting the same exact file rapid-fire like this,
+ // it'll end up being cached by the FS, and never trigger
+ // the race condition we're trying to expose.
+ fs.stat = function (stat) { return function () {
+ var args = [].slice.call(arguments)
+ var cb = args.pop()
+ stat.apply(fs, args.concat(function(er, st) {
+ setTimeout(function () {
+ cb(er, st)
+ }, 100)
+ }))
+ }}(fs.stat)
+
+ lockFile.lock(lock, { stale: 100000 }, function (er) {
+ if (er && er.code !== 'EEXIST')
+ throw er
+ else if (er)
+ process.exit(17)
+ else
+ setTimeout(function(){}, 500)
+ })
+}
+
+test('create stale file', function (t) {
+ try { fs.unlinkSync(lock) } catch (er) {}
+ touch.sync(lock, { time: '1979-07-01T19:10:00.000Z' })
+ t.end()
+})
+
+test('contenders', function (t) {
+ var n = 10
+ var fails = 0
+ var wins = 0
+ var args = [ __filename, 'child' ]
+ var opt = { stdio: [0, "pipe", 2] }
+ for (var i = 0; i < n; i++) {
+ spawn(node, args, opt).on('close', then)
+ }
+
+ function then (code) {
+ if (code === 17) {
+ fails ++
+ } else if (code) {
+ t.fail("unexpected failure", code)
+ fails ++
+ } else {
+ wins ++
+ }
+ if (fails + wins === n) {
+ done()
+ }
+ }
+
+ function done () {
+ t.equal(wins, 1, "should have 1 lock winner")
+ t.equal(fails, n - 1, "all others should lose")
+ t.end()
+ }
+})
+
+test('remove stale file', function (t) {
+ try { fs.unlinkSync(lock) } catch (er) {}
+ t.end()
+})