From 331daf0f6a9afb15dcec61c151b2f48b2849be12 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 23 Oct 2016 04:54:45 -0700 Subject: [PATCH] lru: better atomicity for chain and walletdb. --- lib/chain/chaindb.js | 44 ++++++++++++++++++++++++++++++------------ lib/wallet/txdb.js | 9 +++++++-- lib/wallet/walletdb.js | 18 ++++++++++++----- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/lib/chain/chaindb.js b/lib/chain/chaindb.js index ec929024..c3d45e1f 100644 --- a/lib/chain/chaindb.js +++ b/lib/chain/chaindb.js @@ -274,8 +274,14 @@ ChainDB.prototype._close = function close() { ChainDB.prototype.start = function start() { assert(!this.current); assert(!this.pending); + this.current = this.db.batch(); this.pending = this.state.clone(); + + this.coinCache.start(); + this.cacheHash.start(); + this.cacheHeight.start(); + return this.current; }; @@ -316,11 +322,19 @@ ChainDB.prototype.batch = function batch() { */ ChainDB.prototype.drop = function drop() { + var batch = this.current; + assert(this.current); assert(this.pending); - this.current.clear(); + this.current = null; this.pending = null; + + this.coinCache.drop(); + this.cacheHash.drop(); + this.cacheHeight.drop(); + + batch.clear(); }; /** @@ -337,11 +351,12 @@ ChainDB.prototype.commit = co(function* commit() { } catch (e) { this.current = null; this.pending = null; + this.coinCache.drop(); + this.cacheHash.drop(); + this.cacheHeight.drop(); throw e; } - this.current = null; - // Overwrite the entire state // with our new best state // only if it is committed. @@ -350,7 +365,12 @@ ChainDB.prototype.commit = co(function* commit() { if (this.pending.committed) this.state = this.pending; + this.current = null; this.pending = null; + + this.coinCache.commit(); + this.cacheHash.commit(); + this.cacheHeight.commit(); }); /** @@ -1167,14 +1187,14 @@ ChainDB.prototype._save = co(function* save(entry, block, view) { this.put(layout.h(hash), U32(entry.height)); this.put(layout.e(hash), entry.toRaw()); - this.cacheHash.set(entry.hash, entry); + this.cacheHash.push(entry.hash, entry); if (!view) { yield this.saveBlock(block); return; } - this.cacheHeight.set(entry.height, entry); + this.cacheHeight.push(entry.height, entry); this.put(layout.n(entry.prevBlock), hash); this.put(layout.H(entry.height), hash); @@ -1218,8 +1238,8 @@ ChainDB.prototype._reconnect = co(function* reconnect(entry, block, view) { this.put(layout.n(entry.prevBlock), hash); this.put(layout.H(entry.height), hash); - this.cacheHash.set(entry.hash, entry); - this.cacheHeight.set(entry.height, entry); + this.cacheHash.push(entry.hash, entry); + this.cacheHeight.push(entry.height, entry); yield this.connectBlock(block, view); @@ -1262,7 +1282,7 @@ ChainDB.prototype._disconnect = co(function* disconnect(entry) { this.del(layout.n(entry.prevBlock)); this.del(layout.H(entry.height)); - this.cacheHeight.remove(entry.height); + this.cacheHeight.unpush(entry.height); block = yield this.getBlock(entry.hash); @@ -1457,10 +1477,10 @@ ChainDB.prototype.connectBlock = co(function* connectBlock(block, view) { raw = coins.toRaw(); if (!raw) { this.del(layout.c(coins.hash)); - this.coinCache.remove(coins.hash); + this.coinCache.unpush(coins.hash); } else { this.put(layout.c(coins.hash), raw); - this.coinCache.set(coins.hash, raw); + this.coinCache.push(coins.hash, raw); } } @@ -1553,10 +1573,10 @@ ChainDB.prototype.disconnectBlock = co(function* disconnectBlock(block) { raw = coins.toRaw(); if (!raw) { this.del(layout.c(coins.hash)); - this.coinCache.remove(coins.hash); + this.coinCache.unpush(coins.hash); } else { this.put(layout.c(coins.hash), raw); - this.coinCache.set(coins.hash, raw); + this.coinCache.push(coins.hash, raw); } } diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index 6e8bf329..5a378510 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -262,6 +262,7 @@ TXDB.prototype.open = co(function* open() { TXDB.prototype.start = function start() { this.pending = this.state.clone(); + this.coinCache.start(); return this.wallet.start(); }; @@ -273,6 +274,7 @@ TXDB.prototype.start = function start() { TXDB.prototype.drop = function drop() { this.pending = null; this.events.length = 0; + this.coinCache.drop(); return this.wallet.drop(); }; @@ -284,6 +286,7 @@ TXDB.prototype.drop = function drop() { TXDB.prototype.clear = function clear() { this.pending = this.state.clone(); this.events.length = 0; + this.coinCache.clear(); return this.wallet.clear(); }; @@ -300,6 +303,7 @@ TXDB.prototype.commit = co(function* commit() { } catch (e) { this.pending = null; this.events.length = 0; + this.coinCache.drop(); throw e; } @@ -319,6 +323,7 @@ TXDB.prototype.commit = co(function* commit() { this.pending = null; this.events.length = 0; + this.coinCache.commit(); }); /** @@ -677,7 +682,7 @@ TXDB.prototype.saveCredit = function saveCredit(credit, path) { var raw = credit.toRaw(); this.put(layout.c(prevout.hash, prevout.index), raw); this.put(layout.C(path.account, prevout.hash, prevout.index), DUMMY); - this.coinCache.set(key, raw); + this.coinCache.push(key, raw); }; /** @@ -691,7 +696,7 @@ TXDB.prototype.removeCredit = function removeCredit(credit, path) { var key = prevout.hash + prevout.index; this.del(layout.c(prevout.hash, prevout.index)); this.del(layout.C(path.account, prevout.hash, prevout.index)); - this.coinCache.remove(key); + this.coinCache.unpush(key); }; /** diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 75447446..ed118676 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -369,6 +369,8 @@ WalletDB.prototype.getHeight = co(function* getHeight() { WalletDB.prototype.start = function start(wallet) { assert(!wallet.current, 'Batch already started.'); wallet.current = this.db.batch(); + wallet.accountCache.start(); + wallet.pathCache.start(); return wallet.current; }; @@ -381,6 +383,8 @@ WalletDB.prototype.start = function start(wallet) { WalletDB.prototype.drop = function drop(wallet) { var batch = this.batch(wallet); wallet.current = null; + wallet.accountCache.drop(); + wallet.pathCache.drop(); batch.clear(); }; @@ -392,6 +396,8 @@ WalletDB.prototype.drop = function drop(wallet) { WalletDB.prototype.clear = function clear(wallet) { var batch = this.batch(wallet); + wallet.accountCache.clear(); + wallet.pathCache.clear(); batch.clear(); }; @@ -414,11 +420,13 @@ WalletDB.prototype.batch = function batch(wallet) { * @returns {Promise} */ -WalletDB.prototype.commit = function commit(wallet) { +WalletDB.prototype.commit = co(function* commit(wallet) { var batch = wallet.current; wallet.current = null; - return batch.write(); -}; + yield batch.write(); + wallet.accountCache.commit(); + wallet.pathCache.commit(); +}); /** * Load the bloom filter into memory. @@ -862,7 +870,7 @@ WalletDB.prototype.saveAccount = function saveAccount(account) { batch.put(layout.a(wid, index), account.toRaw()); batch.put(layout.i(wid, name), U32(index)); - wallet.accountCache.set(index, account); + wallet.accountCache.push(index, account); }; /** @@ -947,7 +955,7 @@ WalletDB.prototype.savePath = co(function* savePath(wallet, path) { return; this.pathMapCache.set(hash, wids); - wallet.pathCache.set(hash, path); + wallet.pathCache.push(hash, path); batch.put(layout.p(hash), serializeWallets(wids)); batch.put(layout.P(wid, hash), path.toRaw());