On Monday 20 April 2009 22:21:12 saces at freenetproject.org wrote:
> Author: saces
> Date: 2009-04-20 21:21:11 +0000 (Mon, 20 Apr 2009)
> New Revision: 27121
> 
> Modified:
>    trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
> Log:
> teach the SFI how to fetch the new metadata format 
(ARCHIVE_METADATA_REDIRECT)
> needs review

As requested ... this commit has problems...
> 
> Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
> ===================================================================
> --- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java     
> 2009-04-20 
21:16:19 UTC (rev 27120)
> +++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java     
> 2009-04-20 
21:21:11 UTC (rev 27121)
> @@ -114,7 +114,7 @@
>       /** Copy constructor, modifies a few given fields, don't call 
> schedule().
>        * Used for things like slave fetchers for MultiLevelMetadata, 
> therefore 
does not remember returnBucket,
>        * metaStrings etc. */
> -     public SingleFileFetcher(SingleFileFetcher fetcher, boolean persistent, 
boolean deleteFetchContext, Metadata newMeta, GetCompletionCallback callback, 
FetchContext ctx2, ObjectContainer container, ClientContext context) throws 
FetchException {
> +     public SingleFileFetcher(SingleFileFetcher fetcher, boolean persistent, 
boolean deleteFetchContext, Metadata newMeta, ArrayList<String> metaStrings2, 
GetCompletionCallback callback, FetchContext ctx2, ObjectContainer container, 
ClientContext context) throws FetchException {
>               // Don't add a block, we have already fetched the data, we are 
> just 
handling the metadata in a different fetcher.
>               super(persistent ? fetcher.key.cloneKey() : fetcher.key, 
fetcher.maxRetries, ctx2, fetcher.parent, callback, false, true, 
fetcher.token, container, context, deleteFetchContext);
>               if(logMINOR) Logger.minor(this, "Creating SingleFileFetcher 
for "+fetcher.key+" meta="+fetcher.metaStrings.toString(), new 
Exception("debug"));
> @@ -128,7 +128,7 @@
>               this.archiveMetadata = null;
>               this.clientMetadata = (fetcher.clientMetadata != null ? 
fetcher.clientMetadata.clone() : new ClientMetadata());
>               this.metadata = newMeta;
> -             this.metaStrings = new ArrayList<String>();
> +             this.metaStrings = metaStrings2;

This should be copied unless you can guarantee that the caller will always 
copy it unless nonpersistent.

>               this.addedMetaStrings = 0;
>               this.recursionLevel = fetcher.recursionLevel + 1;
>               if(recursionLevel > ctx.maxRecursionLevel)
> @@ -471,6 +471,83 @@
>                               }
>                               metadataBucket.free();
>                               continue;
> +                     } else if(metadata.isArchiveMetadataRedirect()) {
> +                             if(logMINOR) Logger.minor(this, "Is 
> archive-metadata");
> +                             // Fetch it from the archive
> +                             if(ah == null)
> +                                     throw new 
> FetchException(FetchException.UNKNOWN_METADATA, "Archive 
redirect not in an archive manifest");
> +                             String filename = 
> metadata.getArchiveInternalName();
> +                             if(logMINOR) Logger.minor(this, "Fetching 
> "+filename);
> +                             Bucket dataBucket = ah.get(filename, actx, 
> context.archiveManager);
> +                             if(dataBucket != null) {
> +                                     if(logMINOR) Logger.minor(this, 
> "Returning data");
> +                                     final Metadata newMetadata;
> +                                     try {
> +                                             
> +                                             newMetadata = 
> Metadata.construct(dataBucket);
> +                                             dataBucket.free();
> +                                     } catch (IOException e) {
> +                                             throw new 
> FetchException(FetchException.BUCKET_ERROR);
> +                                     }
> +                                     continueWithNewMetadata(newMetadata, 
> this.rcb, container, context);
> +                                     return;
> +                             } else {
> +                                     if(logMINOR) Logger.minor(this, 
> "Fetching archive 
(thisKey="+thisKey+ ')');
> +                                     // Metadata cannot contain pointers to 
> files which don't exist.
> +                                     // We enforce this in ArchiveHandler.
> +                                     // Therefore, the archive needs to be 
> fetched.
> +                                     final boolean persistent = 
> this.persistent;
> +                                     fetchArchive(true, archiveMetadata, 
> filename, new 
ArchiveExtractCallback() {
> +                                             public void gotBucket(Bucket 
> data, ObjectContainer container, 
ClientContext context) {
> +                                                     if(persistent)
> +                                                             
> container.activate(SingleFileFetcher.this, 1);
> +                                                     if(logMINOR) 
> Logger.minor(this, "Returning data");
> +                                                     final Metadata 
> newMetadata;
> +                                                     try {
> +                                                             
> +                                                             newMetadata = 
> Metadata.construct(data);
> +                                                             
> continueWithNewMetadata(newMetadata, SingleFileFetcher.this.rcb, 
container, context);

Here we are using the metadata we have just fetched as new metadata.
...
> @@ -576,18 +653,7 @@
>                               if(logMINOR) Logger.minor(this, "Is multi-level 
> metadata");
>                               // Fetch on a second SingleFileFetcher, like 
> with archives.
>                               metadata.setSimpleRedirect();
> -                             final SingleFileFetcher f = new 
> SingleFileFetcher(this, persistent, 
false, metadata, new MultiLevelMetadataCallback(), ctx, container, context);
> -                             // Clear our own metadata so it can be garbage 
> collected, it will be 
replaced by whatever is fetched.
> -                             // The new fetcher has our metadata so we don't 
> need to 
removeMetadata().
> -                             this.metadata = null;
> -                             if(persistent) container.store(this);
> -                             if(persistent) container.store(f);
> -                             
> -                             // We must transition to the sub-fetcher so 
> that if the request is 
cancelled, it will get deleted.
> -                             parent.onTransition(this, f, container);
> -                             
> -                             f.wrapHandleMetadata(true, container, context);
> -                             if(persistent) container.deactivate(f, 1);
> +                             continueWithNewMetadata(metadata, new 
> MultiLevelMetadataCallback(), 
container, context);

Here we are using the CURRENT metadata to fetch new metadata in order to 
unpack that metadata and use that. These are *two different operations*. The 
latter is fine, but the former is broken. What you want to do is simply 
remove the old metadata (if persistent) and set metadata to the new metadata, 
and go back around the loop.

>                               return;
>                       } else if(metadata.isSingleFileRedirect()) {
>                               if(logMINOR) Logger.minor(this, "Is single-file 
> redirect");
> @@ -768,6 +834,22 @@
>                       }
>               }
>       }
> +     
> +     private void continueWithNewMetadata(Metadata newMetadata, 
GetCompletionCallback callback, ObjectContainer container, ClientContext 
context) throws FetchException {
> +             final SingleFileFetcher f = new SingleFileFetcher(this, 
> persistent, 
false, newMetadata, metaStrings, callback, ctx, container, context);

Why do you want to pass in metaStrings? For multi-level metadata we do not 
want to pass it in. For the other case, you don't want to create a new 
SingleFileFetcher.

> +             // Clear our own metadata so it can be garbage collected, it 
> will be 
replaced by whatever is fetched.
> +             // The new fetcher has our metadata so we don't need to 
> removeMetadata().
> +             metadata = null;
> +             if(persistent) container.store(this);
> +             if(persistent) container.store(f);
> +             
> +             // We must transition to the sub-fetcher so that if the request 
> is 
cancelled, it will get deleted.
> +             parent.onTransition(this, f, container);
> +             
> +             f.wrapHandleMetadata(true, container, context);
> +             if(persistent) container.deactivate(f, 1);
> +             return;
> +     }
>  
>       private String removeMetaString() {
>               String name = metaStrings.remove(0);
> @@ -792,7 +874,7 @@
>               Metadata newMeta = (Metadata) meta.clone();
>               newMeta.setSimpleRedirect();
>               final SingleFileFetcher f;
> -             f = new SingleFileFetcher(this, persistent, true, newMeta, new 
ArchiveFetcherCallback(forData, element, callback), new FetchContext(ctx, 
FetchContext.SET_RETURN_ARCHIVES, true, null), container, context);
> +             f = new SingleFileFetcher(this, persistent, true, newMeta, new 
ArrayList<String>(), new ArchiveFetcherCallback(forData, element, callback), 
new FetchContext(ctx, FetchContext.SET_RETURN_ARCHIVES, true, null), 
container, context);

This, like the change to SingleFileFetcher's constructor, is unnecessary.

>               if(persistent) container.store(f);
>               if(logMINOR) Logger.minor(this, "fetchArchive(): "+f);
>               // Fetch the archive. The archive fetcher callback will unpack 
> it, and 
either call the element 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 835 bytes
Desc: This is a digitally signed message part.
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20090429/a9654f41/attachment.pgp>

Reply via email to