Author: toad
Date: 2009-02-03 20:19:07 +0000 (Tue, 03 Feb 2009)
New Revision: 25512

Modified:
   branches/db4o/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
   branches/db4o/freenet/src/freenet/client/async/ChosenBlock.java
   
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
   branches/db4o/freenet/src/freenet/client/async/OfferedKeysList.java
   branches/db4o/freenet/src/freenet/client/async/PersistentChosenBlock.java
   branches/db4o/freenet/src/freenet/client/async/PersistentChosenRequest.java
   branches/db4o/freenet/src/freenet/client/async/SingleBlockInserter.java
   
branches/db4o/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java
   branches/db4o/freenet/src/freenet/client/async/TransientChosenBlock.java
   branches/db4o/freenet/src/freenet/node/LowLevelPutException.java
   branches/db4o/freenet/src/freenet/node/RequestStarter.java
   branches/db4o/freenet/src/freenet/node/SendableRequest.java
   branches/db4o/freenet/src/freenet/node/SimpleSendableInsert.java
Log:
SendableRequest selected request token is a SendableRequestItem, not an Object.
We call dump() on it if we drop it.
Encode at insert time in SingleBlockInserter, hence we do not need to pass 
around whole ClientCHKBlock's, which could easily cause an OOM under heavy load 
as the token stays in RAM until we process onSuccess/onFailure.
We have to take a shadow of the bucket in order to do this.


Modified: 
branches/db4o/freenet/src/freenet/client/async/BaseSingleFileFetcher.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/BaseSingleFileFetcher.java   
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/BaseSingleFileFetcher.java   
2009-02-03 20:19:07 UTC (rev 25512)
@@ -15,9 +15,11 @@
 import freenet.keys.KeyBlock;
 import freenet.keys.KeyVerifyException;
 import freenet.node.KeysFetchingLocally;
+import freenet.node.NullSendableRequestItem;
 import freenet.node.RequestClient;
 import freenet.node.RequestScheduler;
 import freenet.node.SendableGet;
+import freenet.node.SendableRequestItem;
 import freenet.support.Executor;
 import freenet.support.Logger;
 
@@ -29,7 +31,7 @@
        final int maxRetries;
        private int retryCount;
        final FetchContext ctx;
-       static final Object[] keys = new Object[] { Integer.valueOf(0) };
+       static final SendableRequestItem[] keys = new SendableRequestItem[] { 
NullSendableRequestItem.nullItem };
        /** It is essential that we know when the cooldown will end, otherwise 
we cannot 
         * remove the key from the queue if we are killed before that */
        long cooldownWakeupTime;
@@ -48,17 +50,17 @@
        }
 
        @Override
