From 30526aaea438b0237430146a6537d3dea81c82a0 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 4 Dec 2016 02:59:20 -0800 Subject: [PATCH] chaindb: coin cache. --- lib/blockchain/chain.js | 3 ++ lib/blockchain/chaindb.js | 69 +++++++++++++++++++++++++-------------- lib/utils/lru.js | 10 +++++- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index f6627610..54e4885a 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -1409,6 +1409,9 @@ Chain.prototype.finish = function finish(block, entry) { block.getSize(), block.txs.length, time); + + this.logger.debug('Coin Cache: size=%dmb, total=%d.', + util.mb(this.db.coinCache.size), this.db.coinCache.total); }; /** diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 30d076fe..4ef37175 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -795,25 +795,29 @@ ChainDB.prototype.getTips = function getTips() { ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { var state = this.state; - var coins; + var raw, coins; if (this.options.spv) return; - coins = this.coinCache.get(hash); + if (this.coinCache.size !== 0) { + coins = yield this.getCoins(hash); - if (coins) - return Coins.parseCoin(coins, hash, index); + if (!coins) + return; - coins = yield this.db.get(layout.c(hash)); + if (state === this.state) + this.coinCache.set(hash, coins); - if (!coins) + return coins.getCoin(index); + } + + raw = yield this.db.get(layout.c(hash)); + + if (!raw) return; - if (state === this.state) - this.coinCache.set(hash, coins); - - return Coins.parseCoin(coins, hash, index); + return Coins.parseCoin(raw, hash, index); }); /** @@ -823,8 +827,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) { */ ChainDB.prototype.getCoins = co(function* getCoins(hash) { - var state = this.state; - var coins; + var raw, coins; if (this.options.spv) return; @@ -832,17 +835,16 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) { coins = this.coinCache.get(hash); if (coins) - return Coins.fromRaw(coins, hash); + return coins; - coins = yield this.db.get(layout.c(hash)); + raw = yield this.db.get(layout.c(hash)); - if (!coins) + if (!raw) return; - if (state === this.state) - this.coinCache.set(hash, coins); + coins = Coins.fromRaw(raw, hash); - return Coins.fromRaw(coins, hash); + return coins; }); /** @@ -1444,8 +1446,10 @@ ChainDB.prototype.saveUpdates = function saveUpdates() { var updates = this.stateCache.updates; var i, update; - if (updates.length > 0) - this.logger.info('Saving %d state cache updates.', updates.length); + if (updates.length === 0) + return; + + this.logger.info('Saving %d state cache updates.', updates.length); for (i = 0; i < updates.length; i++) { update = updates[i]; @@ -1643,7 +1647,7 @@ ChainDB.prototype.removeBlock = co(function* removeBlock(hash) { */ ChainDB.prototype.saveView = function saveView(view) { - var i, coins, raw; + var i, coins; view = view.toArray(); @@ -1653,9 +1657,8 @@ ChainDB.prototype.saveView = function saveView(view) { this.del(layout.c(coins.hash)); this.coinCache.unpush(coins.hash); } else { - raw = coins.toRaw(); - this.put(layout.c(coins.hash), raw); - this.coinCache.push(coins.hash, raw); + this.put(layout.c(coins.hash), coins.toRaw()); + this.coinCache.push(coins.hash, coins); } } }; @@ -2227,7 +2230,23 @@ CacheUpdate.prototype.toRaw = function toRaw() { */ function getSize(value) { - return 80 + value.length; + var half = 4; // Average half of coins + var total = 0; + + total += 128; // coins + total += 88; // coins hash + total += 32; // coins outputs + + // Average compressed coin size + // compressed coin = 112 + // raw = 80 + // pubkeyhash buffer = 26 + total += half * (112 + 80 + 26); + + // Average coin size + total += half * 509; + + return total; } function BlockPair(hash, height) { diff --git a/lib/utils/lru.js b/lib/utils/lru.js index fda80bb7..e553f987 100644 --- a/lib/utils/lru.js +++ b/lib/utils/lru.js @@ -28,6 +28,7 @@ function LRU(maxSize, getSize) { this.map = {}; this.size = 0; + this.total = 0; this.head = null; this.tail = null; this.pending = null; @@ -66,6 +67,7 @@ LRU.prototype._compact = function _compact() { if (this.size <= this.maxSize) break; this.size -= this._getSize(item); + this.total--; delete this.map[item.key]; next = item.next; item.prev = null; @@ -91,6 +93,7 @@ LRU.prototype.reset = function reset() { for (item = this.head; item; item = next) { delete this.map[item.key]; + this.total--; next = item.next; item.prev = null; item.next = null; @@ -133,6 +136,7 @@ LRU.prototype.set = function set(key, value) { this._appendList(item); this.size += this._getSize(item); + this.total++; this._compact(); }; @@ -186,6 +190,7 @@ LRU.prototype.remove = function remove(key) { return false; this.size -= this._getSize(item); + this.total--; delete this.map[key]; @@ -463,7 +468,10 @@ function LRUOp(remove, key, value) { * @param {Number} size */ -function NullCache(size) {} +function NullCache(size) { + this.size = 0; + this.total = 0; +} NullCache.prototype.set = function set(key, value) {}; NullCache.prototype.remove = function remove(key) {};