/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.util;
import static java.lang.Math.log;
import static java.lang.Math.round;
public class BloomFilter
{
public void add(int hashValue)
{
for (int h = 0; h < hashFunctions; h++) {
int position = position(hashValue, h);
filter[position >> SHIFT] |= 1L << (position & MASK);
}
}
public boolean maybePresent(int hashValue)
{
for (int h = 0; h < hashFunctions; h++) {
int position = position(hashValue, h);
if ((filter[position >> SHIFT] & (1L << (position & MASK))) == 0) {
return false;
}
}
return true;
}
public BloomFilter(long maxKeys, double errorRate)
{
// Formulae from http://en.wikipedia.org/wiki/Bloom_filter.
double ln2 = log(2);
filterSize = (int) -round(maxKeys * log(errorRate) / (ln2 * ln2));
hashFunctions = (int) round(((double) filterSize / maxKeys) * ln2);
filter = new long[1 + filterSize / BITS];
}
// For use by this class
private int position(int x, int h)
{
int hash = x * PRIMES[h];
if (hash < 0) {
hash = hash == Integer.MIN_VALUE ? 0 : -hash;
}
return hash % filterSize;
}
// Class state
private static final int BITS = 64;
private static final int SHIFT = 6; // log2(BITS)
private static final int MASK = (1 << SHIFT) - 1;
// First 100 primes > 1e9
private static int[] PRIMES = {
1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
1000000093, 1000000097, 1000000103, 1000000123, 1000000181,
1000000207, 1000000223, 1000000241, 1000000271, 1000000289,
1000000297, 1000000321, 1000000349, 1000000363, 1000000403,
1000000409, 1000000411, 1000000427, 1000000433, 1000000439,
1000000447, 1000000453, 1000000459, 1000000483, 1000000513,
1000000531, 1000000579, 1000000607, 1000000613, 1000000637,
1000000663, 1000000711, 1000000753, 1000000787, 1000000801,
1000000829, 1000000861, 1000000871, 1000000891, 1000000901,
1000000919, 1000000931, 1000000933, 1000000993, 1000001011,
1000001021, 1000001053, 1000001087, 1000001099, 1000001137,
1000001161, 1000001203, 1000001213, 1000001237, 1000001263,
1000001269, 1000001273, 1000001279, 1000001311, 1000001329,
1000001333, 1000001351, 1000001371, 1000001393, 1000001413,
1000001447, 1000001449, 1000001491, 1000001501, 1000001531,
1000001537, 1000001539, 1000001581, 1000001617, 1000001621,
1000001633, 1000001647, 1000001663, 1000001677, 1000001699,
1000001759, 1000001773, 1000001789, 1000001791, 1000001801,
1000001803, 1000001819, 1000001857, 1000001887, 1000001917,
1000001927, 1000001957, 1000001963, 1000001969, 1000002043,
};
// Object state
private final int filterSize;
private final int hashFunctions;
private final long[] filter;
}