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(),
|
type: this.getType(),
|
||||||
subtype: this.getSubtype(),
|
subtype: this.getSubtype(),
|
||||||
address: this.getAddress(),
|
address: this.getAddress(),
|
||||||
value: utils.btc(coin.value),
|
|
||||||
script: this.script,
|
script: this.script,
|
||||||
witness: this.witness,
|
witness: this.witness,
|
||||||
redeem: this.getRedeem(),
|
redeem: this.getRedeem(),
|
||||||
|
|||||||
@ -21,7 +21,9 @@ var assert = utils.assert;
|
|||||||
|
|
||||||
function Locker(parent, add) {
|
function Locker(parent, add) {
|
||||||
if (!(this instanceof Locker))
|
if (!(this instanceof Locker))
|
||||||
return Locker(parent, add);
|
return new Locker(parent, add);
|
||||||
|
|
||||||
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.jobs = [];
|
this.jobs = [];
|
||||||
|
|||||||
@ -50,6 +50,10 @@ function WalletDB(options) {
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
this.network = bcoin.network.get(options.network);
|
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({
|
this.db = bcoin.ldb({
|
||||||
network: this.network,
|
network: this.network,
|
||||||
name: this.options.name || 'wallet',
|
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.
|
* Emit balance events after a tx is saved.
|
||||||
* @private
|
* @private
|
||||||
@ -398,7 +411,14 @@ WalletDB.prototype.hasListener = function hasListener(id, event) {
|
|||||||
|
|
||||||
WalletDB.prototype.get = function get(id, callback) {
|
WalletDB.prototype.get = function get(id, callback) {
|
||||||
var self = this;
|
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)
|
if (!id)
|
||||||
return callback();
|
return callback();
|
||||||
@ -459,13 +479,20 @@ WalletDB.prototype.save = function save(wallet, callback) {
|
|||||||
|
|
||||||
WalletDB.prototype.create = function create(options, callback) {
|
WalletDB.prototype.create = function create(options, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var wallet;
|
var wallet, unlock;
|
||||||
|
|
||||||
if (typeof options === 'function') {
|
if (typeof options === 'function') {
|
||||||
callback = options;
|
callback = options;
|
||||||
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) {
|
this.has(options.id, function(err, exists) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -1049,9 +1076,6 @@ WalletDB.prototype._getKey = function _getKey(id, account, errback, callback) {
|
|||||||
|
|
||||||
WalletDB.prototype.removeBlockSPV = function removeBlockSPV(block, callback) {
|
WalletDB.prototype.removeBlockSPV = function removeBlockSPV(block, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
this.tx.getHeightHashes(block.height, function(err, hashes) {
|
this.tx.getHeightHashes(block.height, function(err, hashes) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -1071,9 +1095,6 @@ WalletDB.prototype.removeBlockSPV = function removeBlockSPV(block, callback) {
|
|||||||
|
|
||||||
WalletDB.prototype.removeBlock = function removeBlock(block, callback) {
|
WalletDB.prototype.removeBlock = function removeBlock(block, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
callback = utils.ensure(callback);
|
|
||||||
|
|
||||||
utils.forEachSerial(block.txs, function(tx, next) {
|
utils.forEachSerial(block.txs, function(tx, next) {
|
||||||
self.tx.unconfirm(tx.hash('hex'), next);
|
self.tx.unconfirm(tx.hash('hex'), next);
|
||||||
}, callback);
|
}, callback);
|
||||||
@ -1438,6 +1459,51 @@ function isAlpha(key) {
|
|||||||
return /^[\u0030-\u007d]+$/.test(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
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user