mempool: handle trimming differently.

This commit is contained in:
Christopher Jeffrey 2017-03-05 10:27:12 -08:00
parent 47c1955e2c
commit c2b8dc37c7
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 56 additions and 25 deletions

View File

@ -366,39 +366,43 @@ Mempool.prototype._reset = co(function* reset() {
Mempool.prototype.limitSize = function limitSize(added) { Mempool.prototype.limitSize = function limitSize(added) {
var maxSize = this.options.maxSize; var maxSize = this.options.maxSize;
var threshold = maxSize - (maxSize / 10);
var expiryTime = this.options.expiryTime; var expiryTime = this.options.expiryTime;
var now = util.now(); var now = util.now();
var trimmed = false; var i, queue, hashes, hash, entry, start;
var i, queue, entry, keys, hash, start;
if (this.size <= maxSize) if (this.size <= maxSize)
return trimmed; return false;
queue = new Heap(cmpRate); queue = new Heap(cmpRate);
keys = this.getSnapshot(); hashes = this.getSnapshot();
start = util.hrtime(); start = util.hrtime();
for (i = 0; i < keys.length; i++) { for (i = 0; i < hashes.length; i++) {
hash = keys[i]; hash = hashes[i];
entry = this.getEntry(hash); entry = this.getEntry(hash);
if (!entry) if (!entry)
continue; continue;
if (this.hasDepends(entry.tx))
continue;
if (now < entry.ts + expiryTime) { if (now < entry.ts + expiryTime) {
queue.insert(entry); queue.insert(entry);
continue; continue;
} }
if (entry === added) this.logger.debug(
trimmed = true; 'Removing package %s from mempool (too old).',
entry.txid());
this.evictEntry(entry); this.evictEntry(entry);
} }
if (this.size <= maxSize) if (this.size <= threshold)
return trimmed; return !this.hasEntry(added);
this.logger.debug( this.logger.debug(
'(bench) Heap mempool traversal: %d.', '(bench) Heap mempool traversal: %d.',
@ -406,19 +410,23 @@ Mempool.prototype.limitSize = function limitSize(added) {
start = util.hrtime(); start = util.hrtime();
this.logger.debug(
'(bench) Heap mempool queue size: %d.',
queue.size());
while (queue.size() > 0) { while (queue.size() > 0) {
entry = queue.shift(); entry = queue.shift();
hash = entry.hash('hex'); hash = entry.hash('hex');
if (!this.hasEntry(hash)) assert(this.hasEntry(hash));
continue;
this.logger.debug(
'Removing package %s from mempool (low fee).',
entry.txid());
this.evictEntry(entry); this.evictEntry(entry);
if (entry === added) if (this.size <= threshold)
trimmed = true;
if (this.size <= maxSize - (maxSize / 10))
break; break;
} }
@ -426,7 +434,7 @@ Mempool.prototype.limitSize = function limitSize(added) {
'(bench) Heap mempool map removal: %d.', '(bench) Heap mempool map removal: %d.',
util.hrtime(start)); util.hrtime(start));
return trimmed; return !this.hasEntry(added);
}; };
/** /**
@ -877,7 +885,7 @@ Mempool.prototype.insertTX = co(function* insertTX(tx) {
yield this.addEntry(entry, view); yield this.addEntry(entry, view);
// Trim size if we're too big. // Trim size if we're too big.
if (this.limitSize(entry)) { if (this.limitSize(hash)) {
throw new VerifyError(tx, throw new VerifyError(tx,
'insufficientfee', 'insufficientfee',
'mempool full', 'mempool full',
@ -1132,19 +1140,14 @@ Mempool.prototype.removeEntry = function removeEntry(entry) {
}; };
/** /**
* Evict a transaction from the mempool. * Remove a transaction from the mempool.
* Recursively remove its spenders. * Recursively remove its spenders.
* @param {MempoolEntry} entry * @param {MempoolEntry} entry
*/ */
Mempool.prototype.evictEntry = function evictEntry(entry) { Mempool.prototype.evictEntry = function evictEntry(entry) {
var tx = entry.tx;
this.logger.debug('Evicting %s from the mempool.', tx.txid());
this.removeSpenders(entry); this.removeSpenders(entry);
this.updateAncestors(entry, removeFee); this.updateAncestors(entry, removeFee);
this.removeEntry(entry); this.removeEntry(entry);
}; };
@ -1388,6 +1391,25 @@ Mempool.prototype.getDepends = function getDepends(tx) {
return depends; return depends;
}; };
/**
* Test whether a transaction has dependencies.
* @param {TX} tx
* @returns {Boolean}
*/
Mempool.prototype.hasDepends = function hasDepends(tx) {
var i, input, hash;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
hash = input.prevout.hash;
if (this.hasEntry(hash))
return true;
}
return false;
};
/** /**
* Return the full balance of all unspents in the mempool * Return the full balance of all unspents in the mempool
* (not very useful in practice, only used for testing). * (not very useful in practice, only used for testing).
@ -1900,7 +1922,7 @@ Mempool.prototype.removeDoubleSpends = function removeDoubleSpends(tx) {
this.logger.debug( this.logger.debug(
'Removing double spender from mempool: %s.', 'Removing double spender from mempool: %s.',
spent.tx.rhash()); spent.txid());
this.evictEntry(spent); this.evictEntry(spent);

View File

@ -142,6 +142,15 @@ MempoolEntry.prototype.hash = function hash(enc) {
return this.tx.hash(enc); return this.tx.hash(enc);
}; };
/**
* Calculate reverse transaction hash.
* @returns {Hash}
*/
MempoolEntry.prototype.txid = function txid() {
return this.tx.txid();
};
/** /**
* Calculate priority, taking into account * Calculate priority, taking into account
* the entry height delta, modified size, * the entry height delta, modified size,