Author: toad
Date: 2008-07-29 15:27:22 +0000 (Tue, 29 Jul 2008)
New Revision: 21478

Modified:
   branches/db4o/freenet/src/freenet/clients/http/QueueToadlet.java
   branches/db4o/freenet/src/freenet/node/fcp/FCPServer.java
   branches/db4o/freenet/src/freenet/support/SimpleReadOnlyArrayBucket.java
   branches/db4o/freenet/src/freenet/support/api/Bucket.java
   branches/db4o/freenet/src/freenet/support/io/ArrayBucket.java
   branches/db4o/freenet/src/freenet/support/io/BucketChainBucket.java
   branches/db4o/freenet/src/freenet/support/io/BucketTools.java
   branches/db4o/freenet/src/freenet/support/io/DelayedFreeBucket.java
   branches/db4o/freenet/src/freenet/support/io/FileBucket.java
   branches/db4o/freenet/src/freenet/support/io/MultiReaderBucket.java
   branches/db4o/freenet/src/freenet/support/io/NullBucket.java
   
branches/db4o/freenet/src/freenet/support/io/PaddedEphemerallyEncryptedBucket.java
   branches/db4o/freenet/src/freenet/support/io/ReadOnlyFileSliceBucket.java
   branches/db4o/freenet/src/freenet/support/io/TempFileBucket.java
Log:
Shadow buckets: A solution to the activation problems on the queue page which 
doesn't (usually) involve copying to a transient bucket just to send to the 
user.

Modified: branches/db4o/freenet/src/freenet/clients/http/QueueToadlet.java
===================================================================
--- branches/db4o/freenet/src/freenet/clients/http/QueueToadlet.java    
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/clients/http/QueueToadlet.java    
2008-07-29 15:27:22 UTC (rev 21478)
@@ -32,6 +32,7 @@
 import freenet.client.FetchResult;
 import freenet.client.HighLevelSimpleClient;
 import freenet.client.MetadataUnresolvedException;
+import freenet.client.TempFetchResult;
 import freenet.client.async.ClientContext;
 import freenet.client.async.DBJob;
 import freenet.keys.FreenetURI;
@@ -418,13 +419,15 @@
                                FreenetURI key = new FreenetURI(requestPath);

                                /* locate request */
