Author: toad
Date: 2007-07-21 12:42:55 +0000 (Sat, 21 Jul 2007)
New Revision: 14227

Modified:
   trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
Log:
SingleFileFetcher: Refactoring and concurrency fixes:
- handleMetadata() is synchronized, since it accesses many internal objects, 
and if we e.g. want to serialise out, we definitely don't want it running at 
the same time.
- handleMetadata() never calls itself on another object directly, always goes 
through Ticker.
- handleMetadata() is wrapped by wrapHandleMetadata(), which calls it and 
handles any resulting exceptions.
- minor bugfixes relating to whether the size is finalised (we only cleared it 
in a few places, now we clear it everywhere it needs to be cleared).

Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2007-07-21 12:29:01 UTC (rev 14226)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2007-07-21 12:42:55 UTC (rev 14227)
@@ -160,19 +160,7 @@
                                onFailure(new 
FetchException(FetchException.BUCKET_ERROR, e));
                                return;
                        }
-                       try {
-                               handleMetadata();
-                       } catch (MetadataParseException e) {
-                               onFailure(new FetchException(e));
-                               return;
-                       } catch (FetchException e) {
-                               onFailure(e);
-                               return;
-                       } catch (ArchiveFailureException e) {
-                               onFailure(new FetchException(e));
-                       } catch (ArchiveRestartException e) {
-                               onFailure(new FetchException(e));
-                       }
+                       wrapHandleMetadata(false);
                }
        }

@@ -230,7 +218,16 @@
                }
        }

