lru cache

This commit is contained in:
Christopher Jeffrey 2016-02-15 18:19:59 -08:00
parent 8f897c256b
commit 2ae8c17398
4 changed files with 187 additions and 2 deletions

View File

@ -43,6 +43,7 @@ bcoin.ecdsa.signature = require('elliptic/lib/elliptic/ec/signature');
bcoin.ecdsa.keypair = require('elliptic/lib/elliptic/ec/key');
bcoin.utils = require('./bcoin/utils');
bcoin.lru = require('./bcoin/lru');
bcoin.protocol = require('./bcoin/protocol');
bcoin.bloom = require('./bcoin/bloom');
bcoin.script = require('./bcoin/script');

View File

@ -38,6 +38,8 @@ function BlockDB(options) {
this.parser = new bcoin.protocol.parser();
this.data = new BlockData();
this.unspentCache = new bcoin.lru(32 * 1024 * 1024);
this.txCache = new bcoin.lru(32 * 1024 * 1024);
this.index = new levelup(this.file, {
keyEncoding: 'ascii',
@ -414,6 +416,15 @@ BlockDB.prototype._getCoinsByAddress = function _getCoinsByAddress(address, call
var index = +parts[1];
var record = self.parseOffset(data.value);
pending++;
if (self.unspentCache.has(hash + '/' + index)) {
coins.push(self.unspentCache.get(hash + '/' + index));
pending--;
if (done) {
if (!pending)
return callback(null, coins);
}
return;
}
self.data.getAsync(record.size, record.offset, function(err, data) {
var coin;
@ -435,6 +446,7 @@ BlockDB.prototype._getCoinsByAddress = function _getCoinsByAddress(address, call
value: data.value,
spent: false
});
self.unspentCache.set(hash + '/' + index, coin);
coins.push(coin);
}
@ -543,14 +555,24 @@ BlockDB.prototype._getTXByAddress = function _getTXByAddress(address, callback)
});
stream.on('data', function(data) {
// var parts = data.key.split('/').slice(3);
// var hash = parts[0];
var parts = data.key.split('/').slice(3);
var hash = parts[0];
// Could store block hash in key
// var blockHash = parts[1];
var record = self.parseOffset(data.value);
pending++;
if (self.txCache.has(hash)) {
coins.push(self.txCache.get(hash));
pending--;
if (done) {
if (!pending)
return callback(null, coins);
}
return;
}
self.data.getAsync(record.size, record.offset, function(err, data) {
var tx, entry;
@ -568,6 +590,7 @@ BlockDB.prototype._getTXByAddress = function _getTXByAddress(address, callback)
tx.height = record.height;
tx.ts = entry.ts;
tx.block = entry.hash;
self.txCache.set(hash, tx);
txs.push(tx);
}

View File

@ -74,6 +74,10 @@ Coin.prototype.__defineGetter__('chain', function() {
return this._chain || bcoin.chain.global;
});
Coin.prototype.getSize = function getSize() {
return 4 + 4 + 8 + bcoin.script.getSize(this.script) + 32 + 4 + 1;
};
Coin.prototype.getConfirmations = function getConfirmations(height) {
var top;

157
lib/bcoin/lru.js Normal file
View File

@ -0,0 +1,157 @@
/**
* lru.js - LRU cache for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* https://github.com/indutny/bcoin
*/
function LRU(maxSize) {
if (!(this instanceof LRU))
return new LRU(maxSize);
this.data = {};
this.size = 0;
this.maxSize = maxSize;
this.head = null;
this.tail = null;
}
LRU.prototype._getSize = function _getSize(value) {
if (value == null)
return 1;
if (typeof value === 'number')
return 4;
if (value._raw)
return value._raw.length;
if (value.getSize)
return value.getSize();
if (typeof value.length === 'number')
return value.length;
return 1;
};
LRU.prototype._compact = function _compact() {
var item;
if (this.size < this.maxSize)
return;
for (item = this.head; item; item = item.next) {
if (this.size <= this.maxSize / 2 | 0)
break;
this.size -= this._getSize(item.value);
delete this.data[item.key];
}
if (!item) {
this.head = null;
this.tail = null;
return;
}
this.head = item;
item.prev = null;
};
LRU.prototype.set = function set(key, value) {
var item = this.data[key];
if (item) {
this.size -= this._getSize(item.value);
this.size += this._getSize(value);
item.value = value;
this.get(key);
this._compact();
return;
}
item = { key: key, value: value };
this.data[key] = item;
if (!this.head) {
this.head = item;
this.tail = item;
} else {
this.tail.next = item;
item.prev = this.tail;
this.tail = item;
}
this.size += this._getSize(value);
this._compact();
};
LRU.prototype.get = function get(key) {
var item = this.data[key];
var prev, next, tail;
if (!item)
return;
if (this.tail === item)
return item.value;
prev = item.prev;
next = item.next;
tail = this.tail;
this.tail = item;
if (this.head === item)
this.head = next || item;
if (prev)
prev.next = next;
if (next)
next.prev = prev;
item.next = null;
item.prev = tail;
return item.value;
};
LRU.prototype.has = function get(key) {
return this.data[key] != null;
};
LRU.prototype.remove = function remove(key) {
var item = this.data[key];
var prev, next;
if (!item)
return false;
this.size -= this._getSize(item.value);
delete this.data[key];
prev = item.prev;
next = item.next;
if (prev)
prev.next = next;
if (next)
next.prev = prev;
if (this.tail === item)
this.tail = prev || null;
if (this.head === item)
this.head = next || null;
return true;
};
/**
* Expose
*/
module.exports = LRU;