r27121 - trunk/freenet/src/freenet/client/async
[email protected] Mon, 20 Apr 2009 21:21:12 +0000
| Newsgroups | gmane.network.freenet.cvs |
|---|---|
| Message-ID | <[email protected]> |
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
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.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);
+ } catch (IOException e) {
+ onFailure(new FetchException(FetchException.BUCKET_ERROR), false, container, context);
+ } catch (MetadataParseException e) {
+ onFailure(new FetchException(FetchException.INVALID_METADATA), false, container, context);
+ } catch (FetchException e) {
+ onFailure(e, false, container, context);
+ } finally {
+ data.free();
+ }
+ if(persistent)
+ container.deactivate(SingleFileFetcher.this, 1);
+ }
+ public void notInArchive(ObjectContainer container, ClientContext context) {
+ if(persistent)
+ container.activate(SingleFileFetcher.this, 1);
+ onFailure(new FetchException(FetchException.NOT_IN_ARCHIVE), false, container, context);
+ if(persistent)
+ container.deactivate(SingleFileFetcher.this, 1);
+ }
+ public void onFailed(ArchiveRestartException e, ObjectContainer container, ClientContext context) {
+ if(persistent)
+ container.activate(SingleFileFetcher.this, 1);
+ SingleFileFetcher.this.onFailure(new FetchException(e), false, container, context);
+ if(persistent)
+ container.deactivate(SingleFileFetcher.this, 1);
+ }
+ public void onFailed(ArchiveFailureException e, ObjectContainer container, ClientContext context) {
+ if(persistent)
+ container.activate(SingleFileFetcher.this, 1);
+ SingleFileFetcher.this.onFailure(new FetchException(e), false, container, context);
+ if(persistent)
+ container.deactivate(SingleFileFetcher.this, 1);
+ }
+ public void removeFrom(ObjectContainer container) {
+ container.delete(this);
+ }
+ }, container, context);
+ removeMetadata(container);
+ // Will call back into this function when it has been fetched.
+ return;
+ }
} else if(metadata.isArchiveInternalRedirect()) {
if(logMINOR) Logger.minor(this, "Is archive-internal redirect");
clientMetadata.mergeNoOverwrite(metadata.getClientMetadata());
@@ -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);
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);
+ // 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);
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