Author: j16sdiz
Date: 2008-05-11 10:24:22 +0000 (Sun, 11 May 2008)
New Revision: 19891

Modified:
   
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
Log:
Quadratic Probing (datastore resize disabled)


Modified: 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
===================================================================
--- 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java  
    2008-05-11 09:08:40 UTC (rev 19890)
+++ 
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java  
    2008-05-11 10:24:22 UTC (rev 19891)
@@ -126,22 +126,29 @@

        private Entry probeEntry0(byte[] routingKey, long probeStoreSize) 
throws IOException {
                Entry entry;
-               long offset = getOffsetFromPlainKey(routingKey, probeStoreSize);
+               long[] offset = getOffsetFromPlainKey(routingKey, 
probeStoreSize);

-               if (!lockEntry(offset)) {
-                       Logger.error(this, "can't lock entry: " + offset);
-                       return null;
+               for (int i = 0; i < offset.length; i++) {
+                       if (logDEBUG)
+                               Logger.debug(this, "probing for i=" + i + ", 
offset=" + offset[i]);
+                       
+                       if (!lockEntry(offset[i])) {
+                               Logger.error(this, "can't lock entry: " + 
offset[i]);
+                               continue;
+                       }
+                       try {
+                               entry = readEntry(offset[i], routingKey);
+                       } catch (EOFException e) {
+                               // may occur on resize, silent it a bit
+                               Logger.error(this, "EOFException on 
probeEntry", e);
+                               return null;
+                       } finally {
+                               unlockEntry(offset[i]);
+                       }
+                       if (entry != null)
+                               return entry;
                }
-               try {
-                       entry = readEntry(offset, routingKey);
-               } catch (EOFException e) {
-                       // may occur on resize, silent it a bit
-                       Logger.error(this, "EOFException on probeEntry", e);
-                       return null;
-               } finally {
-                       unlockEntry(offset);
-               }
-               return entry;
+               return null;
        }

        public void put(StorableBlock block, byte[] routingKey, byte[] fullKey, 
byte[] data, byte[] header,
@@ -163,16 +170,39 @@
                }

                Entry entry = new Entry(routingKey, header, data);
-               if (!lockEntry(entry.getOffset())) {
+               long[] offset = entry.getOffset();
+
+               for (int i = 0; i < offset.length; i++) {
+                       if (!lockEntry(offset[i])) {
+                               Logger.error(this, "can't lock entry: " + 
offset[i]);
+                               return;
+                       }
+                       try {
+                               if (isFree(offset[i], entry)) {
+                                       if (logDEBUG)
+                                               Logger.debug(this, "probing, 
write to i=" + i + ", offset=" + offset[i]);
+                                       writeEntry(entry, offset[i]);
+                                       incWrites();
+                                       return;
+                               }
+                       } finally {
+                               unlockEntry(offset[i]);
+                       }
+               }
+
+               // no free blocks?
+               int i = random.nextInt(offset.length);
+               if (!lockEntry(offset[i])) {
                        Logger.error(this, "can't lock entry: " + 
entry.getOffset());
-                       incMisses();
                        return;
                }
                try {
-                       writeEntry(entry);
+                       if (logDEBUG)
+                               Logger.debug(this, "collision, write to i=" + i 
+ ", offset=" + offset[i]);
+                       writeEntry(entry, offset[i]);
                        incWrites();
                } finally {
-                       unlockEntry(entry.getOffset());
+                       unlockEntry(offset[i]);
                }
        }

@@ -235,6 +265,7 @@
                private byte[] data;

                private boolean isEncrypted;
+               public long curOffset;

                /**
                 * Create a new entry
@@ -352,7 +383,7 @@
                        return block;
                }

-               public long getOffset() {
+               public long[] getOffset() {
                        if (digestedRoutingKey != null)
                                return 
getOffsetFromDigestedKey(digestedRoutingKey, storeSize);
                        else
@@ -382,7 +413,8 @@
                                }
                        } else {
                                // we do not know the plain key, let's check 
the digest
-                               if (!Arrays.equals(this.digestedRoutingKey, 
getDigestedRoutingKey(routingKey)))
+                               if (!Arrays.equals(this.digestedRoutingKey, 
SaltedHashFreenetStore.this
+                                       .getDigestedRoutingKey(routingKey)))
                                        return false;
                        }

@@ -411,7 +443,7 @@
                        header = cipher.blockEncipher(header, 0, header.length);
                        data = cipher.blockEncipher(data, 0, data.length);

-                       digestedRoutingKey = 
getDigestedRoutingKey(plainRoutingKey);
+                       getDigestedRoutingKey();
                        isEncrypted = true;
                }

@@ -438,6 +470,13 @@
                public boolean isFree() {
                        return (flag & ENTRY_FLAG_OCCUPIED) == 0;
                }
+
+               public byte[] getDigestedRoutingKey() {
+                       if (digestedRoutingKey != null)
+                               return digestedRoutingKey;
+                       else
+                               return 
SaltedHashFreenetStore.this.getDigestedRoutingKey(this.plainRoutingKey);
+               }
        }

        /**
@@ -504,6 +543,7 @@
                                return null;
                }

+               entry.curOffset = offset;
                return entry;
        }

@@ -516,17 +556,12 @@
         * <li>update the entry with latest store size</li>
         * </ul>
         */
-       private void writeEntry(Entry entry) throws IOException {
+       private void writeEntry(Entry entry, long offset) throws IOException {
                entry.encrypt();

-               long offset = entry.getOffset();
                int split = (int) (offset % FILE_SPLIT);
                long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;

-               if (logMINOR && !isFree(offset)) {
-                       Logger.minor(this, "collision, overwritting an entry");
-               }
-
                ByteBuffer bf = entry.toByteBuffer();
                do {
                        int status = storeFC[split].write(bf, rawOffset + 
bf.position());
@@ -554,16 +589,18 @@
        }

        /**
-        * Check if a block is free
+        * Check if a block is free or occupied by a specific routing key
         * 
         * @param offset
+        * @param entry
+        *            entry, maybe <code>null</code>
         * @throws IOException
         */
-       private boolean isFree(long offset) throws IOException {
+       private boolean isFree(long offset, Entry entry) throws IOException {
                int split = (int) (offset % FILE_SPLIT);
                long rawOffset = (offset / FILE_SPLIT) * entryTotalLength;

-               ByteBuffer bf = ByteBuffer.allocate(0x30 + 0x08);
+               ByteBuffer bf = ByteBuffer.allocate((int) ENTRY_HEADER_LENGTH);

                do {
                        int status = storeFC[split].read(bf, rawOffset + 
bf.position());
@@ -571,7 +608,17 @@
                                throw new EOFException();
                } while (bf.hasRemaining());

-               return (bf.getLong(0x30) & ENTRY_FLAG_OCCUPIED) == 0;
+               if ((bf.getLong(0x30) & ENTRY_FLAG_OCCUPIED) == 0) {
+                       // free
+                       return true;
+               } else if (entry != null) {
+                       // check digested key
+                       byte[] digestedRoutingKey = new byte[0x20];
+                       bf.position(0);
+                       bf.get(digestedRoutingKey);
+                       return Arrays.equals(digestedRoutingKey, 
entry.getDigestedRoutingKey());
+               }
+               return false;
        }

        private void flushAndClose() {
@@ -689,7 +736,7 @@
                        while (!shutdown) {
                                synchronized (cleanerLock) {
                                        if (prevStoreSize != 0)
-                                               resizeStore();
+                                               ; //resizeStore();
                                        else
                                                estimateStoreSize();

@@ -728,9 +775,11 @@
                 */
                private int resizeRound;

-               /**
+               /*-
+                * 
+                *
                 * Move old entries to new location and resize store
-                */
+                *
                private void resizeStore() {
                        ++resizeRound;
                        Logger.normal(this, "Starting datastore resize (round " 
+ resizeRound + ")");
@@ -773,7 +822,7 @@

                /**
                 * Scan all entries and try to move them
-                */
+                *
                private void moveOldEntry0(boolean queueItem) {
                        newEntries = 0;
                        oldEntries = 0;
@@ -827,7 +876,7 @@
                                                long newOffset = 
entry.getOffset();

                                                if (newOffset == offset) { // 
lucky! 
-                                                       writeEntry(entry); // 
write back entry storeSize
+                                                       lockAndWrite(entry); // 
write back entry storeSize
                                                        resolvedEntries++;
                                                        continue;
                                                }
@@ -840,7 +889,7 @@

                                                        if 
(newOffsetEntry.isFree()) {
                                                                // the new 
offset is freeeeeeee..
-                                                               
writeEntry(entry);
+                                                               
lockAndWrite(entry);
                                                                
freeOffset(offset);
                                                                
resolvedEntries++;
                                                        } else if 
(newOffsetEntry.getStoreSize() == storeSize) {
@@ -862,7 +911,7 @@
                                                                        
oldEntries++; // newOffset wasn't counted count it
                                                                }

-                                                               
writeEntry(entry);
+                                                               
lockAndWrite(entry);
                                                                
freeOffset(offset);
                                                                
resolvedEntries++;
                                                        }
@@ -896,7 +945,7 @@
                 * Put back oldItems with best effort
                 * 
                 * @throws IOException
-                */
+                *
                private void putBackOldItems(FileChannel oldItems) throws 
IOException {
                        while (true) {
                                Entry entry = readOldItem(oldItems);
@@ -914,7 +963,7 @@
                                        if (isFree(newOffset)) {
                                                if (logDEBUG)
                                                        Logger.debug(this, "Put 
back old item: " + HexUtil.bytesToHex(entry.digestedRoutingKey));
-                                               writeEntry(entry);
+                                               lockAndWrite(entry);
                                                done = true;
                                        } else {
                                                if (logDEBUG)
@@ -948,6 +997,7 @@
                        bf.flip();
                        return new Entry(bf);
                }
+               */

                /**
                 * Samples to take on key count estimation
@@ -972,7 +1022,7 @@
                        long occupied = 0;
                        while (sampled < numSample) {
                                try {
-                                       if (!isFree(samplePos)) {
+                                       if (!isFree(samplePos, null)) {
                                                occupied++;
                                        }
                                        sampled++;
@@ -1173,7 +1223,7 @@
         * @param storeSize
         * @return
         */
-       public long getOffsetFromPlainKey(byte[] plainKey, long storeSize) {
+       public long[] getOffsetFromPlainKey(byte[] plainKey, long storeSize) {
                return 
getOffsetFromDigestedKey(getDigestedRoutingKey(plainKey), storeSize);
        }

@@ -1184,18 +1234,27 @@
         * @param storeSize
         * @return
         */
-       public long getOffsetFromDigestedKey(byte[] digestedKey, long 
storeSize) {
-               long keyValue = (((long) (digestedKey[0]) << 0) + //
-                       (((long) digestedKey[1]) << 8) + //
-                       (((long) digestedKey[3]) << 16) + //
-                       (((long) digestedKey[4]) << 24) + //
-                       (((long) digestedKey[5]) << 32) + //
-                       (((long) digestedKey[6]) << 40) + //
-                       (((long) digestedKey[7]) << 48))
-                       & Long.MAX_VALUE;
-               return keyValue % storeSize;
+       public long[] getOffsetFromDigestedKey(byte[] digestedKey, long 
storeSize) {
+               long keyValue = keyToLong(digestedKey);
+               // h + 141 i^2 + 13 i
+               return new long[] {//
+               ((keyValue + 141 * (0 * 0) + 13 * 0) & Long.MAX_VALUE) % 
storeSize, // i = 0
+                       ((keyValue + 141 * (1 * 1) + 13 * 1) & Long.MAX_VALUE) 
% storeSize, // i = 1
+                       ((keyValue + 141 * (2 * 2) + 13 * 2) & Long.MAX_VALUE) 
% storeSize, // i = 2
+                       ((keyValue + 141 * (3 * 3) + 13 * 3) & Long.MAX_VALUE) 
% storeSize, // i = 3
+               };
        }

+       private long keyToLong(byte[] key) {
+               return (((long) (key[0]) << 0) + //
+                       (((long) key[1]) << 8) + //
+                       (((long) key[3]) << 16) + //
+                       (((long) key[4]) << 24) + //
+                       (((long) key[5]) << 32) + //
+                       (((long) key[6]) << 40) + //
+               (((long) key[7]) << 48));
+       }
+
        // ------------- Statistics (a.k.a. lies)
        private final Object statLock = new Object();
        private long hits;


Reply via email to