add a read lock for walletdb.
This commit is contained in:
parent
e3f023142f
commit
59cdc96c9f
@ -442,7 +442,6 @@ Input.prototype.inspect = function inspect() {
|
||||
type: this.getType(),
|
||||
subtype: this.getSubtype(),
|
||||
address: this.getAddress(),
|
||||
value: utils.btc(coin.value),
|
||||
script: this.script,
|
||||
witness: this.witness,
|
||||
redeem: this.getRedeem(),
|
||||
|
||||
@ -21,7 +21,9 @@ var assert = utils.assert;
|
||||
|
||||
function Locker(parent, add) {
|
||||
if (!(this instanceof Locker))
|
||||
return Locker(parent, add);
|
||||
return new Locker(parent, add);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.parent = parent;
|
||||
this.jobs = [];
|
||||
|
||||
@ -50,6 +50,10 @@ function WalletDB(options) {
|
||||
this.options = options;
|
||||
this.network = bcoin.network.get(options.network);
|
||||
|
||||
// We need one read lock for `get` and `create`.
|
||||
// It will hold locks specific to wallet ids.
|
||||
this.readLock = new ReadLock(this);
|
||||
|
||||
this.db = bcoin.ldb({
|
||||
network: this.network,
|
||||
name: this.options.name || 'wallet',
|
||||
@ -156,6 +160,15 @@ WalletDB.prototype._close = function close(callback) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Invoke mutex lock.
|
||||
* @returns {Function} unlock
|
||||
*/
|
||||
|
||||
WalletDB.prototype._lock = function lock(id, func, args, force) {
|
||||
return this.readLock.lock(id, func, args, force);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit balance events after a tx is saved.
|
||||
* @private
|
||||
@ -398,7 +411,14 @@ WalletDB.prototype.hasListener = function hasListener(id, event) {
|
||||
|
||||
WalletDB.prototype.get = function get(id, callback) {
|
||||
var self = this;
|
||||
var watcher, wallet;
|
||||
var unlock, watcher, wallet;
|
||||
|
||||
unlock = this._lock(id, get, [id, callback]);
|
||||
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
if (!id)
|
||||
return callback();
|
||||
@ -459,13 +479,20 @@ WalletDB.prototype.save = function save(wallet, callback) {
|
||||
|
||||
WalletDB.prototype.create = function create(options, callback) {
|
||||
var self = this;
|
||||
var wallet;
|
||||
var wallet, unlock;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
unlock = this._lock(options.id, create, [options, callback]);
|
||||
|
||||
if (!unlock)
|
||||
return;
|
||||
|
||||
callback = utils.wrap(callback, unlock);
|
||||
|
||||
this.has(options.id, function(err, exists) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -1049,9 +1076,6 @@ WalletDB.prototype._getKey = function _getKey(id, account, errback, callback) {
|
||||
|
||||
WalletDB.prototype.removeBlockSPV = function removeBlockSPV(block, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
this.tx.getHeightHashes(block.height, function(err, hashes) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
@ -1071,9 +1095,6 @@ WalletDB.prototype.removeBlockSPV = function removeBlockSPV(block, callback) {
|
||||
|
||||
WalletDB.prototype.removeBlock = function removeBlock(block, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.ensure(callback);
|
||||
|
||||
utils.forEachSerial(block.txs, function(tx, next) {
|
||||
self.tx.unconfirm(tx.hash('hex'), next);
|
||||
}, callback);
|
||||
@ -1438,6 +1459,51 @@ function isAlpha(key) {
|
||||
return /^[\u0030-\u007d]+$/.test(key);
|
||||
}
|
||||
|
||||
function ReadLock(parent) {
|
||||
if (!(this instanceof ReadLock))
|
||||
return new ReadLock(parent);
|
||||
|
||||
this.parent = parent;
|
||||
this.jobs = [];
|
||||
this.busy = {};
|
||||
}
|
||||
|
||||
ReadLock.prototype.lock = function lock(id, func, args, force) {
|
||||
var self = this;
|
||||
var called;
|
||||
|
||||
if (force || !id) {
|
||||
assert(!id || this.busy[id]);
|
||||
return function unlock() {
|
||||
assert(!called);
|
||||
called = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (this.busy[id]) {
|
||||
this.jobs.push([func, args]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.busy[id] = true;
|
||||
|
||||
return function unlock() {
|
||||
var item;
|
||||
|
||||
assert(!called);
|
||||
called = true;
|
||||
|
||||
delete self.busy[id];
|
||||
|
||||
if (self.jobs.length === 0)
|
||||
return;
|
||||
|
||||
item = self.jobs.shift();
|
||||
|
||||
item[0].apply(self.parent, item[1]);
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user