-                               FetchResult result = 
fcp.getCompletedRequestBlocking(key);
+                               TempFetchResult result = 
fcp.getCompletedRequestBlocking(key);
                                if(result != null) {
                                        Bucket data = result.asBucket();
                                        String mimeType = result.getMimeType();
                                        String requestedMimeType = 
request.getParam("type", null);
                                        String forceString = 
request.getParam("force");
                                        FProxyToadlet.handleDownload(ctx, data, 
ctx.getBucketFactory(), mimeType, requestedMimeType, forceString, 
request.isParameterSet("forcedownload"), "/queue/", key, "", "/queue/", false, 
ctx);
+                                       if(result.freeWhenDone)
+                                               data.free();
                                        return;
                                }
                        } catch (MalformedURLException mue1) {

Modified: branches/db4o/freenet/src/freenet/node/fcp/FCPServer.java
===================================================================
--- branches/db4o/freenet/src/freenet/node/fcp/FCPServer.java   2008-07-29 
14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/node/fcp/FCPServer.java   2008-07-29 
15:27:22 UTC (rev 21478)
@@ -25,6 +25,7 @@
 import freenet.client.FetchResult;
 import freenet.client.HighLevelSimpleClient;
 import freenet.client.InsertContext;
+import freenet.client.TempFetchResult;
 import freenet.client.async.ClientContext;
 import freenet.client.async.DBJob;
 import freenet.config.Config;
@@ -44,8 +45,10 @@
 import freenet.support.MutableBoolean;
 import freenet.support.OOMHandler;
 import freenet.support.api.BooleanCallback;
+import freenet.support.api.Bucket;
 import freenet.support.api.IntCallback;
 import freenet.support.api.StringCallback;
+import freenet.support.io.BucketTools;
 import freenet.support.io.Closer;
 import freenet.support.io.NativeThread;

@@ -1028,15 +1031,15 @@



-       public FetchResult getCompletedRequestBlocking(final FreenetURI key) {
+       public TempFetchResult getCompletedRequestBlocking(final FreenetURI 
key) {
                ClientGet get = globalRebootClient.getCompletedRequest(key, 
null);
                if(get != null) {
                        // FIXME race condition with free() - arrange 
refcounting for the data to prevent this
-                       return new FetchResult(new 
ClientMetadata(get.getMIMEType(null)), get.getBucket());
+                       return new TempFetchResult(new 
ClientMetadata(get.getMIMEType(null)), get.getBucket(), false);
                }

                class OutputWrapper {
-                       FetchResult result;
+                       TempFetchResult result;
                        boolean done;
                }

@@ -1045,12 +1048,33 @@
                core.clientContext.jobRunner.queue(new DBJob() {

                        public void run(ObjectContainer container, 
ClientContext context) {
-                               FetchResult result = null;
+                               TempFetchResult result = null;
                                try {
                                        ClientGet get = 
globalForeverClient.getCompletedRequest(key, container);
                                        container.activate(get, 1);
                                        if(get != null) {
-                                               result = new FetchResult(new 
ClientMetadata(get.getMIMEType(container)), get.getBucket());
+                                               Bucket origData = 
get.getBucket();
+                                               container.activate(origData, 5);
+                                               boolean copied = false;
+                                               Bucket newData;
+                                               try {
+                                                       newData = 
origData.createShadow();
+                                               } catch (IOException e) {
+                                                       Logger.error(this, 
"Caught error "+e+" trying to create shallow copy, copying data...", e);
+                                                       newData = null;
+                                               }
+                                               if(newData == null) {
+                                                       try {
+                                                               newData = 
core.tempBucketFactory.makeBucket(origData.size());
+                                                               
BucketTools.copy(origData, newData);
+                                                       } catch (IOException e) 
{
+                                                               
Logger.error(this, "Unable to copy data: "+e, e);
+                                                               result = null;
+                                                               return;
+                                                       }
+                                                       copied = true;
+                                               }
+                                               result = new 
TempFetchResult(new ClientMetadata(get.getMIMEType(container)), newData, 
copied);
                                        }
                                        container.deactivate(get, 1);
                                } finally {

Modified: 
branches/db4o/freenet/src/freenet/support/SimpleReadOnlyArrayBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/SimpleReadOnlyArrayBucket.java    
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/SimpleReadOnlyArrayBucket.java    
2008-07-29 15:27:22 UTC (rev 21478)
@@ -67,4 +67,13 @@
                container.delete(this);
        }

+       public Bucket createShadow() throws IOException {
+               if(buf.length < 256*1024) {
+                       byte[] newBuf = new byte[length];
+                       System.arraycopy(buf, offset, newBuf, 0, length);
+                       return new SimpleReadOnlyArrayBucket(newBuf);
+               }
+               return null;
+       }
+
 }

Modified: branches/db4o/freenet/src/freenet/support/api/Bucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/api/Bucket.java   2008-07-29 
14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/api/Bucket.java   2008-07-29 
15:27:22 UTC (rev 21478)
@@ -64,4 +64,14 @@
         */
        public void removeFrom(ObjectContainer container);

+       /**
+        * Create a shallow read-only copy of this bucket, using different 
+        * objects but using the same external storage. If this is not 
possible, 
+        * return null. Note that if the underlying bucket is deleted, the copy
+        * will become invalid and probably throw an IOException on read, or 
+        * possibly return too-short data etc. In some use cases e.g. on 
fproxy, 
+        * this is acceptable.
+        */
+       public Bucket createShadow() throws IOException;
+
 }

Modified: branches/db4o/freenet/src/freenet/support/io/ArrayBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/ArrayBucket.java       
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/ArrayBucket.java       
2008-07-29 15:27:22 UTC (rev 21478)
@@ -197,4 +197,8 @@
        public void removeFrom(ObjectContainer container) {
                container.delete(data);
        }
+
+       public Bucket createShadow() throws IOException {
+               return null;
+       }
 }

Modified: branches/db4o/freenet/src/freenet/support/io/BucketChainBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/BucketChainBucket.java 
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/BucketChainBucket.java 
2008-07-29 15:27:22 UTC (rev 21478)
@@ -32,6 +32,14 @@
                readOnly = false;
        }

+       private BucketChainBucket(Vector newBuckets, long bucketSize2, long 
size2, boolean readOnly, BucketFactory bf2) {
+               this.buckets = newBuckets;
+               this.bucketSize = bucketSize2;
+               this.size = size2;
+               this.readOnly = readOnly;
+               this.bf = bf2;
+       }
+
        public void free() {
                Bucket[] list;
                synchronized(this) {
@@ -292,4 +300,18 @@
                container.delete(this);
        }

+       public Bucket createShadow() throws IOException {
+               Vector newBuckets = new Vector();
+               for(int i=0;i<buckets.size();i++) {
+                       Bucket data = (Bucket) buckets.get(i);
+                       Bucket shadow = data.createShadow();
+                       if(shadow == null) {
+                               // Shadow buckets don't need to be freed.
+                               return null;
+                       }
+                       newBuckets.add(shadow);
+               }
+               return new BucketChainBucket(newBuckets, bucketSize, size, 
true, bf);
+       }
+
 }

Modified: branches/db4o/freenet/src/freenet/support/io/BucketTools.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/BucketTools.java       
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/BucketTools.java       
2008-07-29 15:27:22 UTC (rev 21478)
@@ -424,4 +424,5 @@
                        return b;
                } finally { os.close(); }
        }
+
 }

Modified: branches/db4o/freenet/src/freenet/support/io/DelayedFreeBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/DelayedFreeBucket.java 
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/DelayedFreeBucket.java 
2008-07-29 15:27:22 UTC (rev 21478)
@@ -129,6 +129,10 @@
                // Cascading activation of dependancies
                container.activate(bucket, 1);
        }
