diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index f895074b..533b9cc8 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -9,20 +9,20 @@ const assert = require('assert'); const path = require('path'); +const Logger = require('blgr'); +const {Lock} = require('bmutex'); +const encoding = require('bbuf/lib/encoding'); const AsyncEmitter = require('../utils/asyncemitter'); const Network = require('../protocol/network'); -const Logger = require('blgr'); const ChainDB = require('./chaindb'); const common = require('./common'); const consensus = require('../protocol/consensus'); const util = require('../utils/util'); -const Lock = require('../utils/lock'); const LRU = require('../utils/lru'); const ChainEntry = require('./chainentry'); const CoinView = require('../coins/coinview'); const Script = require('../script/script'); const {VerifyError} = require('../protocol/errors'); -const encoding = require('bbuf/lib/encoding'); const thresholdStates = common.thresholdStates; /** diff --git a/lib/mining/cpuminer.js b/lib/mining/cpuminer.js index 5a4cebb6..a44c8c3d 100644 --- a/lib/mining/cpuminer.js +++ b/lib/mining/cpuminer.js @@ -9,10 +9,10 @@ const assert = require('assert'); const EventEmitter = require('events'); +const {Lock} = require('bmutex'); +const encoding = require('bbuf/lib/encoding'); const util = require('../utils/util'); const mine = require('./mine'); -const Lock = require('../utils/lock'); -const encoding = require('bbuf/lib/encoding'); /** * CPU miner. diff --git a/lib/net/peer.js b/lib/net/peer.js index ae475074..60eb0770 100644 --- a/lib/net/peer.js +++ b/lib/net/peer.js @@ -9,6 +9,7 @@ const assert = require('assert'); const EventEmitter = require('events'); +const {Lock} = require('bmutex'); const {format} = require('util'); const tcp = require('btcp'); const Logger = require('blgr'); @@ -20,7 +21,6 @@ const packets = require('./packets'); const consensus = require('../protocol/consensus'); const common = require('./common'); const InvItem = require('../primitives/invitem'); -const Lock = require('../utils/lock'); const BIP151 = require('./bip151'); const BIP150 = require('./bip150'); const BIP152 = require('./bip152'); diff --git a/lib/net/pool.js b/lib/net/pool.js index 66564863..8315404a 100644 --- a/lib/net/pool.js +++ b/lib/net/pool.js @@ -9,6 +9,7 @@ const assert = require('assert'); const EventEmitter = require('events'); +const {Lock} = require('bmutex'); const IP = require('binet'); const dns = require('bdns'); const tcp = require('btcp'); @@ -25,7 +26,6 @@ const Address = require('../primitives/address'); const BIP150 = require('./bip150'); const BIP151 = require('./bip151'); const BIP152 = require('./bip152'); -const Lock = require('../utils/lock'); const Network = require('../protocol/network'); const Peer = require('./peer'); const external = require('./external'); diff --git a/lib/node/rpc.js b/lib/node/rpc.js index 5423d5a5..0aecc18c 100644 --- a/lib/node/rpc.js +++ b/lib/node/rpc.js @@ -8,12 +8,16 @@ const assert = require('assert'); const bweb = require('bweb'); -const util = require('../utils/util'); +const {Lock} = require('bmutex'); +const IP = require('binet'); const hash160 = require('bcrypto/lib/hash160'); const hash256 = require('bcrypto/lib/hash256'); const ccmp = require('bcrypto/lib/ccmp'); -const common = require('../blockchain/common'); const secp256k1 = require('bcrypto/lib/secp256k1'); +const encoding = require('bbuf/lib/encoding'); +const Validator = require('bval/lib/validator'); +const util = require('../utils/util'); +const common = require('../blockchain/common'); const Amount = require('../btc/amount'); const NetAddress = require('../primitives/netaddress'); const Script = require('../script/script'); @@ -28,12 +32,8 @@ const Network = require('../protocol/network'); const Outpoint = require('../primitives/outpoint'); const Output = require('../primitives/output'); const TX = require('../primitives/tx'); -const IP = require('binet'); -const encoding = require('bbuf/lib/encoding'); const consensus = require('../protocol/consensus'); -const Validator = require('bval/lib/validator'); const pkg = require('../pkg'); -const Lock = require('../utils/lock'); const RPCBase = bweb.RPC; const RPCError = bweb.RPCError; diff --git a/lib/node/spvnode.js b/lib/node/spvnode.js index 8da0137e..613ae2cb 100644 --- a/lib/node/spvnode.js +++ b/lib/node/spvnode.js @@ -8,7 +8,7 @@ 'use strict'; const assert = require('assert'); -const Lock = require('../utils/lock'); +const {Lock} = require('bmutex'); const Chain = require('../blockchain/chain'); const Pool = require('../net/pool'); const Node = require('./node'); diff --git a/lib/utils/index.js b/lib/utils/index.js index 4f8aa8fd..39d63224 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -15,7 +15,5 @@ exports.binary = require('./binary'); exports.fixed = require('./fixed'); exports.Heap = require('./heap'); exports.List = require('./list'); -exports.Lock = require('./lock'); exports.LRU = require('./lru'); -exports.MappedLock = require('./mappedlock'); exports.util = require('./util'); diff --git a/lib/utils/lock.js b/lib/utils/lock.js deleted file mode 100644 index 688604aa..00000000 --- a/lib/utils/lock.js +++ /dev/null @@ -1,215 +0,0 @@ -/*! - * lock.js - lock and queue for bcoin - * Copyright (c) 2014-2015, Fedor Indutny (MIT License) - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'use strict'; - -const assert = require('assert'); - -/** - * Mutex Lock - * @alias module:utils.Lock - */ - -class Lock { - /** - * Create a lock. - * @constructor - * @param {Boolean?} named - Whether to - * maintain a map of queued jobs by job name. - */ - - constructor(named = false) { - this.named = named === true; - - this.jobs = []; - this.busy = false; - this.destroyed = false; - - this.map = new Map(); - this.current = null; - - this.unlocker = this.unlock.bind(this); - } - - /** - * Create a closure scoped lock. - * @param {Boolean?} named - * @returns {Function} Lock method. - */ - - static create(named) { - const lock = new Lock(named); - return function _lock(arg1, arg2) { - return lock.lock(arg1, arg2); - }; - } - - /** - * Test whether the lock has a pending - * job or a job in progress (by name). - * @param {String} name - * @returns {Boolean} - */ - - has(name) { - assert(this.named, 'Must use named jobs.'); - - if (this.current === name) - return true; - - return this.pending(name); - } - - /** - * Test whether the lock has - * a pending job by name. - * @param {String} name - * @returns {Boolean} - */ - - pending(name) { - assert(this.named, 'Must use named jobs.'); - - const count = this.map.get(name); - - if (count == null) - return false; - - return count > 0; - } - - /** - * Lock the parent object and all its methods - * which use the lock. Begin to queue calls. - * @param {String?} name - Job name. - * @param {Boolean?} force - Bypass the lock. - * @returns {Promise} - Returns {Function}, must be - * called once the method finishes executing in order - * to resolve the queue. - */ - - lock(arg1, arg2) { - let name, force; - - if (this.named) { - name = arg1 || null; - force = arg2 || false; - } else { - name = null; - force = arg1 || false; - } - - if (this.destroyed) - return Promise.reject(new Error('Lock is destroyed.')); - - if (force) { - assert(this.busy); - return Promise.resolve(nop); - } - - if (this.busy) { - if (name) { - const count = this.map.get(name) || 0; - this.map.set(name, count + 1); - } - return new Promise((resolve, reject) => { - this.jobs.push(new Job(resolve, reject, name)); - }); - } - - this.busy = true; - this.current = name; - - return Promise.resolve(this.unlocker); - } - - /** - * The actual unlock callback. - * @private - */ - - unlock() { - assert(this.destroyed || this.busy); - - this.busy = false; - this.current = null; - - if (this.jobs.length === 0) - return; - - assert(!this.destroyed); - - const job = this.jobs.shift(); - - if (job.name) { - let count = this.map.get(job.name); - assert(count > 0); - if (--count === 0) - this.map.delete(job.name); - else - this.map.set(job.name, count); - } - - this.busy = true; - this.current = job.name; - - job.resolve(this.unlocker); - } - - /** - * Destroy the lock. Purge all pending calls. - */ - - destroy() { - assert(!this.destroyed, 'Lock is already destroyed.'); - - this.destroyed = true; - - const jobs = this.jobs; - - this.busy = false; - this.jobs = []; - this.map.clear(); - this.current = null; - - for (const job of jobs) - job.reject(new Error('Lock was destroyed.')); - } -} - -/** - * Lock Job - * @ignore - */ - -class Job { - /** - * Create a lock job. - * @constructor - * @param {Function} resolve - * @param {Function} reject - * @param {String?} name - */ - - constructor(resolve, reject, name) { - this.resolve = resolve; - this.reject = reject; - this.name = name || null; - } -} - -/* - * Helpers - */ - -function nop() {} - -/* - * Expose - */ - -module.exports = Lock; diff --git a/lib/utils/mappedlock.js b/lib/utils/mappedlock.js deleted file mode 100644 index d3673af3..00000000 --- a/lib/utils/mappedlock.js +++ /dev/null @@ -1,181 +0,0 @@ -/*! - * mappedlock.js - lock and queue for bcoin - * Copyright (c) 2014-2015, Fedor Indutny (MIT License) - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'use strict'; - -const assert = require('assert'); - -/** - * Mapped Lock - * @alias module:utils.MappedLock - */ - -class MappedLock { - /** - * Create a mapped lock. - * @constructor - */ - - constructor() { - this.jobs = new Map(); - this.busy = new Set(); - this.destroyed = false; - } - - /** - * Create a closure scoped lock. - * @returns {Function} Lock method. - */ - - static create() { - const lock = new MappedLock(); - return function _lock(key, force) { - return lock.lock(key, force); - }; - } - - /** - * Test whether the lock has a pending - * job or a job in progress (by name). - * @param {String} name - * @returns {Boolean} - */ - - has(name) { - return this.busy.has(name); - } - - /** - * Test whether the lock has - * a pending job by name. - * @param {String} name - * @returns {Boolean} - */ - - pending(name) { - return this.jobs.has(name); - } - - /** - * Lock the parent object and all its methods - * which use the lock with a specified key. - * Begin to queue calls. - * @param {String|Number} key - * @param {Boolean} [force=false] - Force a call. - * @returns {Promise} - Returns {Function}, must be - * called once the method finishes executing in order - * to resolve the queue. - */ - - lock(key, force = false) { - if (this.destroyed) - return Promise.reject(new Error('Lock is destroyed.')); - - if (key == null) - return Promise.resolve(nop); - - if (force) { - assert(this.busy.has(key)); - return Promise.resolve(nop); - } - - if (this.busy.has(key)) { - return new Promise((resolve, reject) => { - if (!this.jobs.has(key)) - this.jobs.set(key, []); - this.jobs.get(key).push(new Job(resolve, reject)); - }); - } - - this.busy.add(key); - - return Promise.resolve(this.unlock(key)); - } - - /** - * Create an unlock callback. - * @private - * @param {String} key - * @returns {Function} Unlocker. - */ - - unlock(key) { - const self = this; - return function unlocker() { - const jobs = self.jobs.get(key); - - assert(self.destroyed || self.busy.has(key)); - self.busy.delete(key); - - if (!jobs) - return; - - assert(!self.destroyed); - - const job = jobs.shift(); - assert(job); - - if (jobs.length === 0) - self.jobs.delete(key); - - self.busy.add(key); - - job.resolve(unlocker); - }; - } - - /** - * Destroy the lock. Purge all pending calls. - */ - - destroy() { - assert(!this.destroyed, 'Lock is already destroyed.'); - - const map = this.jobs; - - this.destroyed = true; - - this.jobs = new Map(); - this.busy = new Map(); - - for (const jobs of map.values()) { - for (const job of jobs) - job.reject(new Error('Lock was destroyed.')); - } - } -} - -/** - * Lock Job - * @ignore - */ - -class Job { - /** - * Create a lock job. - * @constructor - * @param {Function} resolve - * @param {Function} reject - */ - - constructor(resolve, reject) { - this.resolve = resolve; - this.reject = reject; - } -} - -/* - * Helpers - */ - -function nop() {} - -/* - * Expose - */ - -module.exports = MappedLock; diff --git a/lib/wallet/masterkey.js b/lib/wallet/masterkey.js index 2a72bf5f..7fed5965 100644 --- a/lib/wallet/masterkey.js +++ b/lib/wallet/masterkey.js @@ -7,9 +7,7 @@ 'use strict'; const assert = require('assert'); -const Network = require('../protocol/network'); -const util = require('../utils/util'); -const Lock = require('../utils/lock'); +const {Lock} = require('bmutex'); const random = require('bcrypto/lib/random'); const cleanse = require('bcrypto/lib/cleanse'); const aes = require('bcrypto/lib/aes'); @@ -19,6 +17,8 @@ const scrypt = require('bcrypto/lib/scrypt'); const BufferReader = require('bbuf/lib/reader'); const StaticWriter = require('bbuf/lib/staticwriter'); const encoding = require('bbuf/lib/encoding'); +const Network = require('../protocol/network'); +const util = require('../utils/util'); const HD = require('../hd/hd'); const Mnemonic = HD.Mnemonic; diff --git a/lib/wallet/rpc.js b/lib/wallet/rpc.js index 3bbba6fd..e05e76a1 100644 --- a/lib/wallet/rpc.js +++ b/lib/wallet/rpc.js @@ -7,11 +7,14 @@ 'use strict'; const assert = require('assert'); -const bweb = require('bweb'); -const fs = require('bfile'); const {format} = require('util'); -const util = require('../utils/util'); +const bweb = require('bweb'); +const {Lock} = require('bmutex'); +const fs = require('bfile'); const hash256 = require('bcrypto/lib/hash256'); +const encoding = require('bbuf/lib/encoding'); +const Validator = require('bval/lib/validator'); +const util = require('../utils/util'); const Amount = require('../btc/amount'); const Script = require('../script/script'); const Address = require('../primitives/address'); @@ -21,10 +24,7 @@ const MTX = require('../primitives/mtx'); const Outpoint = require('../primitives/outpoint'); const Output = require('../primitives/output'); const TX = require('../primitives/tx'); -const encoding = require('bbuf/lib/encoding'); const pkg = require('../pkg'); -const Validator = require('bval/lib/validator'); -const Lock = require('../utils/lock'); const common = require('./common'); const RPCBase = bweb.RPC; const RPCError = bweb.RPCError; diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 6606935e..edec74cd 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -9,15 +9,15 @@ const assert = require('assert'); const EventEmitter = require('events'); -const Network = require('../protocol/network'); +const {Lock} = require('bmutex'); const encoding = require('bbuf/lib/encoding'); -const Lock = require('../utils/lock'); const hash160 = require('bcrypto/lib/hash160'); const hash256 = require('bcrypto/lib/hash256'); const cleanse = require('bcrypto/lib/cleanse'); const BufferReader = require('bbuf/lib/reader'); const StaticWriter = require('bbuf/lib/staticwriter'); const base58 = require('bstr/lib/base58'); +const Network = require('../protocol/network'); const TXDB = require('./txdb'); const Path = require('./path'); const common = require('./common'); diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 96e4d797..3a6e9480 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -10,6 +10,8 @@ const assert = require('assert'); const path = require('path'); const EventEmitter = require('events'); +const Lock = require('bmutex/lib/lock'); +const MapLock = require('bmutex/lib/maplock'); const BDB = require('bdb'); const Logger = require('blgr'); const encoding = require('bbuf/lib/encoding'); @@ -17,8 +19,6 @@ const ccmp = require('bcrypto/lib/ccmp'); const aes = require('bcrypto/lib/aes'); const BloomFilter = require('bfilter/lib/bloom'); const StaticWriter = require('bbuf/lib/staticwriter'); -const Lock = require('../utils/lock'); -const MappedLock = require('../utils/mappedlock'); const Network = require('../protocol/network'); const Path = require('./path'); const common = require('./common'); @@ -65,7 +65,7 @@ function WalletDB(options) { this.rescanning = false; // Wallet read lock. - this.readLock = new MappedLock(); + this.readLock = new MapLock(); // Wallet write lock (creation and rename). this.writeLock = new Lock(); diff --git a/package.json b/package.json index 4d875a90..830a429d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "bfile": "^0.0.1", "bfilter": "^0.0.1", "binet": "^0.0.1", + "bmutex": "^0.0.1", "breq": "^0.0.1", "bsock": "^0.0.1", "bstr": "^0.0.1",