package freenet.support; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.util.Random; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.spaceroots.mantissa.random.MersenneTwister; public abstract class BloomFilter { protected ByteBuffer filter; /** Number of hash functions */ protected final int k; protected final int length; protected ReadWriteLock lock = new ReentrantReadWriteLock(); public static BloomFilter createFilter(int length, int k, boolean counting) { if (length == 0) return new NullBloomFilter(length, k); if (counting) return new CountingBloomFilter(length, k); else return new BinaryBloomFilter(length, k); } public static BloomFilter createFilter(File file, int length, int k, boolean counting) throws IOException { if (length == 0) return new NullBloomFilter(length, k); if (counting) return new CountingBloomFilter(file, length, k); else return new BinaryBloomFilter(file, length, k); } protected BloomFilter(int length, int k) { if (length % 8 != 0) length -= length % 8; this.length = length; this.k = k; } //-- Core public void addKey(byte[] key) { Random hashes = getHashes(key); lock.writeLock().lock(); try { for (int i = 0; i < k; i++) setBit(hashes.nextInt(length)); } finally { lock.writeLock().unlock(); } if (forkedFilter != null) forkedFilter.addKey(key); } // add to the forked filter only public void addKeyForked(byte[] key) { if (forkedFilter != null) forkedFilter.addKey(key); } public boolean checkFilter(byte[] key) { Random hashes = getHashes(key); lock.readLock().lock(); try { for (int i = 0; i < k; i++) if (!getBit(hashes.nextInt(length))) return false; } finally { lock.readLock().unlock(); } return true; } public void removeKey(byte[] key) { Random hashes = getHashes(key); lock.writeLock().lock(); try { for (int i = 0; i < k; i++) unsetBit(hashes.nextInt(length)); } finally { lock.writeLock().unlock(); } if (forkedFilter != null) forkedFilter.removeKey(key); } //-- Bits and Hashes protected abstract boolean getBit(int offset); protected abstract void setBit(int offset); protected abstract void unsetBit(int offset); // Wierd impl's should override public void unsetAll() { int x = filter.limit(); for(int i=0;i 64) k = 64; if (k < 1) k = 1; return (int) k; } public int getK() { return k; } protected boolean needRebuild; public boolean needRebuild() { boolean _needRebuild = needRebuild; needRebuild = false; return _needRebuild; } public void force() { if (filter instanceof MappedByteBuffer) { ((MappedByteBuffer) filter).force(); } } public void close() { if (filter != null) { force(); } filter = null; forkedFilter = null; } @Override protected void finalize() { close(); } }