[freenet-cvs] r19897 - branches/saltedhashstore/freenet/src/…

Top Page
Delete this message
Reply to this message
Author: devl
Date:  
To: cvs
Subject: [freenet-cvs] r19897 - branches/saltedhashstore/freenet/src/freenet/store
Author: j16sdiz
Date: 2008-05-11 17:05:03 +0000 (Sun, 11 May 2008)
New Revision: 19897

Modified:
branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
Log:
Fix datastore resize


Modified: branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java
===================================================================
--- branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java    2008-05-11 17:04:42 UTC (rev 19896)
+++ branches/saltedhashstore/freenet/src/freenet/store/SaltedHashFreenetStore.java    2008-05-11 17:05:03 UTC (rev 19897)
@@ -132,7 +132,7 @@
        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;
@@ -310,7 +310,7 @@

        /**
         * @param storeSize
-         * the storeSize to set
+         *         the storeSize to set
         */
        protected void setStoreSize(long storeSize) {
            this.storeSize = storeSize;
@@ -401,8 +401,7 @@
         * Verify and decrypt this entry
         *
         * @param routingKey
-         * @return <code>true</code> if the <code>routeKey</code> match and the entry is
-         * decrypted.
+         * @return <code>true</code> if the <code>routeKey</code> match and the entry is decrypted.
         */
        private boolean decrypt(byte[] routingKey) {
            if (!isEncrypted) {
@@ -599,7 +598,7 @@
     *
     * @param offset
     * @param entry
-     * entry, maybe <code>null</code>
+     *         entry, maybe <code>null</code>
     * @throws IOException
     */
    private boolean isFree(long offset, Entry entry) throws IOException {
@@ -742,7 +741,7 @@
            while (!shutdown) {
                synchronized (cleanerLock) {
                    if (prevStoreSize != 0)
-                        ; //resizeStore();
+                        resizeStore();
                    else
                        estimateStoreSize();

@@ -781,11 +780,9 @@
         */
        private int resizeRound;

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

        /**
         * Scan all entries and try to move them
-         *
+         */
        private void moveOldEntry0(boolean queueItem) {
            newEntries = 0;
            oldEntries = 0;
@@ -851,7 +848,7 @@

            long maxOffset = maxOldItemOffset;
            maxOldItemOffset = 0;
-            for (long offset = 0; offset <= maxOffset; offset++) {
+            LOOP_ENTRIES: for (long offset = 0; offset <= maxOffset; offset++) {
                if (logDEBUG && offset % 1024 == 0) {
                    Logger.debug(this, "Resize progress: newEntries=" + newEntries + ", oldEntries=" + oldEntries
                     + ", freeEntries=" + freeEntries + ", resolvedEntries=" + resolvedEntries
@@ -862,68 +859,104 @@
                    return;

                if (!lockEntry(offset)) //lock
-                    continue;
+                    continue LOOP_ENTRIES;
                try {
                    Entry entry = readEntry(offset, null);

                    if (entry.isFree()) {
                        // free block
                        freeEntries++;
-                    } else if (entry.getStoreSize() == storeSize) {
+                        continue LOOP_ENTRIES;
+                    }
+                    if (entry.getStoreSize() == storeSize) {
                        // new store size entries
                        maxOldItemOffset = offset;
                        newEntries++;
-                    } else { // if (entry.getStoreSize() == prevStoreSize)
-                        // old store size entries, try to move them
-                        oldEntries++;
-                        maxOldItemOffset = offset;
+                        continue LOOP_ENTRIES;
+                    }

-                        entry.setStoreSize(storeSize);
-                        long newOffset = entry.getOffset();
+                    // if (entry.getStoreSize() == prevStoreSize)
+                    // old store size entries, try to move them
+                    maxOldItemOffset = offset;
+                    oldEntries++;

-                        if (newOffset == offset) { // lucky!
-                            lockAndWrite(entry); // write back entry storeSize
+                    entry.setStoreSize(storeSize);
+                    long[] newOffset = entry.getOffset();
+
+                    // Check if I can keep my current offset
+                    for (int i = 0; i < newOffset.length; i++) {
+                        if (newOffset[i] == offset) { // lucky!
+                            writeEntry(entry, offset); // write back entry storeSize
                            resolvedEntries++;
-                            continue;
+
+                            if (logDEBUG)
+                                Logger.debug(this, "old entry " + HexUtil.bytesToHex(entry.getDigestedRoutingKey())
+                                 + " resolved without moving");
+
+                            continue LOOP_ENTRIES;
                        }
+                    }

-                        if (!lockEntry(newOffset)) // lock
-                            continue;
-                        try {
+                    boolean[] locked = new boolean[newOffset.length];
+                    try {
+                        // Lock all possible slots first
+                        for (int i = 0; i < newOffset.length; i++) {
+                            if (lockEntry(newOffset[i])) { // lock
+                                locked[i] = true;
+                            } else if (shutdown) { // oops
+                                return;
+                            }
+                        }
+
+                        // Probe for a free slot
+                        for (int i = 0; i < newOffset.length; i++) {
                            // see what's in the new offset
-                            Entry newOffsetEntry = readEntry(newOffset, null);
+                            Entry newOffsetEntry = readEntry(newOffset[i], null);

+                            // Free slot
                            if (newOffsetEntry.isFree()) {
                                // the new offset is freeeeeeee..
-                                lockAndWrite(entry);
+                                writeEntry(entry, newOffset[i]);
                                freeOffset(offset);
                                resolvedEntries++;
-                            } else if (newOffsetEntry.getStoreSize() == storeSize) {
-                                // new offset already have a new entry, free old entry
+
+                                if (logDEBUG)
+                                    Logger.debug(this, "old entry " + HexUtil.bytesToHex(entry.getDigestedRoutingKey())
+                                     + " resolved by moving to free block");
+
+                                continue LOOP_ENTRIES;
+                            }
+
+                            // Same digested key: same routing key or SHA-256 collision
+                            byte[] digestedRoutingKey = entry.getDigestedRoutingKey();
+                            byte[] digestedRoutingKey2 = newOffsetEntry.getDigestedRoutingKey();
+                            if (Arrays.equals(digestedRoutingKey, digestedRoutingKey2)) {
+                                // assume same routing key, drop this as duplicate
                                freeOffset(offset);
                                droppedEntries++;
-                            } else if (Arrays.equals(entry.digestedRoutingKey, newOffsetEntry.digestedRoutingKey)) {
-                                // same digested routing key, free the old entry
-                                freeOffset(offset);
-                                resolvedEntries++;
-                            } else if (queueItem) {
-                                // break tie by moveing old item to queue
+
                                if (logDEBUG)
-                                    Logger.debug(this, "Write item "
-                                     + HexUtil.bytesToHex(newOffsetEntry.digestedRoutingKey)
-                                     + " to old item file");
-                                writeOldItem(oldItemsFC, newOffsetEntry);
-                                if (newOffset > offset) {
-                                    oldEntries++; // newOffset wasn't counted count it
-                                }
+                                    Logger.debug(this, "old entry " + HexUtil.bytesToHex(entry.getDigestedRoutingKey())
+                                     + " dropped duplicate");

-                                lockAndWrite(entry);
-                                freeOffset(offset);
-                                resolvedEntries++;
+                                continue LOOP_ENTRIES;
                            }
-                        } finally {
-                            unlockEntry(newOffset);
                        }
+
+                        if (queueItem) {
+                            if (logDEBUG)
+                                Logger.debug(this, "old entry " + HexUtil.bytesToHex(entry.getDigestedRoutingKey())
+                                 + " queued");
+                            writeOldItem(oldItemsFC, entry);
+                            freeOffset(offset);
+                        }
+                    } finally {
+                        // unlock all entries
+                        for (int i = 0; i < newOffset.length; i++) {
+                            if (locked[i]) {
+                                unlockEntry(newOffset[i]);
+                            }
+                        }
                    }
                } catch (IOException e) {
                    Logger.debug(this, "IOExcception on moveOldEntries0", e);
@@ -951,40 +984,41 @@
         * Put back oldItems with best effort
         *
         * @throws IOException
-         *
+         */
        private void putBackOldItems(FileChannel oldItems) throws IOException {
-            while (true) {
+            LOOP_ITEMS: while (true) {
                Entry entry = readOldItem(oldItems);
                if (entry == null)
                    break;

                entry.setStoreSize(storeSize);

-                long newOffset = entry.getOffset();
+                long[] newOffset = entry.getOffset();

-                if (!lockEntry(newOffset)) // lock
-                    continue;
-                boolean done = false;
-                try {
-                    if (isFree(newOffset)) {
-                        if (logDEBUG)
-                            Logger.debug(this, "Put back old item: " + HexUtil.bytesToHex(entry.digestedRoutingKey));
-                        lockAndWrite(entry);
-                        done = true;
-                    } else {
-                        if (logDEBUG)
-                            Logger.debug(this, "Drop old item: " + HexUtil.bytesToHex(entry.digestedRoutingKey));
+                for (int i = 0; i < newOffset.length; i++) {
+                    if (!lockEntry(newOffset[i])) // lock
+                        continue;
+                    try {
+                        if (isFree(newOffset[i], entry)) {
+                            if (logDEBUG)
+                                Logger
+                                 .debug(this, "Put back old item: "
+                                 + HexUtil.bytesToHex(entry.digestedRoutingKey));
+                            writeEntry(entry, newOffset[i]);
+                            resolvedEntries++;
+                            continue LOOP_ITEMS;
+                        } else {
+                            if (logDEBUG)
+                                Logger.debug(this, "Drop old item: " + HexUtil.bytesToHex(entry.digestedRoutingKey));
+                        }
+                    } catch (IOException e) {
+                        Logger.debug(this, "IOExcception on putBackOldItems", e);
+                    } finally {
+                        unlockEntry(newOffset[i]);
                    }
-                } catch (IOException e) {
-                    Logger.debug(this, "IOExcception on putBackOldItems", e);
-                } finally {
-                    unlockEntry(newOffset);
+                }

-                    if (done)
-                        resolvedEntries++;
-                    else
-                        droppedEntries++;
-                }
+                droppedEntries++;
            }
        }

@@ -996,14 +1030,17 @@
        }

        private Entry readOldItem(FileChannel fc) throws IOException {
-            ByteBuffer bf = ByteBuffer.allocate((int) entryTotalLength);
-            do {
-                fc.read(bf);
-            } while (bf.hasRemaining());
-            bf.flip();
-            return new Entry(bf);
+            try {
+                ByteBuffer bf = ByteBuffer.allocate((int) entryTotalLength);
+                do {
+                    fc.read(bf);
+                } while (bf.hasRemaining());
+                bf.flip();
+                return new Entry(bf);
+            } catch (EOFException e) {
+                return null;
+            }
        }
-        */

        /**
         * Samples to take on key count estimation
@@ -1056,6 +1093,7 @@
        Logger.normal(this, "[" + name + "] Resize newStoreSize=" + newStoreSize + ", shinkNow=" + shrinkNow);

        assert newStoreSize > 0;
+        // TODO assert newStoreSize > (141 * (3 * 3) + 13 * 3) * 2; // store size too small

        synchronized (cleanerLock) {
            if (newStoreSize == this.storeSize)
@@ -1088,8 +1126,8 @@
    /**
     * Lock the entry
     *
-     * This lock is <strong>not</strong> reentrance. No threads except Cleaner should hold more
-     * then one lock at a time (or deadlock may occur).
+     * This lock is <strong>not</strong> reentrance. No threads except Cleaner should hold more then
+     * one lock at a time (or deadlock may occur).
     */
    private boolean lockEntry(long offset) {
        if (logDEBUG && logLOCK)
@@ -1140,7 +1178,7 @@
     * Use this method to stop all read / write before database shutdown.
     *
     * @param timeout
-     * the maximum time to wait in milliseconds.
+     *         the maximum time to wait in milliseconds.
     */
    private boolean lockGlobal(long timeout) {
        synchronized (lockMap) {