diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index c1f9ef5d..0118a5f4 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -1161,7 +1161,7 @@ Chain.prototype.onDrain = function onDrain() { */ Chain.prototype.isBusy = function isBusy() { - return this.locker.busy; + return this.locker.isBusy(); }; /** diff --git a/lib/net/pool.js b/lib/net/pool.js index 97e02009..40dc44ed 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -1071,7 +1071,7 @@ Pool.prototype.handleBlock = co(function* handleBlock(block, peer) { + ' ts=%s height=%d highest=%d progress=%s' + ' blocks=%d orphans=%d active=%d' + ' queue=%d target=%s peers=%d' - + ' jobs=%d', + + ' pending=%d jobs=%d', util.date(block.ts), this.chain.height, this.chain.bestHeight, @@ -1082,6 +1082,7 @@ Pool.prototype.handleBlock = co(function* handleBlock(block, peer) { peer.queueBlock.size, block.bits, this.peers.size(), + this.chain.locker.pending, this.chain.locker.jobs.length); } diff --git a/lib/utils/locker.js b/lib/utils/locker.js index 72e92c46..c761ee28 100644 --- a/lib/utils/locker.js +++ b/lib/utils/locker.js @@ -29,6 +29,7 @@ function Locker(named) { this.destroyed = false; this.map = {}; + this.pending = 0; this.current = null; this.unlocker = this.unlock.bind(this); @@ -75,6 +76,19 @@ Locker.prototype.hasPending = function hasPending(name) { return this.map[name] > 0; }; +/** + * Test whether the locker is + * busy with a named job. + * @returns {Boolean} + */ + +Locker.prototype.isBusy = function isBusy() { + assert(this.named, 'Must use named jobs.'); + if (this.current) + return true; + return this.pending > 0; +}; + /** * Lock the parent object and all its methods * which use the locker. Begin to queue calls. @@ -110,6 +124,7 @@ Locker.prototype.lock = function lock(arg1, arg2) { if (!this.map[name]) this.map[name] = 0; this.map[name]++; + this.pending++; } return new Promise(function(resolve, reject) { self.jobs.push(new Job(resolve, reject, name)); @@ -136,6 +151,7 @@ Locker.prototype.unlock = function unlock() { this.current = null; if (this.jobs.length === 0) { + assert(this.pending === 0); this.drain(); return; } @@ -148,6 +164,10 @@ Locker.prototype.unlock = function unlock() { assert(this.map[job.name] > 0); if (--this.map[job.name] === 0) delete this.map[job.name]; + this.pending--; + } else { + if (this.pending === 0) + this.drain(); } this.busy = true; @@ -164,10 +184,12 @@ Locker.prototype.unlock = function unlock() { Locker.prototype.wait = function wait() { var self = this; + assert(this.named, 'Must use named jobs.'); + if (this.destroyed) return Promise.reject(new Error('Locker is destroyed.')); - if (!this.busy) { + if (!this.isBusy()) { assert(this.waiting.length === 0); return Promise.resolve(); } @@ -206,11 +228,17 @@ Locker.prototype.destroy = function destroy() { var err = new Error('Locker was destroyed.'); var i, jobs, job; + assert(!this.destroyed, 'Locker is already destroyed.'); + this.destroyed = true; jobs = this.jobs.slice(); + this.busy = false; this.jobs.length = 0; + this.map = {}; + this.pending = 0; + this.current = null; for (i = 0; i < jobs.length; i++) { job = jobs[i]; @@ -265,6 +293,15 @@ MappedLock.prototype.has = function has(name) { return this.busy[name] === true; }; +/** + * Test whether the locker is busy . + * @returns {Boolean} + */ + +MappedLock.prototype.isBusy = function isBusy() { + return this.busy; +}; + /** * Lock the parent object and all its methods * which use the locker with a specified key. @@ -346,9 +383,12 @@ MappedLock.prototype.destroy = function destroy() { var keys = Object.keys(map); var i, j, key, jobs, job; + assert(!this.destroyed, 'Locker is already destroyed.'); + this.destroyed = true; this.jobs = {}; + this.busy = {}; for (i = 0; i < keys.length; i++) { key = keys[i];