Added a block cache to speed up syncing.

This commit is contained in:
Chris Kleeschulte 2017-10-24 17:46:34 -04:00
parent cb06d8a3cb
commit ad650c383e
No known key found for this signature in database
GPG Key ID: 33195D27EF6BDB7F
3 changed files with 32 additions and 16 deletions

View File

@ -29,6 +29,7 @@ var BlockService = function(options) {
this._blocksInQueue = 0; this._blocksInQueue = 0;
this._recentBlockHashesCount = options.recentBlockHashesCount || 50; // if you expect this chain to reorg deeper than 50, set this this._recentBlockHashesCount = options.recentBlockHashesCount || 50; // if you expect this chain to reorg deeper than 50, set this
this._recentBlockHashes = new LRU(this._recentBlockHashesCount); this._recentBlockHashes = new LRU(this._recentBlockHashesCount);
this._readAheadBlockCount = options.readAheadBlockCount || 2; // this is the number of blocks to direct the p2p service to read aheead
}; };
inherits(BlockService, BaseService); inherits(BlockService, BaseService);
@ -943,13 +944,13 @@ BlockService.prototype._sync = function() {
log.debug('Block Service: querying header service for next block using tip: ' + self._tip.hash); log.debug('Block Service: querying header service for next block using tip: ' + self._tip.hash);
self._header.getNextHash(self._tip, function(err, targetHash, nextHash) { self._header.getEndHash(self._tip, self._readAheadBlockCount, function(err, targetHash, endHash) {
if(err) { if(err) {
return self._handleError(err); return self._handleError(err);
} }
if (!targetHash && !nextHash) { if (!targetHash && !endHash) {
return self.emit('synced'); return self.emit('synced');
} }
@ -974,7 +975,7 @@ BlockService.prototype._sync = function() {
self._p2p.getP2PBlock({ self._p2p.getP2PBlock({
filter: { filter: {
startHash: self._tip.hash, startHash: self._tip.hash,
endHash: nextHash endHash: endHash
}, },
blockHash: targetHash blockHash: targetHash
}, self._syncBlock.bind(self)); }, self._syncBlock.bind(self));

View File

@ -852,12 +852,13 @@ HeaderService.prototype._sync = function() {
}; };
// this gets the header that is +2 places from hash or returns 0 if there is no such HeaderService.prototype.getEndHash = function(tip, blockCount, callback) {
HeaderService.prototype.getNextHash = function(tip, callback) {
assert(blockCount >= 1, 'Header Service: block count to getEndHash must be at least 1.');
var self = this; var self = this;
var numResultsNeeded = Math.min((self._tip.height - tip.height), 2); var numResultsNeeded = Math.min((self._tip.height - tip.height), blockCount + 1);
if (numResultsNeeded === 0 && self._tip.hash === tip.hash) { if (numResultsNeeded === 0 && self._tip.hash === tip.hash) {
return callback(); return callback();
@ -867,14 +868,14 @@ HeaderService.prototype.getNextHash = function(tip, callback) {
return callback(new Error('Header Service: block service is mis-aligned ')); return callback(new Error('Header Service: block service is mis-aligned '));
} }
var startingHeight = tip.height + 1;
var start = self._encoding.encodeHeaderHeightKey(tip.height + 1); var start = self._encoding.encodeHeaderHeightKey(startingHeight);
var end = self._encoding.encodeHeaderHeightKey(tip.height + 3); var end = self._encoding.encodeHeaderHeightKey(startingHeight + blockCount);
var results = []; var results = [];
var criteria = { var criteria = {
gte: start, gte: start,
lt: end lte: end
}; };
var stream = self._db.createReadStream(criteria); var stream = self._db.createReadStream(criteria);
@ -895,19 +896,18 @@ HeaderService.prototype.getNextHash = function(tip, callback) {
return streamErr; return streamErr;
} }
assert(results.length === numResultsNeeded, 'GetNextHash returned incorrect number of results.'); assert(results.length === numResultsNeeded, 'getEndHash returned incorrect number of results.');
if (!results[1]) { var index = numResultsNeeded - 1;
results[1] = 0; var endHash = index <= 0 || !results[index] ? 0 : results[index];
}
if (self._slowMode) { if (self._slowMode) {
return setTimeout(function() { return setTimeout(function() {
callback(null, results[0], results[1]); callback(null, results[0], endHash);
}, self._slowMode); }, self._slowMode);
} }
callback(null, results[0], results[1]); callback(null, results[0], endHash);
}); });

View File

@ -27,6 +27,10 @@ var P2P = function(options) {
this._currentBestHeight = null; this._currentBestHeight = null;
this._latestBits = 0x1d00ffff; this._latestBits = 0x1d00ffff;
this._outgoingTxs = LRU(100); // these are outgoing txs that are awaiting getdata messages this._outgoingTxs = LRU(100); // these are outgoing txs that are awaiting getdata messages
this._blockCache = options.blockCacheCount || LRU({
max: 10,
maxAge: 1000 * 60 * 5}); // keep this modest to avoid memory dumps [hash -> block]
}; };
util.inherits(P2P, BaseService); util.inherits(P2P, BaseService);
@ -53,8 +57,18 @@ P2P.prototype.getNumberOfPeers = function() {
}; };
P2P.prototype.getP2PBlock = function(opts, callback) { P2P.prototype.getP2PBlock = function(opts, callback) {
// opts is { filter: {<start and end hashes>}, blockHash: block hash we want } // opts is { filter: {<start and end hashes>}, blockHash: block hash we want }
var self = this; var self = this;
// do we already have this block in our cache?
var block = self._blockCache.get(opts.blockHash);
if (block) {
return callback(block);
}
var peer = self._getPeer(); var peer = self._getPeer();
var blockFilter = self._setResourceFilter(opts.filter, 'blocks'); var blockFilter = self._setResourceFilter(opts.filter, 'blocks');
@ -291,6 +305,7 @@ P2P.prototype._initPubSub = function() {
}; };
P2P.prototype._onPeerBlock = function(peer, message) { P2P.prototype._onPeerBlock = function(peer, message) {
this._blockCache.set(message.block.rhash(), message.block);
this.emit(message.block.rhash(), message.block); this.emit(message.block.rhash(), message.block);
this._broadcast(this.subscriptions.block, 'p2p/block', message.block); this._broadcast(this.subscriptions.block, 'p2p/block', message.block);
}; };