Author: toad
Date: 2005-11-16 14:46:11 +0000 (Wed, 16 Nov 2005)
New Revision: 7544

Modified:
   trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
   trunk/freenet/src/freenet/node/FNPPacketMangler.java
   trunk/freenet/src/freenet/node/KeyTracker.java
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/PeerNode.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/support/DoublyLinkedListImpl.java
   trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
   trunk/freenet/src/freenet/support/UpdatableSortedLinkedList.java
   
trunk/freenet/src/freenet/support/UpdatableSortedLinkedListWithForeignIndex.java
Log:
Mandatory 181:
Fix lots of bugs, including some stuff on synchronization.
End result is that we no longer get the load related bugs (delayed 
DataInsert's, sequence errors, etc).
But there may be some bugs related to large splitfiles.

Modified: trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
===================================================================
--- trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-15 
21:10:36 UTC (rev 7543)
+++ trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-16 
14:46:11 UTC (rev 7544)
@@ -22,6 +22,53 @@
  */
 public class StandardOnionFECCodec extends FECCodec {

+       public class Encoder implements Runnable {
+
+               private final SplitfileBlock[] dataBlockStatus, 
checkBlockStatus;
+               private final int blockLength;
+               private final BucketFactory bf;
+               private IOException thrownIOE;
+               private RuntimeException thrownRE;
+               private Error thrownError;
+               private boolean finished;
+               
+               public Encoder(SplitfileBlock[] dataBlockStatus, 
SplitfileBlock[] checkBlockStatus, int blockLength, BucketFactory bf) {
+                       this.dataBlockStatus = dataBlockStatus;
+                       this.checkBlockStatus = checkBlockStatus;
+                       this.blockLength = blockLength;
+                       this.bf = bf;
+               }
+
+               public void run() {
+                       long startTime = System.currentTimeMillis();
+                       try {
+                               realEncode(dataBlockStatus, checkBlockStatus, 
blockLength, bf);
+                       } catch (IOException e) {
+                               thrownIOE = e;
+                       } catch (RuntimeException e) {
+                               thrownRE = e;
+                       } catch (Error e) {
+                               thrownError = e;
+                       }
+                       long endTime = System.currentTimeMillis();
+                       Logger.minor(this, "Splitfile encode: k="+k+", n="+n+" 
encode took "+(endTime-startTime)+"ms");
+                       finished = true;
+                       synchronized(this) {
+                               notify();
+                       }
+               }
+
+               public void throwException() throws IOException {
+                       if(thrownIOE != null)
+                               throw thrownIOE;
+                       if(thrownRE != null)
+                               throw thrownRE;
+                       if(thrownError != null)
+                               throw thrownError;
+               }
+
+       }
+
        // REDFLAG: How big is one of these?
        private static int MAX_CACHED_CODECS = 16;
        // REDFLAG: Optimal stripe size? Smaller => less memory usage, but more 
JNI overhead
@@ -249,10 +296,22 @@
                        runningDecodes++;
                }
                try {
-                       long startTime = System.currentTimeMillis();
-                       realEncode(dataBlockStatus, checkBlockStatus, 
blockLength, bf);
-                       long endTime = System.currentTimeMillis();
-                       Logger.minor(this, "Splitfile encode: k="+k+", n="+n+" 
encode took "+(endTime-startTime)+"ms");
+                       // Run on a separate thread so we can tweak priority
+                       Encoder et = new Encoder(dataBlockStatus, 
checkBlockStatus, blockLength, bf);
+                       Thread t = new Thread(et, "Encoder thread for k="+k+", 
n="+n+" started at "+System.currentTimeMillis());
+                       t.setDaemon(true);
+                       t.setPriority(Thread.MIN_PRIORITY);
+                       t.start();
+                       synchronized(et) {
+                               while(!et.finished) {
+                                       try {
+                                               et.wait(10*1000);
+                                       } catch (InterruptedException e) {
+                                               // Ignore
+                                       }
+                               }
+                       }
+                       et.throwException();
                } finally {
                        synchronized(runningDecodesSync) {
                                runningDecodes--;
@@ -266,10 +325,10 @@
        private void realEncode(SplitfileBlock[] dataBlockStatus,
                        SplitfileBlock[] checkBlockStatus, int blockLength, 
BucketFactory bf)
                        throws IOException {
-               Runtime.getRuntime().gc();
-               Runtime.getRuntime().runFinalization();
-               Runtime.getRuntime().gc();
-               Runtime.getRuntime().runFinalization();
+//             Runtime.getRuntime().gc();
+//             Runtime.getRuntime().runFinalization();
+//             Runtime.getRuntime().gc();
+//             Runtime.getRuntime().runFinalization();
                long memUsedAtStart = Runtime.getRuntime().totalMemory() - 
Runtime.getRuntime().freeMemory();
                Logger.minor(this, "Memory in use at start: "+memUsedAtStart+" 
max="+Runtime.getRuntime().maxMemory());
                System.err.println("************* Encoding " + 
dataBlockStatus.length
@@ -340,23 +399,30 @@
                                        // Do the encode
                                        // Not shuffled
                                        long startTime = 
System.currentTimeMillis();
-                                       Runtime.getRuntime().gc();
-                                       Runtime.getRuntime().runFinalization();
-                                       Runtime.getRuntime().gc();
-                                       Runtime.getRuntime().runFinalization();
+//                                     Runtime.getRuntime().gc();
+//                                     Runtime.getRuntime().runFinalization();
+//                                     Runtime.getRuntime().gc();
+//                                     Runtime.getRuntime().runFinalization();
                                        long memUsedBeforeStripe = 
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
                                        Logger.minor(this, "Memory in use 
before stripe: "+memUsedBeforeStripe);
                                        code.encode(dataPackets, checkPackets, 
toEncode);
-                                       Runtime.getRuntime().gc();
-                                       Runtime.getRuntime().runFinalization();
-                                       Runtime.getRuntime().gc();
-                                       Runtime.getRuntime().runFinalization();
+//                                     Runtime.getRuntime().gc();
+//                                     Runtime.getRuntime().runFinalization();
+//                                     Runtime.getRuntime().gc();
+//                                     Runtime.getRuntime().runFinalization();
                                        long memUsedAfterStripe = 
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
                                        Logger.minor(this, "Memory in use after 
stripe: "+memUsedAfterStripe);
                                        long endTime = 
System.currentTimeMillis();
                                        Logger.minor(this, "Stripe encode took "
                                                        + (endTime - startTime) 
+ " ms for k=" + k + ", n="
                                                        + n + ", stripeSize=" + 
STRIPE_SIZE);
+                                       // FIXME this is a total horrible hack, 
but I was desperate
+                                       // Without this, threads get randomly 
stuck for many seconds at a time
+                                       try {
+                                               Thread.sleep(endTime - 
startTime);
+                                       } catch (InterruptedException e) {
+                                               // Ignore
+                                       }
                                        // packets now contains an array of 
decoded blocks, in order
                                        // Write the data out
                                        for (int i = k; i < n; i++) {

Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java        2005-11-15 
21:10:36 UTC (rev 7543)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java        2005-11-16 
14:46:11 UTC (rev 7544)
@@ -1062,25 +1062,45 @@
         }

         // We do not support forgotten packets at present
+
+        int[] acks, resendRequests, ackRequests;
+       int seqNumber;
+        /* Locking:
+         * Avoid allocating a packet number, then a long pause due to 
+         * overload, during which many other packets are sent, 
+         * resulting in the other side asking us to resend a packet 
+         * which doesn't exist yet.
+         * => grabbing resend reqs, packet no etc must be as
+         * close together as possible.
+         * 
+         * HOWEVER, tracker.allocateOutgoingPacketNumber can block,
+         * so should not be locked.
+         */
+       
+               if(packetNumber > 0)
+                       seqNumber = packetNumber;
+               else {
+                       if(buf.length == 1)
+                               // Ack/resendreq only packet
+                               seqNumber = -1;
+                       else
+                               seqNumber = 
tracker.allocateOutgoingPacketNumber();
+               }

-        int[] acks = tracker.grabAcks();
-        int[] resendRequests = tracker.grabResendRequests();
-        int[] ackRequests = tracker.grabAckRequests();
+               Logger.minor(this, "Sequence number (sending): "+seqNumber+" 
("+packetNumber+") to "+tracker.pn.getPeer());

-        // Allocate a sequence number
-        int seqNumber;
-        if(packetNumber > 0)
-            seqNumber = packetNumber;
-        else {
-            if(buf.length == 1)
-                // Ack/resendreq only packet
-                seqNumber = -1;
-            else
-                seqNumber = tracker.allocateOutgoingPacketNumber();
+        /** The last sent sequence number, so that we can refer to packets
+         * sent after this packet was originally sent (it may be a resend) */
+               int realSeqNumber;
+               
+               synchronized(tracker) {
+               acks = tracker.grabAcks();
+               resendRequests = tracker.grabResendRequests();
+               ackRequests = tracker.grabAckRequests();
+            realSeqNumber = tracker.getLastOutgoingSeqNumber();
+            
         }

-        Logger.minor(this, "Sequence number (sending): "+seqNumber+" 
("+packetNumber+") to "+tracker.pn.getPeer());
-        
         int packetLength = acks.length + resendRequests.length + 
ackRequests.length + 4 + 1 + length + 4 + 4 + RANDOM_BYTES_LENGTH;
         if(packetNumber == -1) packetLength += 4;
         else packetLength++;
@@ -1103,18 +1123,12 @@

         plaintext[ptr++] = 0; // version number

-        /** The last sent sequence number, so that we can refer to packets
-         * sent after this packet was originally sent (it may be a resend) */
-        int realSeqNumber = seqNumber;
-        
         if(seqNumber == -1) {
-            realSeqNumber = tracker.getLastOutgoingSeqNumber();
             plaintext[ptr++] = (byte)(realSeqNumber >> 24);
             plaintext[ptr++] = (byte)(realSeqNumber >> 16);
             plaintext[ptr++] = (byte)(realSeqNumber >> 8);
             plaintext[ptr++] = (byte)realSeqNumber;
         } else {
-            realSeqNumber = tracker.getLastOutgoingSeqNumber();
             plaintext[ptr++] = (byte)(realSeqNumber - seqNumber);
         }


Modified: trunk/freenet/src/freenet/node/KeyTracker.java
===================================================================
--- trunk/freenet/src/freenet/node/KeyTracker.java      2005-11-15 21:10:36 UTC 
(rev 7543)
+++ trunk/freenet/src/freenet/node/KeyTracker.java      2005-11-16 14:46:11 UTC 
(rev 7544)
@@ -85,7 +85,8 @@
         this.sessionKey = sessionKey;
         ackQueue = new DoublyLinkedListImpl();
         highestSeenIncomingSerialNumber = -1;
-        sentPacketsContents = new LimitedRangeIntByteArrayMap(256);
+        // give some leeway
+        sentPacketsContents = new LimitedRangeIntByteArrayMap(128);
         resendRequestQueue = new UpdatableSortedLinkedListWithForeignIndex();
         ackRequestQueue = new UpdatableSortedLinkedListWithForeignIndex();
         packetsToResend = new HashSet();
@@ -319,8 +320,10 @@
     /**
      * Called when we receive a packet.
      * @param seqNumber The packet's serial number.
+     * See the comments in FNPPacketMangler.processOutgoing* for
+     * the reason for the locking.
      */
-    public void receivedPacket(int seqNumber) {
+    public synchronized void receivedPacket(int seqNumber) {
        Logger.minor(this, "Received packet "+seqNumber);
         try {
                        pn.receivedPacket();
@@ -437,12 +440,16 @@

     /**
      * Called when we have received several packet acknowledgements.
+     * Synchronized for the same reason as the sender code is:
+     * So that we don't end up sending packets too late when overloaded,
+     * and get horrible problems such as asking to resend packets which
+     * haven't been sent yet.
      */
-    public void acknowledgedPackets(int[] seqNos) {
+    public synchronized void acknowledgedPackets(int[] seqNos) {
        AsyncMessageCallback[][] callbacks = new 
AsyncMessageCallback[seqNos.length][];
                for(int i=0;i<seqNos.length;i++) {
                        int realSeqNo = seqNos[i];
-               Logger.minor(this, "Acknowledged packet (synced): "+realSeqNo);
+               Logger.minor(this, "Acknowledged packet: "+realSeqNo);
             try {
                                removeAckRequest(realSeqNo);
                        } catch (UpdatableSortedLinkedListKilledException e) {
@@ -472,7 +479,7 @@
      */
     public void acknowledgedPacket(int realSeqNo) {
         AsyncMessageCallback[] callbacks;
-               Logger.minor(this, "Acknowledged packet (synced): "+realSeqNo);
+               Logger.minor(this, "Acknowledged packet: "+realSeqNo);
         try {
                        removeAckRequest(realSeqNo);
                } catch (UpdatableSortedLinkedListKilledException e) {
@@ -512,11 +519,8 @@
                synchronized(this) {
                        String msg = "Asking me to resend packet "+seqNumber+
                                " which we haven't sent yet or which they have 
already acked (next="+nextPacketNumber+")";
-                       // Can have a race condition
-                       if(seqNumber < nextPacketNumber && seqNumber > 
nextPacketNumber-64)
-                               Logger.minor(this, msg);
-                       else
-                               Logger.error(this, msg);
+                       // Probably just a bit late - caused by overload etc
+                       Logger.minor(this, msg);
                }
         }
     }
@@ -526,7 +530,7 @@
      * @param packetNumber The packet that the other side wants
      * us to re-ack.
      */
-    public void receivedAckRequest(int packetNumber) {
+    public synchronized void receivedAckRequest(int packetNumber) {
         if(queuedAck(packetNumber)) {
             // Already going to send an ack
             // Don't speed it up though; wasteful
@@ -541,9 +545,7 @@
                                } catch 
(UpdatableSortedLinkedListKilledException e) {
                                        // Ignore, we are decoding, not sending.
                                }
-                synchronized(this) {
-                    highestSeenIncomingSerialNumber = 
Math.max(highestSeenIncomingSerialNumber, packetNumber);
-                }
+                highestSeenIncomingSerialNumber = 
Math.max(highestSeenIncomingSerialNumber, packetNumber);
             }
         }
     }
@@ -570,7 +572,7 @@
      * This is normal if we are the secondary key.
      * @param seqNumber The packet number lost.
      */
-    public void destForgotPacket(int seqNumber) {
+    public synchronized void destForgotPacket(int seqNumber) {
         if(isDeprecated) {
             Logger.normal(this, "Destination forgot packet: "+seqNumber);
         } else {
@@ -631,6 +633,7 @@
      * @return An array of packet numbers that we need to acknowledge.
      */
     public int[] grabAcks() {
+       Logger.minor(this, "Grabbing acks");
         int[] acks;
         synchronized(ackQueue) {
             // Grab the acks and tell them they are sent
@@ -691,9 +694,9 @@
         UpdatableSortedLinkedListItem[] items;
         int[] packetNumbers;
         int realLength;
-        long now = System.currentTimeMillis();
         try {
         synchronized(ackRequestQueue) {
+            long now = System.currentTimeMillis();
             items = ackRequestQueue.toArray();
             int length = items.length;
             packetNumbers = new int[length];
@@ -711,7 +714,7 @@
                     Logger.minor(this, "Grabbing ack request "+packetNumber+" 
from "+this);
                     qr.sent();
                 } else {
-                    Logger.minor(this, "Ignoring ack request "+packetNumber+" 
- will become active in "+(qr.activeTime-now)+" ms on "+this);
+                    Logger.minor(this, "Ignoring ack request "+packetNumber+" 
- will become active in "+(qr.activeTime-now)+" ms on "+this+" - "+qr);
                 }
             }
         }

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2005-11-15 21:10:36 UTC (rev 
7543)
+++ trunk/freenet/src/freenet/node/Node.java    2005-11-16 14:46:11 UTC (rev 
7544)
@@ -71,8 +71,8 @@
     public static final double DECREMENT_AT_MAX_PROB = 0.1;
     // Send keepalives every 2.5-5.0 seconds
     public static final int KEEPALIVE_INTERVAL = 2500;
-    // If no activity for 15 seconds, node is dead
-    public static final int MAX_PEER_INACTIVITY = 15000;
+    // If no activity for 30 seconds, node is dead
+    public static final int MAX_PEER_INACTIVITY = 60000;
     /** Time after which a handshake is assumed to have failed. */
     public static final int HANDSHAKE_TIMEOUT = 5000;
     // Inter-handshake time must be at least 2x handshake timeout
@@ -265,6 +265,9 @@
         Node n = new Node(port, yarrow, overrideIP, "");
         n.start(new StaticSwapRequestInterval(2000));
         new TextModeClientInterface(n);
+        Thread t = new Thread(new MemoryChecker(), "Memory checker");
+        t.setPriority(Thread.MAX_PRIORITY);
+        t.start();
     }

     // FIXME - the whole overrideIP thing is a hack to avoid config
@@ -786,4 +789,19 @@
        public HighLevelSimpleClient makeClient() {
                return new HighLevelSimpleClientImpl(this, archiveManager, 
tempBucketFactory, random);
        }
+       
+       private static class MemoryChecker implements Runnable {
+
+               public void run() {
+                       Runtime r = Runtime.getRuntime();
+                       while(true) {
+                               try {
+                                       Thread.sleep(1000);
+                               } catch (InterruptedException e) {
+                                       // Ignore
+                               }
+                               Logger.minor(this, "Memory in use: 
"+(r.totalMemory()-r.freeMemory()));
+                       }
+               }
+       }
 }

Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java        2005-11-15 21:10:36 UTC 
(rev 7543)
+++ trunk/freenet/src/freenet/node/PeerNode.java        2005-11-16 14:46:11 UTC 
(rev 7544)
@@ -72,11 +72,6 @@
     /** When did we last receive a packet? */
     private long timeLastReceivedPacket;

-    /** Maximum time between packet receives. In other words,
-     * after this amount of time, we assume the node is dead.
-     */
-    private int maxTimeBetweenPacketReceives;
-
     /** Are we connected? If not, we need to start trying to
      * handshake.
      */
@@ -235,7 +230,6 @@
         timeLastReceivedPacket = -1;
         timeLastReceivedSwapRequest = -1;

-        randomizeMaxTimeBetweenPacketReceives();
         randomizeMaxTimeBetweenPacketSends();
         swapRequestsInterval = new SimpleRunningAverage(50, 
Node.MIN_INTERVAL_BETWEEN_INCOMING_SWAP_REQUESTS);

@@ -253,12 +247,6 @@
         x += node.random.nextInt(x);
     }

-    private void randomizeMaxTimeBetweenPacketReceives() {
-        int x = Node.MAX_PEER_INACTIVITY;
-        x += node.random.nextInt(x);
-        maxTimeBetweenPacketReceives = x;
-    }
-
     /**
      * Get my low-level address
      */
@@ -351,7 +339,7 @@
     public void requeueMessageItems(MessageItem[] messages, int offset, int 
length, boolean dontLog) {
         // Will usually indicate serious problems
         if(!dontLog)
-            Logger.error(this, "Requeueing "+messages.length+" messages on 
"+this);
+            Logger.normal(this, "Requeueing "+messages.length+" messages on 
"+this);
         synchronized(messagesToSendNow) {
             for(int i=offset;i<offset+length;i++)
                 if(messages[i] != null)
@@ -427,7 +415,7 @@
      * @return The maximum time between received packets.
      */
     public int maxTimeBetweenReceivedPackets() {
-        return this.maxTimeBetweenPacketReceives;
+       return Node.MAX_PEER_INACTIVITY;
     }

     /**
@@ -470,11 +458,10 @@

     /**
      * Send a message, right now, on this thread, to this node.
-     * REDFLAG: If we ever implement queueing, do it here.
      */
     public void send(Message req) throws NotConnectedException {
         if(!isConnected) {
-            Logger.error(this, "Tried to send "+req+" but not connected", new 
Exception("debug"));
+            Logger.error(this, "Tried to send "+req+" but not connected to 
"+this, new Exception("debug"));
             return;
         }
         node.usm.send(this, req);
@@ -564,7 +551,6 @@
             throw new NotConnectedException();
         }
         timeLastReceivedPacket = System.currentTimeMillis();
-        randomizeMaxTimeBetweenPacketReceives();
     }

     /**

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2005-11-15 21:10:36 UTC (rev 
7543)
+++ trunk/freenet/src/freenet/node/Version.java 2005-11-16 14:46:11 UTC (rev 
7544)
@@ -20,10 +20,10 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       public static final int buildNumber = 180;
+       public static final int buildNumber = 181;

        /** Oldest build of Fred we will talk to */
-       public static final int lastGoodBuild = 180;
+       public static final int lastGoodBuild = 181;

        /** The highest reported build of fred */
        public static int highestSeenBuild = buildNumber;

Modified: trunk/freenet/src/freenet/support/DoublyLinkedListImpl.java
===================================================================
--- trunk/freenet/src/freenet/support/DoublyLinkedListImpl.java 2005-11-15 
21:10:36 UTC (rev 7543)
+++ trunk/freenet/src/freenet/support/DoublyLinkedListImpl.java 2005-11-16 
14:46:11 UTC (rev 7544)
@@ -244,7 +244,9 @@
        if (i.getParent() != this)
                throw new PromiscuousItemException(i, i.getParent());
         DoublyLinkedList.Item next = i.getNext(), prev = i.getPrev();
-        if (next == null || prev == null) return null;  // not in the list
+        if (next == null && prev == null) return null;  // not in the list
+        if (next == null || prev == null)
+               throw new NullPointerException("next="+next+", prev="+prev); // 
partially in the list?!
         if(next.getPrev() != i || prev.getNext() != i) {
                String msg = "Illegal ERROR: i="+i+", next="+next+", 
next.prev="+next.getPrev()+", prev="+prev+", prev.next="+prev.getNext();
                Logger.error(this, msg);

Modified: trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java
===================================================================
--- trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java  
2005-11-15 21:10:36 UTC (rev 7543)
+++ trunk/freenet/src/freenet/support/LimitedRangeIntByteArrayMap.java  
2005-11-16 14:46:11 UTC (rev 7544)
@@ -101,11 +101,17 @@
         boolean oldFlag = flag;
         if(minValue == -1) return;
         if(index - minValue < maxRange) return;
-        Logger.normal(this, toString()+" lock("+index+") - minValue = 
"+minValue+", maxValue = "+maxValue+", maxRange="+maxRange);
+        Logger.minor(this, toString()+" lock("+index+") - minValue = 
"+minValue+", maxValue = "+maxValue+", maxRange="+maxRange);
         while(true) {
             wait();
-            if(flag != oldFlag) throw new InterruptedException();
-            if(index - minValue < maxRange) return;
+            if(flag != oldFlag) {
+               Logger.minor(this, "Interrupted");
+               throw new InterruptedException();
+            }
+            if(index - minValue < maxRange || minValue == -1) {
+               Logger.minor(this, "index="+index+", minValue="+minValue+", 
maxRange="+maxRange+" - returning");
+               return;
+            }
         }
     }

@@ -127,6 +133,7 @@
             if(index > minValue && index < maxValue) return;
             if(contents.size() == 0) {
                 minValue = maxValue = -1;
+                notifyAll();
                 return;
             }
             if(index == maxValue) {
@@ -134,10 +141,12 @@
                     Integer ii = new Integer(i);
                     if(contents.containsKey(ii)) {
                         maxValue = i;
+                        notifyAll();
                         return;
                     }
                 }
                 // Still here - WTF?
+                notifyAll();
                 throw new IllegalStateException("Still here! (a)");
             }
             if(index == minValue) {
@@ -145,12 +154,15 @@
                     Integer ii = new Integer(i);
                     if(contents.containsKey(ii)) {
                         minValue = i;
+                        notifyAll();
                         return;
                     }
                 }
                 // Still here - WTF?
+                notifyAll();
                 throw new IllegalStateException("Still here! (b)");
             }
+            notifyAll();
             throw new IllegalStateException("impossible");
         }
     }

Modified: trunk/freenet/src/freenet/support/UpdatableSortedLinkedList.java
===================================================================
--- trunk/freenet/src/freenet/support/UpdatableSortedLinkedList.java    
2005-11-15 21:10:36 UTC (rev 7543)
+++ trunk/freenet/src/freenet/support/UpdatableSortedLinkedList.java    
2005-11-16 14:46:11 UTC (rev 7544)
@@ -77,12 +77,15 @@
        }
        }

-       public synchronized void remove(UpdatableSortedLinkedListItem i) throws 
UpdatableSortedLinkedListKilledException {
+       public synchronized UpdatableSortedLinkedListItem 
remove(UpdatableSortedLinkedListItem i) throws 
UpdatableSortedLinkedListKilledException {
        if(killed) throw new UpdatableSortedLinkedListKilledException();
         Logger.minor(this, "Remove("+i+") on "+this);
         checkList();
-        list.remove(i);
+        UpdatableSortedLinkedListItem item = 
+               (UpdatableSortedLinkedListItem) list.remove(i);
+        Logger.minor(this, "Returning "+item);
         checkList();
+        return item;
     }

     public synchronized void update(UpdatableSortedLinkedListItem i) throws 
UpdatableSortedLinkedListKilledException {
@@ -193,7 +196,7 @@
         int i=0;
         for(Enumeration e = list.elements();e.hasMoreElements();) {
             output[i++] = (UpdatableSortedLinkedListItem)e.nextElement();
-            Logger.minor(this, "["+(i-1)+"] = "+output[i-1]);
+            //Logger.minor(this, "["+(i-1)+"] = "+output[i-1]);
         }
         return output;
     }

Modified: 
trunk/freenet/src/freenet/support/UpdatableSortedLinkedListWithForeignIndex.java
===================================================================
--- 
trunk/freenet/src/freenet/support/UpdatableSortedLinkedListWithForeignIndex.java
    2005-11-15 21:10:36 UTC (rev 7543)
+++ 
trunk/freenet/src/freenet/support/UpdatableSortedLinkedListWithForeignIndex.java
    2005-11-16 14:46:11 UTC (rev 7544)
@@ -33,9 +33,9 @@
         checkList();
     }

-    public synchronized void remove(UpdatableSortedLinkedListItem item) throws 
UpdatableSortedLinkedListKilledException {
-        super.remove(item);
+    public synchronized UpdatableSortedLinkedListItem 
remove(UpdatableSortedLinkedListItem item) throws 
UpdatableSortedLinkedListKilledException {
         
map.remove(((IndexableUpdatableSortedLinkedListItem)item).indexValue());
+        return super.remove(item);
     }

     public synchronized boolean containsKey(Object o) {


Reply via email to