Author: toad
Date: 2008-02-08 18:31:57 +0000 (Fri, 08 Feb 2008)
New Revision: 17705

Modified:
   trunk/freenet/src/freenet/node/FailureTable.java
   trunk/freenet/src/freenet/node/FailureTableEntry.java
   trunk/freenet/src/freenet/support/LRUHashtable.java
Log:
Cleanup the failure table every 30 minutes.

Modified: trunk/freenet/src/freenet/node/FailureTable.java
===================================================================
--- trunk/freenet/src/freenet/node/FailureTable.java    2008-02-08 18:31:02 UTC 
(rev 17704)
+++ trunk/freenet/src/freenet/node/FailureTable.java    2008-02-08 18:31:57 UTC 
(rev 17705)
@@ -53,6 +53,8 @@
        static final int OFFER_EXPIRY_TIME = 10*60*1000;
        /** HMAC key for the offer authenticator */
        final byte[] offerAuthenticatorKey;
+       /** Clean up old data every 30 minutes to save memory and improve 
privacy */
+       static final int CLEANUP_PERIOD = 30*60*1000;

        static boolean logMINOR;
        static boolean logDEBUG;
@@ -66,6 +68,7 @@
                node.random.nextBytes(offerAuthenticatorKey);
                logMINOR = Logger.shouldLog(Logger.MINOR, this);
                logDEBUG = Logger.shouldLog(Logger.DEBUG, this);
