bloom: cleanup instantiation.

This commit is contained in:
Christopher Jeffrey 2017-01-11 12:10:04 -08:00
parent dbaae30700
commit 65ab296d2e
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 138 additions and 42 deletions

View File

@ -2199,7 +2199,7 @@ function FilterLoadPacket(filter) {
Packet.call(this);
this.filter = filter || new Bloom(0, 0, 0, -1);
this.filter = filter || new Bloom();
}
util.inherits(FilterLoadPacket, Packet);

View File

@ -14,6 +14,7 @@ var StaticWriter = require('./staticwriter');
var encoding = require('./encoding');
var sum32 = murmur3.sum32;
var mul32 = murmur3.mul32;
var DUMMY = new Buffer(0);
/*
* Constants
@ -29,6 +30,7 @@ var LN2 = 0.6931471805599453094172321214581765680755001343602552;
* @param {Number|Bufer} size - Filter size in bits, or filter itself.
* @param {Number} n - Number of hash functions.
* @param {Number} tweak - Seed value.
* @param {Number|String} - Update type.
* @property {Buffer} filter
* @property {Number} size
* @property {Number} n
@ -40,27 +42,14 @@ function Bloom(size, n, tweak, update) {
if (!(this instanceof Bloom))
return new Bloom(size, n, tweak, update);
if (Buffer.isBuffer(size)) {
this.filter = size;
this.size = this.filter.length * 8;
} else {
this.size = size - (size % 8);
this.filter = new Buffer(this.size / 8);
this.reset();
}
this.filter = DUMMY;
this.size = 0;
this.n = 0;
this.tweak = 0;
this.update = Bloom.flags.NONE;
if (tweak == null || tweak === -1)
tweak = (Math.random() * 0x100000000) >>> 0;
if (update == null || update === -1)
update = Bloom.flags.NONE;
if (typeof update === 'string')
update = Bloom.flags[update.toUpperCase()];
this.n = n;
this.tweak = tweak;
this.update = update;
if (size != null)
this.fromOptions(size, n, tweak, update);
}
/**
@ -117,6 +106,68 @@ Bloom.MAX_BLOOM_FILTER_SIZE = 36000;
Bloom.MAX_HASH_FUNCS = 50;
/**
* Inject properties from options.
* @private
* @param {Number|Bufer} size - Filter size in bits, or filter itself.
* @param {Number} n - Number of hash functions.
* @param {Number} tweak - Seed value.
* @param {Number|String} - Update type.
* @returns {Bloom}
*/
Bloom.prototype.fromOptions = function fromOptions(size, n, tweak, update) {
var filter;
if (Buffer.isBuffer(size)) {
filter = size;
size = filter.length * 8;
} else {
assert(typeof size === 'number', '`size` must be a number.');
assert(size > 0, '`size` must be greater than zero.');
size -= size % 8;
filter = new Buffer(size / 8);
filter.fill(0);
}
if (tweak == null || tweak === -1)
tweak = (Math.random() * 0x100000000) >>> 0;
if (update == null || update === -1)
update = Bloom.flags.NONE;
if (typeof update === 'string') {
update = Bloom.flags[update.toUpperCase()];
assert(update != null, 'Unknown update flag.');
}
assert(size > 0, '`size` must be greater than zero.');
assert(n > 0, '`n` must be greater than zero.');
assert(typeof tweak === 'number', '`tweak` must be a number.');
assert(Bloom.flagsByVal[update], 'Unknown update flag.');
this.filter = filter;
this.size = size;
this.n = n;
this.tweak = tweak;
this.update = update;
return this;
};
/**
* Instantiate bloom filter from options.
* @param {Number|Bufer} size - Filter size in bits, or filter itself.
* @param {Number} n - Number of hash functions.
* @param {Number} tweak - Seed value.
* @param {Number|String} - Update type.
* @returns {Bloom}
*/
Bloom.fromOptions = function fromOptions(size, n, tweak, update) {
return new Bloom().fromOptions(size, n, tweak, update);
};
/**
* Perform the mumur3 hash on data.
* @param {Buffer} val
@ -203,11 +254,11 @@ Bloom.prototype.added = function added(val, enc) {
/**
* Create a filter from a false positive rate.
* @param {Number} items - Expeected number of items.
* @param {Number} items - Expected number of items.
* @param {Number} rate - False positive rate (0.0-1.0).
* @param {Number|String} update
* @example
* bcoin.bloom.fromRate(800000, 0.01, 'none');
* Bloom.fromRate(800000, 0.0001, 'none');
* @returns {Boolean}
*/
@ -219,7 +270,7 @@ Bloom.fromRate = function fromRate(items, rate, update) {
if (update !== -1)
size = Math.min(size, Bloom.MAX_BLOOM_FILTER_SIZE * 8);
n = ((size / items * LN2) | 0) || 1;
n = Math.max(1, size / items * LN2);
if (update !== -1)
n = Math.min(n, Bloom.MAX_HASH_FUNCS);
@ -285,7 +336,7 @@ Bloom.prototype.fromReader = function fromReader(br) {
this.n = br.readU32();
this.tweak = br.readU32();
this.update = br.readU8();
assert(Bloom.flagsByVal[this.update] != null, 'Bad filter flag.');
assert(Bloom.flagsByVal[this.update] != null, 'Unknown update flag.');
return this;
};
@ -332,31 +383,76 @@ Bloom.fromRaw = function fromRaw(data, enc) {
*/
function RollingFilter(items, rate) {
var logRate, max;
if (!(this instanceof RollingFilter))
return new RollingFilter(items, rate);
logRate = Math.log(rate);
this.entries = 0;
this.generation = 1;
this.n = 0;
this.limit = 0;
this.size = 0;
this.items = 0;
this.tweak = 0;
this.filter = DUMMY;
this.n = Math.max(1, Math.min(Math.round(logRate / Math.log(0.5)), 50));
this.limit = (items + 1) / 2 | 0;
max = this.limit * 3;
this.size = -1 * this.n * max / Math.log(1.0 - Math.exp(logRate / this.n));
this.size = Math.ceil(this.size);
this.items = ((this.size + 63) / 64 | 0) << 1;
this.tweak = (Math.random() * 0x100000000) >>> 0;
this.filter = new Buffer(this.items * 8);
this.filter.fill(0);
if (items != null)
this.fromRate(items, rate);
}
/**
* Inject properties from items and FPR.
* @private
* @param {Number} items - Expected number of items.
* @param {Number} rate - False positive rate (0.0-1.0).
* @returns {RollingFilter}
*/
RollingFilter.prototype.fromRate = function fromRate(items, rate) {
var logRate, max, n, limit, size, items, tweak, filter;
assert(typeof items === 'number', '`items` must be a number.');
assert(items > 0, '`items` must be greater than zero.');
assert(typeof rate === 'number', '`rate` must be a number.');
assert(rate >= 0, '`rate` must be positive.');
logRate = Math.log(rate);
n = Math.max(1, Math.min(Math.round(logRate / Math.log(0.5)), 50));
limit = (items + 1) / 2 | 0;
max = limit * 3;
size = -1 * n * max / Math.log(1.0 - Math.exp(logRate / n));
size = Math.ceil(size);
items = ((size + 63) / 64 | 0) << 1;
items >>>= 0;
tweak = (Math.random() * 0x100000000) >>> 0;
filter = new Buffer(items * 8);
filter.fill(0);
this.n = n;
this.limit = limit;
this.size = size;
this.items = items;
this.tweak = tweak;
this.filter = filter;
return this;
};
/**
* Instantiate rolling filter from items and FPR.
* @param {Number} items - Expected number of items.
* @param {Number} rate - False positive rate (0.0-1.0).
* @returns {RollingFilter}
*/
RollingFilter.fromRate = function fromRate(items, rate) {
return new RollingFilter().fromRate(items, rate);
};
/**
* Perform the mumur3 hash on data.
* @param {Buffer} val