-       public Object[] allKeys(ObjectContainer container) {
+       public SendableRequestItem[] allKeys(ObjectContainer container) {
                return keys;
        }
        
        @Override
-       public Object[] sendableKeys(ObjectContainer container) {
+       public SendableRequestItem[] sendableKeys(ObjectContainer container) {
                return keys;
        }
        
        @Override
-       public Object chooseKey(KeysFetchingLocally fetching, ObjectContainer 
container, ClientContext context) {
+       public SendableRequestItem chooseKey(KeysFetchingLocally fetching, 
ObjectContainer container, ClientContext context) {
                if(persistent)
                        container.activate(key, 5);
                if(fetching.hasKey(key.getNodeKey())) return null;

Modified: branches/db4o/freenet/src/freenet/client/async/ChosenBlock.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/ChosenBlock.java     
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/ChosenBlock.java     
2009-02-03 20:19:07 UTC (rev 25512)
@@ -6,6 +6,7 @@
 import freenet.node.LowLevelPutException;
 import freenet.node.NodeClientCore;
 import freenet.node.RequestScheduler;
+import freenet.node.SendableRequestItem;
 import freenet.node.SendableRequestSender;
 
 /**
@@ -16,7 +17,7 @@
 
        /** The token indicating the key within the request to be 
fetched/inserted.
         * Meaning is entirely defined by the request. */
-       public transient final Object token;
+       public transient final SendableRequestItem token;
        /** The key to be fetched, null if not a BaseSendableGet */
        public transient final Key key;
        /** The client-layer key to be fetched, null if not a SendableGet */
@@ -25,7 +26,7 @@
        public transient final boolean cacheLocalRequests;
        public transient final boolean ignoreStore;
        
-       public ChosenBlock(Object token, Key key, ClientKey ckey, boolean 
localRequestOnly, boolean cacheLocalRequests, boolean ignoreStore, 
RequestScheduler sched) {
+       public ChosenBlock(SendableRequestItem token, Key key, ClientKey ckey, 
boolean localRequestOnly, boolean cacheLocalRequests, boolean ignoreStore, 
RequestScheduler sched) {
                this.token = token;
                this.key = key;
                this.ckey = ckey;
@@ -60,4 +61,8 @@
        }
        
        public abstract SendableRequestSender getSender(ClientContext context);
+       
+       public void onDumped() {
+               token.dump();
+       }
 }

Modified: 
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java
===================================================================
--- 
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java  
    2009-02-03 19:56:15 UTC (rev 25511)
+++ 
branches/db4o/freenet/src/freenet/client/async/ClientRequestSchedulerCore.java  
    2009-02-03 20:19:07 UTC (rev 25512)
@@ -22,6 +22,7 @@
 import freenet.node.SendableGet;
 import freenet.node.SendableInsert;
 import freenet.node.SendableRequest;
+import freenet.node.SendableRequestItem;
 import freenet.support.Logger;
 import freenet.support.PrioritizedSerialExecutor;
 import freenet.support.RandomGrabArray;
@@ -318,7 +319,7 @@
        public ChosenBlock maybeMakeChosenRequest(SendableRequest req, 
ObjectContainer container, ClientContext context) {
                if(req == null) return null;
                if(req.isEmpty(container) || req.isCancelled(container)) return 
null;
-               Object token = req.chooseKey(this, req.persistent() ? container 
: null, context);
+               SendableRequestItem token = req.chooseKey(this, 
req.persistent() ? container : null, context);
                if(token == null) {
                        return null;
                } else {

Modified: branches/db4o/freenet/src/freenet/client/async/OfferedKeysList.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/OfferedKeysList.java 
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/OfferedKeysList.java 
2009-02-03 20:19:07 UTC (rev 25512)
@@ -16,6 +16,7 @@
 import freenet.node.NodeClientCore;
 import freenet.node.RequestClient;
 import freenet.node.RequestScheduler;
+import freenet.node.SendableRequestItem;
 import freenet.node.SendableRequestSender;
 import freenet.node.NodeClientCore.SimpleRequestSenderCompletionListener;
 import freenet.support.Logger;
@@ -71,19 +72,29 @@
        }
 
        @Override
-       public Object[] allKeys(ObjectContainer container) {
+       public SendableRequestItem[] allKeys(ObjectContainer container) {
                // Not supported.
                throw new UnsupportedOperationException();
        }
 
        @Override
-       public Object[] sendableKeys(ObjectContainer container) {
+       public SendableRequestItem[] sendableKeys(ObjectContainer container) {
                // Not supported.
                throw new UnsupportedOperationException();
        }
 
+       private class MySendableRequestItem implements SendableRequestItem {
+               final Key key;
+               MySendableRequestItem(Key key) {
+                       this.key = key;
+               }
+               public void dump() {
+                       // Ignore, we will be GC'ed
+               }
+       }
+       
        @Override
-       public synchronized Object chooseKey(KeysFetchingLocally fetching, 
ObjectContainer container, ClientContext context) {
+       public synchronized SendableRequestItem chooseKey(KeysFetchingLocally 
fetching, ObjectContainer container, ClientContext context) {
                assert(keysList.size() == keys.size());
                if(keys.size() == 1) {
                        // Shortcut the common case
@@ -91,7 +102,7 @@
                        if(fetching.hasKey(k)) return null;
                        keys.remove(k);
                        keysList.setSize(0);
-                       return k;
+                       return new MySendableRequestItem(k);
                }
                for(int i=0;i<10;i++) {
                        // Pick a random key
@@ -104,7 +115,7 @@
                        keysList.setSize(keysList.size()-1);
                        keys.remove(k);
                        assert(keysList.size() == keys.size());
-                       return k;
+                       return new MySendableRequestItem(k);
                }
                return null;
        }
@@ -160,7 +171,7 @@
                return new SendableRequestSender() {
 
                        public boolean send(NodeClientCore core, 
RequestScheduler sched, ClientContext context, ChosenBlock req) {
-                               Key key = (Key) req.token;
+                               Key key = ((MySendableRequestItem) 
req.token).key;
                                // Have to cache it in order to propagate it; 
FIXME
                                // Don't let a node force us to start a real 
request for a specific key.
                                // We check the datastore, take up offers if 
any (on a short timeout), and then quit if we still haven't fetched the data.

Modified: 
branches/db4o/freenet/src/freenet/client/async/PersistentChosenBlock.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/PersistentChosenBlock.java   
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/PersistentChosenBlock.java   
2009-02-03 20:19:07 UTC (rev 25512)
@@ -7,6 +7,7 @@
 import freenet.node.NodeClientCore;
 import freenet.node.RequestScheduler;
 import freenet.node.SendableGet;
+import freenet.node.SendableRequestItem;
 import freenet.node.SendableRequestSender;
 import freenet.support.Logger;
 
@@ -32,7 +33,7 @@
        /** If a SendableInsert failed, failedPut will be set to the exception 
generated. Cannot be null if it failed. */
        private LowLevelPutException failedPut;
        
-       public PersistentChosenBlock(boolean isInsert, PersistentChosenRequest 
parent, Object token, Key key, ClientKey ckey, RequestScheduler sched) {
+       public PersistentChosenBlock(boolean isInsert, PersistentChosenRequest 
parent, SendableRequestItem token, Key key, ClientKey ckey, RequestScheduler 
sched) {
                super(token, key, ckey, parent.localRequestOnly, 
parent.cacheLocalRequests, parent.ignoreStore, sched);
                this.isInsert = isInsert;
                this.parent = parent;

Modified: 
branches/db4o/freenet/src/freenet/client/async/PersistentChosenRequest.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/PersistentChosenRequest.java 
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/PersistentChosenRequest.java 
2009-02-03 20:19:07 UTC (rev 25512)
@@ -242,10 +242,14 @@
                        Logger.minor(this, "Dumping "+this);
                scheduler.removeRunningRequest(request);
                boolean wasStarted;
+               PersistentChosenBlock[] blocks;
                synchronized(this) {
+                       blocks = blocksNotStarted.toArray(new 
PersistentChosenBlock[blocksNotStarted.size()]);
                        blocksNotStarted.clear();
                        wasStarted = !blocksStarted.isEmpty();
                }
+               for(PersistentChosenBlock block : blocks)
+                       block.onDumped();
                if(!wasStarted) {
                        if(logMINOR) Logger.minor(this, "Finishing immediately 
in onDumped() as nothing pending: "+this);
                        finish(container, core.sched.clientContext, true, 
reqAlreadyActive);

Modified: 
branches/db4o/freenet/src/freenet/client/async/SingleBlockInserter.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/SingleBlockInserter.java     
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/SingleBlockInserter.java     
2009-02-03 20:19:07 UTC (rev 25512)
@@ -23,9 +23,11 @@
 import freenet.node.KeysFetchingLocally;
 import freenet.node.LowLevelPutException;
 import freenet.node.NodeClientCore;
+import freenet.node.NullSendableRequestItem;
 import freenet.node.RequestClient;
 import freenet.node.RequestScheduler;
 import freenet.node.SendableInsert;
+import freenet.node.SendableRequestItem;
 import freenet.node.SendableRequestSender;
 import freenet.support.Logger;
 import freenet.support.SimpleFieldSet;
@@ -92,30 +94,30 @@
                        container.activate(uri, 1);
                        container.activate(sourceData, 1);
                }
+               try {
+                       return innerEncode(random, uri, sourceData, isMetadata, 
compressionCodec, sourceLength);
+               } catch (CHKEncodeException e) {
+                       Logger.error(SingleBlockInserter.class, "Caught "+e, e);
+                       throw new 
InsertException(InsertException.INTERNAL_ERROR, e, null);
+               } catch (MalformedURLException e) {
+                       throw new InsertException(InsertException.INVALID_URI, 
e, null);
+               } catch (IOException e) {
+                       Logger.error(SingleBlockInserter.class, "Caught "+e+" 
encoding data "+sourceData, e);
+                       throw new InsertException(InsertException.BUCKET_ERROR, 
e, null);
+               } catch (SSKEncodeException e) {
+                       Logger.error(SingleBlockInserter.class, "Caught "+e, e);
+                       throw new 
InsertException(InsertException.INTERNAL_ERROR, e, null);
+               }
+                       
+       }
+       
+       protected static ClientKeyBlock innerEncode(RandomSource random, 
FreenetURI uri, Bucket sourceData, boolean isMetadata, short compressionCodec, 
int sourceLength) throws InsertException, CHKEncodeException, IOException, 
SSKEncodeException, MalformedURLException {
                String uriType = uri.getKeyType();
                if(uriType.equals("CHK")) {
-                       try {
-                               return ClientCHKBlock.encode(sourceData, 
isMetadata, compressionCodec == -1, compressionCodec, sourceLength);
-                       } catch (CHKEncodeException e) {
-                               Logger.error(this, "Caught "+e, e);
-                               throw new 
InsertException(InsertException.INTERNAL_ERROR, e, null);
-                       } catch (IOException e) {
-                               Logger.error(this, "Caught "+e+" encoding data 
"+sourceData, e);
-                               throw new 
InsertException(InsertException.BUCKET_ERROR, e, null);
-                       }
+                       return ClientCHKBlock.encode(sourceData, isMetadata, 
compressionCodec == -1, compressionCodec, sourceLength);
                } else if(uriType.equals("SSK") || uriType.equals("KSK")) {
-                       try {
-                               InsertableClientSSK ik = 
InsertableClientSSK.create(uri);
-                               return ik.encode(sourceData, isMetadata, 
compressionCodec == -1, compressionCodec, sourceLength, random);
-                       } catch (MalformedURLException e) {
-                               throw new 
InsertException(InsertException.INVALID_URI, e, null);
-                       } catch (SSKEncodeException e) {
-                               Logger.error(this, "Caught "+e, e);
-                               throw new 
InsertException(InsertException.INTERNAL_ERROR, e, null);
-                       } catch (IOException e) {
-                               Logger.error(this, "Caught "+e, e);
-                               throw new 
InsertException(InsertException.BUCKET_ERROR, e, null);
-                       }
+                       InsertableClientSSK ik = 
InsertableClientSSK.create(uri);
+                       return ik.encode(sourceData, isMetadata, 
compressionCodec == -1, compressionCodec, sourceLength, random);
                } else {
                        throw new InsertException(InsertException.INVALID_URI, 
"Unknown keytype "+uriType, null);
                }
@@ -395,7 +397,21 @@
                                // Ignore keyNum, key, since we're only sending 
one block.
                                try {
                                        if(logMINOR) Logger.minor(this, 
"Starting request: "+SingleBlockInserter.this);
-                                       ClientKeyBlock b = (ClientKeyBlock) 
req.token;
+                                       BlockItem block = (BlockItem) req.token;
+                                       ClientKeyBlock b;
+                                       try {
+                                               b = innerEncode(context.random, 
block.uri, block.copyBucket, block.isMetadata, block.compressionCodec, 
block.sourceLength);
+                                       } catch (CHKEncodeException e) {
+                                               throw new 
LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + 
e.getMessage(), e);
+                                       } catch (SSKEncodeException e) {
+                                               throw new 
LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + 
e.getMessage(), e);
+                                       } catch (MalformedURLException e) {
+                                               throw new 
LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + 
e.getMessage(), e);
+                                       } catch (InsertException e) {
+                                               throw new 
LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + 
e.getMessage(), e);
+                                       } catch (IOException e) {
+                                               throw new 
LowLevelPutException(LowLevelPutException.INTERNAL_ERROR, e.toString() + ":" + 
e.getMessage(), e);
+                                       }
                                        if(b != null)
                                                core.realPut(b, 
req.cacheLocalRequests);
                                        else {
@@ -448,36 +464,107 @@
        }
 
        @Override
-       public synchronized Object[] sendableKeys(ObjectContainer container) {
+       public synchronized SendableRequestItem[] sendableKeys(ObjectContainer 
container) {
                if(finished)
-                       return new Object[] {};
+                       return new SendableRequestItem[] {};
                else
-                       return new Object[] { Integer.valueOf(0) };
+                       return new SendableRequestItem[] { 
NullSendableRequestItem.nullItem };
        }
 
        @Override
-       public synchronized Object[] allKeys(ObjectContainer container) {
+       public synchronized SendableRequestItem[] allKeys(ObjectContainer 
container) {
                return sendableKeys(container);
        }
 
        @Override
-       public synchronized Object chooseKey(KeysFetchingLocally ignored, 
ObjectContainer container, ClientContext context) {
+       public synchronized SendableRequestItem chooseKey(KeysFetchingLocally 
ignored, ObjectContainer container, ClientContext context) {
                if(finished) return null;
-               // Ignore KeysFetchingLocally, it's for requests.
-               Object ret = getBlock(container, context, false);
                if(!persistent) {
-                       if(ignored.hasTransientInsert(this, ret))
+                       if(ignored.hasTransientInsert(this, new 
FakeBlockItem()))
                                return null;
                }
-               return ret;
+               return getBlockItem(container, context);
        }
 
+       private BlockItem getBlockItem(ObjectContainer container, ClientContext 
context) {
+               try {
+                       return new BlockItem(this, sourceData, isMetadata, 
compressionCodec, sourceLength, uri, hashCode());
+               } catch (IOException e) {
+                       fail(new InsertException(InsertException.BUCKET_ERROR, 
e, null), container, context);
+                       return null;
+               }
+       }
+       
        @Override
        public List<PersistentChosenBlock> makeBlocks(PersistentChosenRequest 
request, RequestScheduler sched, ObjectContainer container, ClientContext 
context) {
-               ClientKeyBlock encoded = getBlock(container, context, false);
-               if(encoded == null) return null;
-               PersistentChosenBlock block = new PersistentChosenBlock(true, 
request, encoded, null, null, sched);
+               BlockItem item = getBlockItem(container, context);
+               if(item == null) return null;
+               PersistentChosenBlock block = new PersistentChosenBlock(true, 
request, item, null, null, sched);
                return Collections.singletonList(block);
        }
 
+       private static class BlockItem implements SendableRequestItem {
+               
+               private final Bucket copyBucket;
+               private final boolean isMetadata;
+               private final short compressionCodec;
+               private final int sourceLength;
+               private final FreenetURI uri;
+               private final int hashCode;
+               /** STRICTLY for purposes of equals() !!! */
+               private final SingleBlockInserter parent;
+               
+               BlockItem(SingleBlockInserter parent, Bucket bucket, boolean 
meta, short codec, int srclen, FreenetURI u, int hashCode) throws IOException {
+                       this.parent = parent;
+                       this.copyBucket = bucket.createShadow();
+                       this.isMetadata = meta;
+                       this.compressionCodec = codec;
+                       this.sourceLength = srclen;
+                       this.uri = u;
+                       this.hashCode = hashCode;
+               }
+               
+               public void dump() {
+                       copyBucket.free();
+               }
+               
+               public int hashCode() {
+                       return hashCode;
+               }
+               
+               public boolean equals(Object o) {
+                       if(o instanceof BlockItem) {
+                               if(((BlockItem)o).parent == parent) return true;
+                       } else if(o instanceof FakeBlockItem) {
+                               if(((FakeBlockItem)o).getParent() == parent) 
return true;
+                       }
+                       return false;
+               }
+               
+       }
+       
+       // Used for testing whether a block is already queued.
+       private class FakeBlockItem implements SendableRequestItem {
+               
+               public void dump() {
+                       // Do nothing
+               }
+               
+               public SingleBlockInserter getParent() {
+                       return SingleBlockInserter.this;
+               }
+
+               public int hashCode() {
+                       return SingleBlockInserter.this.hashCode();
+               }
+               
+               public boolean equals(Object o) {
+                       if(o instanceof BlockItem) {
+                               if(((BlockItem)o).parent == 
SingleBlockInserter.this) return true;
+                       } else if(o instanceof FakeBlockItem) {
+                               if(((FakeBlockItem)o).getParent() == 
SingleBlockInserter.this) return true;
+                       }
+                       return false;
+               }
+       }
 }

Modified: 
branches/db4o/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java
===================================================================
--- 
branches/db4o/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java  
    2009-02-03 19:56:15 UTC (rev 25511)
+++ 
branches/db4o/freenet/src/freenet/client/async/SplitFileFetcherSubSegment.java  
    2009-02-03 20:19:07 UTC (rev 25512)
@@ -26,6 +26,7 @@
 import freenet.node.RequestClient;
 import freenet.node.RequestScheduler;
 import freenet.node.SendableGet;
+import freenet.node.SendableRequestItem;
 import freenet.node.SupportsBulkCallFailure;
 import freenet.support.Logger;
 import freenet.support.api.Bucket;
@@ -82,7 +83,7 @@
        }
 
        @Override
-       public Object chooseKey(KeysFetchingLocally keys, ObjectContainer 
container, ClientContext context) {
+       public SendableRequestItem chooseKey(KeysFetchingLocally keys, 
ObjectContainer container, ClientContext context) {
                if(cancelled) return null;
                return getRandomBlockNum(keys, context, container);
        }
@@ -118,7 +119,7 @@
         * those on cooldown queues. This is important when unregistering.
         */
        @Override
-       public Object[] allKeys(ObjectContainer container) {
+       public SendableRequestItem[] allKeys(ObjectContainer container) {
                if(persistent) {
                        container.activate(this, 1);
                        container.activate(segment, 1);
@@ -126,22 +127,29 @@
                // j16sdiz (22-DEC-2008):
                // ClientRequestSchedular.removePendingKeys() call this to get 
a list of request to be removed
                // FIXME ClientRequestSchedular.removePendingKeys() is leaking, 
what's missing here?
-               return segment.getKeyNumbersAtRetryLevel(retryCount);
+               return 
convertIntegerToMySendableRequestItems(segment.getKeyNumbersAtRetryLevel(retryCount));
        }
        
        /**
         * Just those keys which are eligible to be started now.
         */
        @Override
-       public Object[] sendableKeys(ObjectContainer container) {
+       public SendableRequestItem[] sendableKeys(ObjectContainer container) {
                if(persistent) {
                        container.activate(this, 1);
                        container.activate(blockNums, 1);
                }
                cleanBlockNums(container);
-               return blockNums.toArray();
+               return 
convertIntegerToMySendableRequestItems((Integer[])blockNums.toArray());
        }
        
+       private SendableRequestItem[] 
convertIntegerToMySendableRequestItems(Integer[] nums) {
+               SendableRequestItem[] wrapped = new 
SendableRequestItem[nums.length];
+               for(int i=0;i<nums.length;i++)
+                       wrapped[i] = new MySendableRequestItem(nums[i]);
+               return wrapped;
+       }
+
        private void cleanBlockNums(ObjectContainer container) {
                synchronized(segment) {
                        int initSize = blockNums.size();
@@ -160,7 +168,7 @@
                }
        }
 
-       private Object getRandomBlockNum(KeysFetchingLocally keys, 
ClientContext context, ObjectContainer container) {
+       private SendableRequestItem getRandomBlockNum(KeysFetchingLocally keys, 
ClientContext context, ObjectContainer container) {
                if(persistent) {
                        container.activate(this, 1);
                        container.activate(blockNums, 1);
@@ -194,11 +202,21 @@
                                }
                                if(logMINOR)
                                        Logger.minor(this, "Removing block 
"+x+" of "+(blockNums.size()+1)+ " : "+ret+ " on "+this);
-                               return ret;
+                               return new MySendableRequestItem(num);
                        }
                        return null;
                }
        }
+       
+       private class MySendableRequestItem implements SendableRequestItem {
+               final int x;
+               MySendableRequestItem(int x) {
+                       this.x = x;
+               }
+               public void dump() {
+                       // Ignore, we will be GC'ed
+               }
+       }
 
        @Override
        public boolean hasValidKeys(KeysFetchingLocally keys, ObjectContainer 
container, ClientContext context) {
@@ -865,7 +883,7 @@
                        }
                        key = key.cloneKey();
                        Key k = key.getNodeKey();
-                       PersistentChosenBlock block = new 
PersistentChosenBlock(false, request, blockNumber, k, key, sched);
+                       PersistentChosenBlock block = new 
PersistentChosenBlock(false, request, new MySendableRequestItem(blockNumber), 
k, key, sched);
                        if(logMINOR) Logger.minor(this, "Created block 
"+block+" for block number "+blockNumber+" on "+this);
                        blocks.add(block);
                }

Modified: 
branches/db4o/freenet/src/freenet/client/async/TransientChosenBlock.java
===================================================================
--- branches/db4o/freenet/src/freenet/client/async/TransientChosenBlock.java    
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/client/async/TransientChosenBlock.java    
2009-02-03 20:19:07 UTC (rev 25512)
@@ -9,6 +9,7 @@
 import freenet.node.SendableGet;
 import freenet.node.SendableInsert;
 import freenet.node.SendableRequest;
+import freenet.node.SendableRequestItem;
 import freenet.node.SendableRequestSender;
 
 /**
@@ -21,7 +22,7 @@
        public final SendableRequest request;
        public final RequestScheduler sched;
 
-       public TransientChosenBlock(SendableRequest req, Object token, Key key, 
ClientKey ckey, 
+       public TransientChosenBlock(SendableRequest req, SendableRequestItem 
token, Key key, ClientKey ckey, 
                        boolean localRequestOnly, boolean cacheLocalRequests, 
boolean ignoreStore, RequestScheduler sched) {
                super(token, key, ckey, localRequestOnly, cacheLocalRequests, 
ignoreStore, sched);
                this.request = req;

Modified: branches/db4o/freenet/src/freenet/node/LowLevelPutException.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/LowLevelPutException.java    
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/node/LowLevelPutException.java    
2009-02-03 20:19:07 UTC (rev 25512)
@@ -38,7 +38,7 @@
                
        }
        
-       LowLevelPutException(int code, String message, Throwable t) {
+       public LowLevelPutException(int code, String message, Throwable t) {
                super(message, t);
                this.code = code;
        }

Modified: branches/db4o/freenet/src/freenet/node/RequestStarter.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/RequestStarter.java  2009-02-03 
19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/node/RequestStarter.java  2009-02-03 
20:19:07 UTC (rev 25512)
@@ -181,14 +181,19 @@
 
        private boolean startRequest(ChosenBlock req, boolean logMINOR) {
                if((!req.isPersistent()) && req.isCancelled()) {
+                       req.onDumped();
                        return false;
                }
                if(req.key != null) {
-                       if(!sched.addToFetching(req.key))
+                       if(!sched.addToFetching(req.key)) {
+                               req.onDumped();
                                return false;
+                       }
                } else if((!req.isPersistent()) && 
((TransientChosenBlock)req).request instanceof SendableInsert) {
-                       
if(!sched.addTransientInsertFetching((SendableInsert)(((TransientChosenBlock)req).request),
 req.token))
+                       
if(!sched.addTransientInsertFetching((SendableInsert)(((TransientChosenBlock)req).request),
 req.token)) {
+                               req.onDumped();
                                return false;
+                       }
                }
                if(logMINOR) Logger.minor(this, "Running request "+req+" 
priority "+req.getPriority());
                core.getExecutor().execute(new SenderThread(req, req.key), 
"RequestStarter$SenderThread for "+req);

Modified: branches/db4o/freenet/src/freenet/node/SendableRequest.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/SendableRequest.java 2009-02-03 
19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/node/SendableRequest.java 2009-02-03 
20:19:07 UTC (rev 25512)
@@ -48,15 +48,15 @@
         * (but not the key itself, implementors must have a separate queue of 
block 
         * numbers and mapping of block numbers to keys).
         * @return An object identifying a specific key. null indicates no keys 
available. */
-       public abstract Object chooseKey(KeysFetchingLocally keys, 
ObjectContainer container, ClientContext context);
+       public abstract SendableRequestItem chooseKey(KeysFetchingLocally keys, 
ObjectContainer container, ClientContext context);
        
        /** All key identifiers. Including those not currently eligible to be 
sent because 
         * they are on a cooldown queue, requests for them are in progress, 
etc. */
-       public abstract Object[] allKeys(ObjectContainer container);
+       public abstract SendableRequestItem[] allKeys(ObjectContainer 
container);
 
        /** All key identifiers currently eligible to be sent. Does not include 
those 
         * currently running, on the cooldown queue etc. */
-       public abstract Object[] sendableKeys(ObjectContainer container);
+       public abstract SendableRequestItem[] sendableKeys(ObjectContainer 
container);
 
        /**
         * Get or create a SendableRequestSender for this object. This is a 
non-persistent

Modified: branches/db4o/freenet/src/freenet/node/SimpleSendableInsert.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/SimpleSendableInsert.java    
2009-02-03 19:56:15 UTC (rev 25511)
+++ branches/db4o/freenet/src/freenet/node/SimpleSendableInsert.java    
2009-02-03 20:19:07 UTC (rev 25512)
@@ -141,23 +141,31 @@
                return false;
        }
 
+       private static SendableRequestItem nullItem = new SendableRequestItem() 
{
+
+               public void dump() {
+                       // No problem
+               }
+               
+       };
+       
        @Override
-       public synchronized Object[] allKeys(ObjectContainer container) {
-               if(finished) return new Object[] {};
-               return new Object[] { 0 };
+       public synchronized SendableRequestItem[] allKeys(ObjectContainer 
container) {
+               if(finished) return new SendableRequestItem[] {};
+               return new SendableRequestItem[] { 
NullSendableRequestItem.nullItem };
        }
 
        @Override
-       public synchronized Object[] sendableKeys(ObjectContainer container) {
-               if(finished) return new Object[] {};
-               return new Object[] { 0 };
+       public synchronized SendableRequestItem[] sendableKeys(ObjectContainer 
container) {
+               if(finished) return new SendableRequestItem[] {};
+               return new SendableRequestItem[] { 
NullSendableRequestItem.nullItem };
        }
 
        @Override
-       public synchronized Object chooseKey(KeysFetchingLocally keys, 
ObjectContainer container, ClientContext context) {
+       public synchronized SendableRequestItem chooseKey(KeysFetchingLocally 
keys, ObjectContainer container, ClientContext context) {
                if(finished) return null;
                else
-                       return 0;
+                       return NullSendableRequestItem.nullItem;
        }
 
        public boolean isSSK() {

_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs

Reply via email to