Author: j16sdiz
Date: 2008-05-23 14:20:09 +0000 (Fri, 23 May 2008)
New Revision: 20059

Added:
   branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
Log:
bloom filter


Added: branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java       
                        (rev 0)
+++ branches/saltedhashstore/freenet/src/freenet/support/BloomFilter.java       
2008-05-23 14:20:09 UTC (rev 20059)
@@ -0,0 +1,116 @@
+/* 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 freenet.crypt.SHA256;
+
+/**
+ * @author sdiz
+ */
+//TODO use ReadWriteLock once we move to java 5
+public class BloomFilter {
+       protected ByteBuffer filter;
+       protected final int length;
+       /** Number of hash functions */
+       protected final int k;
+
+       /**
+        * Constructor
+        * 
+        * @param length
+        *              length in bits
+        */
+       public BloomFilter(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 BloomFilter(File file, int length, int k) throws IOException {
+               if (length % 8 != 0)
+                       throw new IllegalArgumentException();
+
+               RandomAccessFile raf = new RandomAccessFile(file, "rw");
+               raf.setLength(length / 8);
+               filter = raf.getChannel().map(MapMode.READ_WRITE, 0, length / 
8);
+
+               this.length = length;
+               this.k = k;
+       }
+
+       public synchronized void updateFilter(byte[] key) {
+               int[] hashes = getHashes(key);
+               for (int i = 0; i < k; i++)
+                       setBit(hashes[i]);
+               force();
+       }
+
+       public synchronized boolean checkFilter(byte[] key) {
+               int[] hashes = getHashes(key);
+               for (int i = 0; i < k; i++)
+                       if (!getBit(hashes[i]))
+                               return false;
+               return true;
+       }
+
+       private int[] getHashes(byte[] key) {
+               int[] hashes = new int[k];
+
+               MessageDigest md = SHA256.getMessageDigest();
+               try {
+                       for (int i = 0; i < k; i++) {
+                               md.update(key);
+                               md.update((byte) i);
+                               hashes[i] = (int) 
((Fields.bytesToLong(md.digest()) & Long.MAX_VALUE) % length);
+                       }
+               } finally {
+                       SHA256.returnMessageDigest(md);
+               }
+
+               return hashes;
+       }
+
+       protected boolean getBit(int offset) {
+               return (filter.get(offset) & (1 << (offset % 8))) != 0;
+       }
+
+       protected void setBit(int offset) {
+               byte b = filter.get(offset / 8);
+               b |= 1 << (offset % 8);
+               filter.put(offset / 8, b);
+       }
+
+       private void force() {
+               if (filter instanceof MappedByteBuffer) {
+                       ((MappedByteBuffer) filter).force();
+               }
+       }
+
+       protected void finalize() {
+               if (filter != null) {
+                       force();
+               }
+               filter = null;
+       }
+}


Reply via email to