+               node.ps.queueTimedJob(new FailureTableCleaner(), 
CLEANUP_PERIOD);
        }

        /**
@@ -120,11 +123,6 @@
                while(entriesByKey.size() > MAX_ENTRIES) {
                        entriesByKey.popKey();
                }
-               while(true) {
-                       FailureTableEntry e = (FailureTableEntry) 
entriesByKey.peekValue();
-                       if(now - e.creationTime > MAX_LIFETIME) 
entriesByKey.popKey();
-                       else break;
-               }
        }

        private final class BlockOfferList {
@@ -454,4 +452,38 @@
                        return (FailureTableEntry) entriesByKey.get(key);
                }
        }
+       
+       public class FailureTableCleaner implements Runnable {
+
+               public void run() {
+                       try {
+                               realRun();
+                       } catch (Throwable t) {
+                               Logger.error(this, "FailureTableCleaner caught 
"+t, t);
+                       } finally {
+                               node.ps.queueTimedJob(this, CLEANUP_PERIOD);
+                       }
+               }
+
+               private void realRun() {
+                       logMINOR = Logger.shouldLog(Logger.MINOR, 
FailureTable.this);
+                       logDEBUG = Logger.shouldLog(Logger.DEBUG, 
FailureTable.this);
+                       if(logMINOR) Logger.minor(this, "Starting FailureTable 
cleanup");
+                       long startTime = System.currentTimeMillis();
+                       FailureTableEntry[] entries;
+                       synchronized(FailureTable.this) {
+                               entries = new 
FailureTableEntry[entriesByKey.size()];
+                               entriesByKey.toArray(entries);
+                       }
+                       for(int i=0;i<entries.length;i++) {
+                               entries[i].cleanup();
+                               // FIXME how to safely remove them if empty?
+                               // I suppose we'll have to establish a lock 
taking order...
+                       }
+                       long endTime = System.currentTimeMillis();
+                       if(logMINOR) Logger.minor(this, "Finished FailureTable 
cleanup took "+(endTime-startTime)+"ms");
+               }
+
+       }
+
 }

Modified: trunk/freenet/src/freenet/node/FailureTableEntry.java
===================================================================
--- trunk/freenet/src/freenet/node/FailureTableEntry.java       2008-02-08 
18:31:02 UTC (rev 17704)
+++ trunk/freenet/src/freenet/node/FailureTableEntry.java       2008-02-08 
18:31:57 UTC (rev 17705)
@@ -429,4 +429,71 @@
                return -1; // not timed out
        }

+       public synchronized void cleanup() {
+               int x = 0;
+               long now = System.currentTimeMillis(); // don't pass in as a 
pass over the whole FT may take a while. get it in the method.
+               for(int i=0;i<requestorNodes.length;i++) {
+                       WeakReference ref = requestorNodes[i];
+                       if(ref == null) continue;
+                       PeerNode pn = (PeerNode) ref.get();
+                       if(pn == null) continue;
+                       long bootID = pn.getBootID();
+                       if(bootID != requestorBootIDs[i]) continue;
+                       if(!pn.isConnected()) continue;
+                       if(now - requestorTimes[i] > 
MAX_TIME_BETWEEN_REQUEST_AND_OFFER) continue;
+                       requestorNodes[x] = requestorNodes[i];
+                       requestorTimes[x] = requestorTimes[i];
+                       requestorBootIDs[x] = requestorBootIDs[i];
+                       x++;
+               }
+               if(x < requestorNodes.length) {
+                       WeakReference[] newRequestorNodes = new 
WeakReference[x];
+                       long[] newRequestorTimes = new long[x];
+                       long[] newRequestorBootIDs = new long[x];
+                       System.arraycopy(requestorNodes, 0, newRequestorNodes, 
0, x);
+                       System.arraycopy(requestorTimes, 0, newRequestorTimes, 
0, x);
+                       System.arraycopy(requestorBootIDs, 0, 
newRequestorBootIDs, 0, x);
+                       requestorNodes = newRequestorNodes;
+                       requestorTimes = newRequestorTimes;
+                       requestorBootIDs = newRequestorBootIDs;
+               }
+               x = 0;
+               for(int i=0;i<requestedNodes.length;i++) {
+                       WeakReference ref = requestedNodes[i];
+                       if(ref == null) continue;
+                       PeerNode pn = (PeerNode) ref.get();
+                       if(pn == null) continue;
+                       long bootID = pn.getBootID();
+                       if(bootID != requestedBootIDs[i]) continue;
+                       if(!pn.isConnected()) continue;
+                       if(now - requestedTimes[i] > 
MAX_TIME_BETWEEN_REQUEST_AND_OFFER) continue;
+                       requestedNodes[x] = requestedNodes[i];
+                       requestedTimes[x] = requestedTimes[i];
+                       requestedBootIDs[x] = requestedBootIDs[i];
+                       if(now < requestedTimeouts[x]) { 
+                               requestedTimeouts[x] = requestedTimeouts[i];
+                               requestedTimeoutHTLs[x] = 
requestedTimeoutHTLs[i];
+                       } else {
+                               requestedTimeouts[x] = -1;
+                               requestedTimeoutHTLs[x] = (short)-1;
+                       }
+                       x++;
+               }
+               if(x < requestedNodes.length) {
+                       WeakReference[] newRequestedNodes = new 
WeakReference[x];
+                       long[] newRequestedTimes = new long[x];
+                       long[] newRequestedBootIDs = new long[x];
+                       long[] newRequestedTimeouts = new long[x];
+                       short[] newRequestedTimeoutHTLs = new short[x];
+                       System.arraycopy(requestedNodes, 0, newRequestedNodes, 
0, x);
+                       System.arraycopy(requestedTimes, 0, newRequestedTimes, 
0, x);
+                       System.arraycopy(requestedBootIDs, 0, 
newRequestedBootIDs, 0, x);
+                       requestedNodes = newRequestedNodes;
+                       requestedTimes = newRequestedTimes;
+                       requestedBootIDs = newRequestedBootIDs;
+                       requestedTimeouts = newRequestedTimeouts;
+                       requestedTimeoutHTLs = newRequestedTimeoutHTLs;
+               }
+       }
+
 }
\ No newline at end of file

Modified: trunk/freenet/src/freenet/support/LRUHashtable.java
===================================================================
--- trunk/freenet/src/freenet/support/LRUHashtable.java 2008-02-08 18:31:02 UTC 
(rev 17704)
+++ trunk/freenet/src/freenet/support/LRUHashtable.java 2008-02-08 18:31:57 UTC 
(rev 17705)
@@ -133,4 +133,17 @@
                return list.isEmpty();
        }

+       /**
+        * Note that unlike the java.util versions, this will not reallocate 
(hence it doesn't return), 
+        * so pass in an appropriately big array, and make sure you hold the 
lock!
+        * @param entries
+        * @return
+        */
+       public synchronized void toArray(Object[] entries) {
+               Enumeration keys = keys();
+               int i=0;
+               while(keys.hasMoreElements())
+                       entries[i++] = keys.nextElement();
+       }
+
 }


Reply via email to