-       private void handleMetadata() throws FetchException, 
MetadataParseException, ArchiveFailureException, ArchiveRestartException {
+       /**
+        * Handle the current metadata. I.e. do something with it: transition 
to a splitfile, look up a manifest, etc.
+        * LOCKING: Synchronized as it changes so many variables; if we want to 
write the structure to disk, we don't
+        * want this running at the same time.
+        * @throws FetchException
+        * @throws MetadataParseException
+        * @throws ArchiveFailureException
+        * @throws ArchiveRestartException
+        */
+       private synchronized void handleMetadata() throws FetchException, 
MetadataParseException, ArchiveFailureException, ArchiveRestartException {
                while(true) {
                        if(metadata.isSimpleManifest()) {
                                if(logMINOR) Logger.minor(this, "Is simple 
manifest");
@@ -286,18 +283,7 @@
                                                                onFailure(new 
FetchException(FetchException.BUCKET_ERROR, e));
                                                                return;
                                                        }
-                                                       try {
-                                                               
handleMetadata();
-                                                       } catch 
(MetadataParseException e) {
-                                                               
SingleFileFetcher.this.onFailure(new FetchException(e));
-                                                       } catch (FetchException 
e) {
-                                                               
e.setNotFinalizedSize();
-                                                               
SingleFileFetcher.this.onFailure(e);
-                                                       } catch 
(ArchiveFailureException e) {
-                                                               
SingleFileFetcher.this.onFailure(new FetchException(e));
-                                                       } catch 
(ArchiveRestartException e) {
-                                                               
SingleFileFetcher.this.onFailure(new FetchException(e));
-                                                       }
+                                                       
wrapHandleMetadata(true);
                                                }
                                                public void notInArchive() {
                                                        onFailure(new 
FetchException(FetchException.INTERNAL_ERROR, "No metadata in container! Cannot 
happen as ArchiveManager should synthesise some!"));
@@ -376,8 +362,12 @@
                                // Fetch on a second SingleFileFetcher, like 
with archives.
                                Metadata newMeta = (Metadata) metadata.clone();
                                newMeta.setSimpleRedirect();
-                               SingleFileFetcher f = new 
SingleFileFetcher(this, newMeta, new MultiLevelMetadataCallback(), ctx);
-                               f.handleMetadata();
+                               final SingleFileFetcher f = new 
SingleFileFetcher(this, newMeta, new MultiLevelMetadataCallback(), ctx);
+                               ctx.ticker.queueTimedJob(new Runnable() {
+                                       public void run() {
+                                               f.wrapHandleMetadata(true);
+                                       }
+                               }, 0);
                                return;
                        } else if(metadata.isSingleFileRedirect()) {
                                if(logMINOR) Logger.minor(this, "Is single-file 
redirect");
@@ -533,14 +523,37 @@
                // reschedules us.
                Metadata newMeta = (Metadata) meta.clone();
                newMeta.setSimpleRedirect();
-               SingleFileFetcher f;
+               final SingleFileFetcher f;
                f = new SingleFileFetcher(this, newMeta, new 
ArchiveFetcherCallback(forData, element, callback), new FetchContext(ctx, 
FetchContext.SET_RETURN_ARCHIVES, true));
-               f.handleMetadata();
-               // When it is done (if successful), the ArchiveCallback will 
re-call this function.
-               // Which will then discover that the metadata *is* available.
-               // And will also discover that the data is available, and will 
complete.
+               ctx.ticker.queueTimedJob(new Runnable() {
+                       public void run() {
+                               // When it is done (if successful), the 
ArchiveCallback will re-call this function.
+                               // Which will then discover that the metadata 
*is* available.
+                               // And will also discover that the data is 
available, and will complete.
+                               f.wrapHandleMetadata(true);
+                       }
+               }, 0);
        }

+       /**
+        * Call handleMetadata(), and deal with any resulting exceptions
+        */
+       private void wrapHandleMetadata(boolean notFinalizedSize) {
+               try {
+                       handleMetadata();
+               } catch (MetadataParseException e) {
+                       onFailure(new FetchException(e));
+               } catch (FetchException e) {
+                       if(notFinalizedSize)
+                               e.setNotFinalizedSize();
+                       onFailure(e);
+               } catch (ArchiveFailureException e) {
+                       onFailure(new FetchException(e));
+               } catch (ArchiveRestartException e) {
+                       onFailure(new FetchException(e));
+               }
+       }
+       
        class ArchiveFetcherCallback implements GetCompletionCallback {

                private final boolean wasFetchingFinalData;
@@ -564,18 +577,7 @@
                                return;
                        }
                        if(callback != null) return;
-                       try {
-                               handleMetadata();
-                       } catch (MetadataParseException e) {
-                               SingleFileFetcher.this.onFailure(new 
FetchException(e));
-                       } catch (FetchException e) {
-                               e.setNotFinalizedSize();
-                               SingleFileFetcher.this.onFailure(e);
-                       } catch (ArchiveFailureException e) {
-                               SingleFileFetcher.this.onFailure(new 
FetchException(e));
-                       } catch (ArchiveRestartException e) {
-                               SingleFileFetcher.this.onFailure(new 
FetchException(e));
-                       }
+                       wrapHandleMetadata(true);
                }

                public void onFailure(FetchException e, ClientGetState state) {
@@ -600,22 +602,12 @@
                public void onSuccess(FetchResult result, ClientGetState state) 
{
                        try {
                                metadata = 
Metadata.construct(result.asBucket());
-                               handleMetadata();
-                       } catch (MetadataParseException e) {
-                               SingleFileFetcher.this.onFailure(new 
FetchException(e));
-                               return;
                        } catch (IOException e) {
                                // Bucket error?
                                SingleFileFetcher.this.onFailure(new 
FetchException(FetchException.BUCKET_ERROR, e));
                                return;
-                       } catch (FetchException e) {
-                               e.setNotFinalizedSize();
-                               onFailure(e, SingleFileFetcher.this);
-                       } catch (ArchiveFailureException e) {
-                               onFailure(new 
FetchException(FetchException.ARCHIVE_FAILURE), SingleFileFetcher.this);
-                       } catch (ArchiveRestartException e) {
-                               onFailure(new 
FetchException(FetchException.ARCHIVE_RESTART), SingleFileFetcher.this);
                        }
+                       wrapHandleMetadata(true);
                }

                public void onFailure(FetchException e, ClientGetState state) {


Reply via email to