utils: start using bmutex.

This commit is contained in:
Christopher Jeffrey 2017-11-01 18:42:17 -07:00
parent a79c2b0b1a
commit 4535cd1827
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
14 changed files with 29 additions and 426 deletions

View File

@ -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;
/**

View File

@ -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.

View File

@ -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');

View File

@ -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');

View File

@ -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;

View File

@ -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');

View File

@ -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');

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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');

View File

@ -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();

View File

@ -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",