+
+       public Bucket createShadow() throws IOException {
+               return bucket.createShadow();
+       }

 //     public void objectOnDeactivate(ObjectContainer container) {
 //             if(Logger.shouldLog(Logger.MINOR, this)) Logger.minor(this, 
"Deactivating "+super.toString()+" : "+bucket, new Exception("debug"));

Modified: branches/db4o/freenet/src/freenet/support/io/FileBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/FileBucket.java        
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/FileBucket.java        
2008-07-29 15:27:22 UTC (rev 21478)
@@ -4,6 +4,7 @@
 package freenet.support.io;

 import java.io.File;
+import java.io.IOException;

 import com.db4o.ObjectContainer;

@@ -115,4 +116,10 @@
        public void objectOnActivate(ObjectContainer container) {
                container.activate(file, 5);
        }
+
+       public Bucket createShadow() throws IOException {
+               String fnam = new String(file.getPath());
+               File newFile = new File(fnam);
+               return new FileBucket(newFile, true, false, false, false, 
false);
+       }
 }

Modified: branches/db4o/freenet/src/freenet/support/io/MultiReaderBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/MultiReaderBucket.java 
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/MultiReaderBucket.java 
2008-07-29 15:27:22 UTC (rev 21478)
@@ -139,6 +139,10 @@
                        container.delete(readers);
                        container.delete(MultiReaderBucket.this);
                }
+
+               public Bucket createShadow() throws IOException {
+                       return null;
+               }

        }


Modified: branches/db4o/freenet/src/freenet/support/io/NullBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/NullBucket.java        
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/NullBucket.java        
2008-07-29 15:27:22 UTC (rev 21478)
@@ -2,6 +2,7 @@
  * Public License, version 2 (or at your option any later version). See
  * http://www.gnu.org/ for further details of the GPL. */
 package freenet.support.io;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;

@@ -80,5 +81,9 @@
        public void removeFrom(ObjectContainer container) {
                container.delete(this);
        }
+
+       public Bucket createShadow() throws IOException {
+               return new NullBucket();
+       }
 }


Modified: 
branches/db4o/freenet/src/freenet/support/io/PaddedEphemerallyEncryptedBucket.java
===================================================================
--- 
branches/db4o/freenet/src/freenet/support/io/PaddedEphemerallyEncryptedBucket.java
  2008-07-29 14:44:46 UTC (rev 21477)
+++ 
branches/db4o/freenet/src/freenet/support/io/PaddedEphemerallyEncryptedBucket.java
  2008-07-29 15:27:22 UTC (rev 21478)
@@ -123,6 +123,16 @@
                origRandom.nextBytes(randomSeed);
        }

+       public 
PaddedEphemerallyEncryptedBucket(PaddedEphemerallyEncryptedBucket orig, Bucket 
newBucket) {
+               this.dataLength = orig.dataLength;
+               this.key = new byte[orig.key.length];
+               System.arraycopy(orig.key, 0, key, 0, orig.key.length);
+               this.randomSeed = null; // Will be read-only
+               setReadOnly();
+               this.bucket = newBucket;
+               this.minPaddedSize = orig.minPaddedSize;
+       }
+
        public OutputStream getOutputStream() throws IOException {
                if(readOnly) throw new IOException("Read only");
                OutputStream os = bucket.getOutputStream();
@@ -392,4 +402,10 @@
                container.activate(bucket, 1);
        }

+       public Bucket createShadow() throws IOException {
+               Bucket newUnderlying = bucket.createShadow();
+               if(newUnderlying == null) return null;
+               return new PaddedEphemerallyEncryptedBucket(this, 
newUnderlying);
+       }
+
 }

Modified: 
branches/db4o/freenet/src/freenet/support/io/ReadOnlyFileSliceBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/ReadOnlyFileSliceBucket.java   
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/ReadOnlyFileSliceBucket.java   
2008-07-29 15:27:22 UTC (rev 21478)
@@ -161,4 +161,10 @@
                container.activate(file, 5);
        }

+       public Bucket createShadow() throws IOException {
+               String fnam = new String(file.getPath());
+               File newFile = new File(fnam);
+               return new ReadOnlyFileSliceBucket(newFile, startAt, length);
+       }
+
 }

Modified: branches/db4o/freenet/src/freenet/support/io/TempFileBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/TempFileBucket.java    
2008-07-29 14:44:46 UTC (rev 21477)
+++ branches/db4o/freenet/src/freenet/support/io/TempFileBucket.java    
2008-07-29 15:27:22 UTC (rev 21478)
@@ -1,6 +1,7 @@
 package freenet.support.io;

 import java.io.File;
+import java.io.IOException;

 import com.db4o.ObjectContainer;

@@ -96,4 +97,10 @@
                // filenameGenerator is a global, we don't need to worry about 
it.
                container.delete(this);
        }
+
+       public Bucket createShadow() throws IOException {
+               TempFileBucket ret = new TempFileBucket(filenameID, generator);
+               ret.setReadOnly();
+               return ret;
+       }
 }


Reply via email to