Author: j16sdiz
Date: 2008-07-28 14:27:21 +0000 (Mon, 28 Jul 2008)
New Revision: 21447
Added:
branches/saltedhashstore/freenet/src/freenet/support/BinaryBloomFilter.java
Modified:
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
Log:
extract abstract class for BloomFilter (perpare for counting filter)
Modified:
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
===================================================================
---
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
2008-07-28 13:57:42 UTC (rev 21446)
+++
branches/saltedhashstore/freenet/src/freenet/store/saltedhash/SaltedHashFreenetStore.java
2008-07-28 14:27:21 UTC (rev 21447)
@@ -36,6 +36,7 @@
import freenet.store.KeyCollisionException;
import freenet.store.StorableBlock;
import freenet.store.StoreCallback;
+import freenet.support.BinaryBloomFilter;
import freenet.support.BloomFilter;
import freenet.support.Fields;
import freenet.support.HTMLNode;
@@ -116,7 +117,7 @@
openStoreFiles(baseDir, name);
File bloomFile = new File(this.baseDir, name + ".bloom");
- bloomFilter = new BloomFilter(bloomFile, bloomFilterSize,
bloomFilterK);
+ bloomFilter = new BinaryBloomFilter(bloomFile, bloomFilterSize,
bloomFilterK);
if (bloomFilter.needRebuild()) {
flags |= FLAG_REBUILD_BLOOM;
checkBloom = false;
Copied:
branches/saltedhashstore/freenet/src/freenet/support/BinaryBloomFilter.java
(from rev 21396,
branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java)
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/support/BinaryBloomFilter.java
(rev 0)
+++ branches/saltedhashstore/freenet/src/freenet/support/BinaryBloomFilter.java
2008-07-28 14:27:21 UTC (rev 21447)
@@ -0,0 +1,207 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel.MapMode;
+import java.security.MessageDigest;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import freenet.crypt.SHA256;
+
+/**
+ * @author sdiz
+ */
+public class BinaryBloomFilter extends BloomFilter {
+ protected ByteBuffer filter;
+ protected final int length;
+ /** Number of hash functions */
+ protected final int k;
+ private ReadWriteLock lock = new ReentrantReadWriteLock();
+ private boolean needRebuild;
+
+ /**
+ * Constructor
+ *
+ * @param length
+ * length in bits
+ */
+ public BinaryBloomFilter(int length, int k) {
+ if (length % 8 != 0)
+ throw new IllegalArgumentException();
+
+ filter = ByteBuffer.allocate(length / 8);
+ this.length = length;
+ this.k = k;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param file
+ * disk file
+ * @param length
+ * length in bits
+ * @throws IOException
+ */
+ public BinaryBloomFilter(File file, int length, int k) throws
IOException {
+ if (length % 8 != 0)
+ throw new IllegalArgumentException();
+ if (!file.exists() || file.length() != length / 8)
+ needRebuild = true;
+
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.setLength(length / 8);
+ filter = raf.getChannel().map(MapMode.READ_WRITE, 0, length /
8).load();
+
+ this.length = length;
+ this.k = k;
+ }
+
+ @Override
+ public void addKey(byte[] key) {
+ int[] hashes = getHashes(key);
+ lock.writeLock().lock();
+ try {
+ for (int i = 0; i < k; i++)
+ setBit(hashes[i]);
+ } finally {
+ lock.writeLock().unlock();
+ }
+
+ if (forkedFilter != null)
+ forkedFilter.addKey(key);
+ }
+
+ @Override
+ public void removeKey(byte[] key) {
+ // ignore
+ }
+
+ @Override
+ public boolean checkFilter(byte[] key) {
+ int[] hashes = getHashes(key);
+ lock.readLock().lock();
+ try {
+ for (int i = 0; i < k; i++)
+ if (!getBit(hashes[i]))
+ return false;
+ } finally {
+ lock.readLock().unlock();
+ }
+ return true;
+ }
+
+ private int[] getHashes(byte[] key) {
+ int[] hashes = new int[k];
+
+ MessageDigest md = SHA256.getMessageDigest();
+ try {
+ byte[] lastDigest = key;
+ ByteBuffer bf = ByteBuffer.wrap(lastDigest);
+
+ for (int i = 0; i < k; i++) {
+ if (bf.remaining() < 4) {
+ lastDigest = md.digest(lastDigest);
+ bf = ByteBuffer.wrap(lastDigest);
+ }
+
+ hashes[i] = (int) ((bf.getInt() &
Long.MAX_VALUE) % length);
+ }
+ } finally {
+ SHA256.returnMessageDigest(md);
+ }
+
+ return hashes;
+ }
+
+ protected boolean getBit(int offset) {
+ return (filter.get(offset / 8) & (1 << (offset % 8))) != 0;
+ }
+
+ protected void setBit(int offset) {
+ byte b = filter.get(offset / 8);
+ b |= 1 << (offset % 8);
+ filter.put(offset / 8, b);
+ }
+
+ @Override
+ public void force() {
+ if (filter instanceof MappedByteBuffer) {
+ ((MappedByteBuffer) filter).force();
+ }
+ }
+
+ protected BinaryBloomFilter forkedFilter;
+
+ /**
+ * Create an empty, in-memory copy of bloom filter. New updates are
written to both filters.
+ * This is written back to disk on #merge()
+ */
+ @Override
+ public void fork(int k) {
+ lock.writeLock().lock();
+ try {
+ forkedFilter = new BinaryBloomFilter(length, k);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void discard() {
+ lock.writeLock().lock();
+ try {
+ forkedFilter = null;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void merge() {
+ lock.writeLock().lock();
+ try {
+ if (forkedFilter == null)
+ return;
+
+ filter.position(0);
+ forkedFilter.filter.position(0);
+
+ filter.put(forkedFilter.filter);
+
+ filter.position(0);
+ forkedFilter = null;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ if (filter != null) {
+ force();
+ }
+ filter = null;
+ forkedFilter = null;
+ }
+
+ @Override
+ public int getK() {
+ return k;
+ }
+
+
+ @Override
+ public boolean needRebuild() {
+ boolean _needRebuild = needRebuild;
+ needRebuild = false;
+ return _needRebuild;
+ }
+}
Modified: branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
2008-07-28 13:57:42 UTC (rev 21446)
+++ branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
2008-07-28 14:27:21 UTC (rev 21447)
@@ -1,216 +1,45 @@
-/* This code is part of Freenet. It is distributed under the GNU General
- * Public License, version 2 (or at your option any later version). See
- * http://www.gnu.org/ for further details of the GPL. */
package freenet.support;
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel.MapMode;
-import java.security.MessageDigest;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import freenet.crypt.SHA256;
-
-/**
- * @author sdiz
- */
-public class BloomFilter {
- protected ByteBuffer filter;
- protected final int length;
- /** Number of hash functions */
- protected final int k;
- private ReadWriteLock lock = new ReentrantReadWriteLock();
- private boolean needRebuild;
-
+public abstract class BloomFilter {
/**
- * Constructor
+ * Calculate optimal K value
*
- * @param length
- * length in bits
+ * @param filterLength
+ * filter length in bits
+ * @param maxKey
+ * @return optimal K
*/
- public BloomFilter(int length, int k) {
- if (length % 8 != 0)
- throw new IllegalArgumentException();
+ public static int optimialK(int filterLength, long maxKey) {
+ long k = Math.round(Math.log(2) * filterLength / maxKey);
- filter = ByteBuffer.allocate(length / 8);
- this.length = length;
- this.k = k;
- }
+ if (k < 1)
+ k = 1;
+ if (k > 32)
+ k = 32;
- /**
- * Constructor
- *
- * @param file
- * disk file
- * @param length
- * length in bits
- * @throws IOException
- */
- public BloomFilter(File file, int length, int k) throws IOException {
- if (length % 8 != 0)
- throw new IllegalArgumentException();
- if (!file.exists() || file.length() != length / 8)
- needRebuild = true;
-
- RandomAccessFile raf = new RandomAccessFile(file, "rw");
- raf.setLength(length / 8);
- filter = raf.getChannel().map(MapMode.READ_WRITE, 0, length /
8).load();
-
- this.length = length;
- this.k = k;
+ return (int) k;
}
- public void addKey(byte[] key) {
- int[] hashes = getHashes(key);
- lock.writeLock().lock();
- try {
- for (int i = 0; i < k; i++)
- setBit(hashes[i]);
- } finally {
- lock.writeLock().unlock();
- }
+ public abstract void addKey(byte[] key);
- if (forkedFilter != null)
- forkedFilter.addKey(key);
- }
+ public abstract void removeKey(byte[] key);
- public void removeKey(byte[] key) {
- // ignore
- }
+ public abstract boolean checkFilter(byte[] key);
- public boolean checkFilter(byte[] key) {
- int[] hashes = getHashes(key);
- lock.readLock().lock();
- try {
- for (int i = 0; i < k; i++)
- if (!getBit(hashes[i]))
- return false;
- } finally {
- lock.readLock().unlock();
- }
- return true;
- }
+ public abstract void force();
- private int[] getHashes(byte[] key) {
- int[] hashes = new int[k];
-
- MessageDigest md = SHA256.getMessageDigest();
- try {
- byte[] lastDigest = key;
- ByteBuffer bf = ByteBuffer.wrap(lastDigest);
-
- for (int i = 0; i < k; i++) {
- if (bf.remaining() < 4) {
- lastDigest = md.digest(lastDigest);
- bf = ByteBuffer.wrap(lastDigest);
- }
-
- hashes[i] = (int) ((bf.getInt() &
Long.MAX_VALUE) % length);
- }
- } finally {
- SHA256.returnMessageDigest(md);
- }
-
- return hashes;
- }
-
- protected boolean getBit(int offset) {
- return (filter.get(offset / 8) & (1 << (offset % 8))) != 0;
- }
-
- protected void setBit(int offset) {
- byte b = filter.get(offset / 8);
- b |= 1 << (offset % 8);
- filter.put(offset / 8, b);
- }
-
- public void force() {
- if (filter instanceof MappedByteBuffer) {
- ((MappedByteBuffer) filter).force();
- }
- }
-
- protected BloomFilter forkedFilter;
-
/**
* Create an empty, in-memory copy of bloom filter. New updates are
written to both filters.
* This is written back to disk on #merge()
*/
- public void fork(int k) {
- lock.writeLock().lock();
- try {
- forkedFilter = new BloomFilter(length, k);
- } finally {
- lock.writeLock().unlock();
- }
- }
+ public abstract void fork(int k);
- public void discard() {
- lock.writeLock().lock();
- try {
- forkedFilter = null;
- } finally {
- lock.writeLock().unlock();
- }
- }
+ public abstract void discard();
- public void merge() {
- lock.writeLock().lock();
- try {
- if (forkedFilter == null)
- return;
+ public abstract void merge();
- filter.position(0);
- forkedFilter.filter.position(0);
+ public abstract int getK();
- filter.put(forkedFilter.filter);
+ public abstract boolean needRebuild();
- filter.position(0);
- forkedFilter = null;
- } finally {
- lock.writeLock().unlock();
- }
- }
-
- @Override
- protected void finalize() {
- if (filter != null) {
- force();
- }
- filter = null;
- forkedFilter = null;
- }
-
- public int getK() {
- return k;
- }
-
- /**
- * Calculate optimal K value
- *
- * @param filterLength
- * filter length in bits
- * @param maxKey
- * @return optimal K
- */
- public static int optimialK(int filterLength, long maxKey) {
- long k = Math.round(Math.log(2) * filterLength / maxKey);
-
- if (k < 1)
- k = 1;
- if (k > 32)
- k = 32;
-
- return (int) k;
- }
-
- public boolean needRebuild() {
- boolean _needRebuild = needRebuild;
- needRebuild = false;
- return _needRebuild;
- }
-}
+}
\ No newline at end of file