Author: toad
Date: 2007-02-15 19:40:47 +0000 (Thu, 15 Feb 2007)
New Revision: 11803
Added:
trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
Modified:
trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
trunk/freenet/src/freenet/keys/FreenetURI.java
trunk/freenet/src/freenet/node/SendableRequest.java
Log:
SimpleSingleFileFetcher: Fetch a single block. Much simpler and smaller than
SingleFileFetcher, which is now its subclass. Should save significant memory
when lots of requests queued.
Added: trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
(rev 0)
+++ trunk/freenet/src/freenet/client/async/SimpleSingleFileFetcher.java
2007-02-15 19:40:47 UTC (rev 11803)
@@ -0,0 +1,139 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.client.async;
+
+import java.io.IOException;
+
+import freenet.client.ClientMetadata;
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.client.FetcherContext;
+import freenet.keys.ClientKey;
+import freenet.keys.ClientKeyBlock;
+import freenet.keys.KeyDecodeException;
+import freenet.node.LowLevelGetException;
+import freenet.support.Logger;
+import freenet.support.api.Bucket;
+
+/**
+ * Fetch a single block file.
+ * Used by SplitFileFetcherSegment.
+ */
+public class SimpleSingleFileFetcher extends BaseSingleFileFetcher implements
ClientGetState {
+
+ SimpleSingleFileFetcher(ClientKey key, int maxRetries, FetcherContext
ctx, BaseClientGetter parent, GetCompletionCallback rcb, boolean isEssential) {
+ super(key, maxRetries, ctx, parent);
+ this.rcb = rcb;
+ if(isEssential)
+ parent.addMustSucceedBlocks(1);
+ }
+
+ final GetCompletionCallback rcb;
+
+ // Translate it, then call the real onFailure
+ public void onFailure(LowLevelGetException e) {
+ switch(e.code) {
+ case LowLevelGetException.DATA_NOT_FOUND:
+ onFailure(new
FetchException(FetchException.DATA_NOT_FOUND));
+ return;
+ case LowLevelGetException.DATA_NOT_FOUND_IN_STORE:
+ onFailure(new
FetchException(FetchException.DATA_NOT_FOUND));
+ return;
+ case LowLevelGetException.DECODE_FAILED:
+ onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR));
+ return;
+ case LowLevelGetException.INTERNAL_ERROR:
+ onFailure(new
FetchException(FetchException.INTERNAL_ERROR));
+ return;
+ case LowLevelGetException.REJECTED_OVERLOAD:
+ onFailure(new
FetchException(FetchException.REJECTED_OVERLOAD));
+ return;
+ case LowLevelGetException.ROUTE_NOT_FOUND:
+ onFailure(new
FetchException(FetchException.ROUTE_NOT_FOUND));
+ return;
+ case LowLevelGetException.TRANSFER_FAILED:
+ onFailure(new
FetchException(FetchException.TRANSFER_FAILED));
+ return;
+ case LowLevelGetException.VERIFY_FAILED:
+ onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR));
+ return;
+ case LowLevelGetException.CANCELLED:
+ onFailure(new FetchException(FetchException.CANCELLED));
+ return;
+ default:
+ Logger.error(this, "Unknown LowLevelGetException code:
"+e.code);
+ onFailure(new
FetchException(FetchException.INTERNAL_ERROR));
+ return;
+ }
+ }
+
+ final void onFailure(FetchException e) {
+ onFailure(e, false);
+ }
+
+ // Real onFailure
+ protected void onFailure(FetchException e, boolean forceFatal) {
+ if(parent.isCancelled() || cancelled) {
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Failing: cancelled");
+ e = new FetchException(FetchException.CANCELLED);
+ forceFatal = true;
+ }
+ if(!(e.isFatal() || forceFatal) ) {
+ if(retry()) return;
+ }
+ // :(
+ if(e.isFatal() || forceFatal)
+ parent.fatallyFailedBlock();
+ else
+ parent.failedBlock();
+ rcb.onFailure(e, this);
+ }
+
+ /** Will be overridden by SingleFileFetcher */
+ protected void onSuccess(FetchResult data) {
+ if(parent.isCancelled()) {
+ data.asBucket().free();
+ onFailure(new FetchException(FetchException.CANCELLED));
+ return;
+ }
+ rcb.onSuccess(data, this);
+ }
+
+ public void onSuccess(ClientKeyBlock block, boolean fromStore) {
+ Bucket data = extract(block);
+ if(data == null) return; // failed
+ if(!block.isMetadata()) {
+ onSuccess(new FetchResult((ClientMetadata)null, data));
+ } else {
+ onFailure(new
FetchException(FetchException.INVALID_METADATA, "Metadata where expected
data"));
+ }
+ }
+
+ /** Convert a ClientKeyBlock to a Bucket. If an error occurs, report it
via onFailure
+ * and return null.
+ */
+ protected Bucket extract(ClientKeyBlock block) {
+ Bucket data;
+ try {
+ data = block.decode(ctx.bucketFactory,
(int)(Math.min(ctx.maxOutputLength, Integer.MAX_VALUE)), false);
+ } catch (KeyDecodeException e1) {
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Decode failure: "+e1, e1);
+ onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR, e1.getMessage()));
+ return null;
+ } catch (IOException e) {
+ Logger.error(this, "Could not capture data - disk
full?: "+e, e);
+ onFailure(new
FetchException(FetchException.BUCKET_ERROR, e));
+ return null;
+ }
+ return data;
+ }
+
+ /** getToken() is not supported */
+ public Object getToken() {
+ throw new UnsupportedOperationException();
+ }
+
+}
Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
2007-02-15 17:52:36 UTC (rev 11802)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
2007-02-15 19:40:47 UTC (rev 11803)
@@ -23,16 +23,14 @@
import freenet.keys.ClientKeyBlock;
import freenet.keys.ClientSSK;
import freenet.keys.FreenetURI;
-import freenet.keys.KeyDecodeException;
import freenet.keys.USK;
-import freenet.node.LowLevelGetException;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.compress.CompressionOutputSizeException;
import freenet.support.compress.Compressor;
import freenet.support.io.BucketTools;
-public class SingleFileFetcher extends BaseSingleFileFetcher implements
ClientGetState {
+public class SingleFileFetcher extends SimpleSingleFileFetcher implements
ClientGetState {
private static boolean logMINOR;
/** Original URI */
@@ -42,7 +40,6 @@
/** Number of metaStrings which were added by redirects etc. They are
added to the start, so this is decremented
* when we consume one. */
private int addedMetaStrings;
- final GetCompletionCallback rcb;
final ClientMetadata clientMetadata;
private Metadata metadata;
private Metadata archiveMetadata;
@@ -68,7 +65,7 @@
ArchiveContext actx, int maxRetries, int recursionLevel,
boolean dontTellClientGet, Object token, boolean
isEssential,
Bucket returnBucket, boolean isFinal) throws
FetchException {
- super(key, maxRetries, ctx, get);
+ super(key, maxRetries, ctx, get, cb, isEssential);
logMINOR = Logger.shouldLog(Logger.MINOR, this);
if(logMINOR) Logger.minor(this, "Creating SingleFileFetcher for
"+key+" from "+origURI+" meta="+metaStrings.toString(), new Exception("debug"));
this.isFinal = isFinal;
@@ -81,7 +78,6 @@
//metaStrings = uri.listMetaStrings();
this.metaStrings = metaStrings;
this.addedMetaStrings = addedMetaStrings;
- this.rcb = cb;
this.clientMetadata = metadata;
thisKey = key.getURI();
this.uri = origURI;
@@ -91,15 +87,13 @@
throw new
FetchException(FetchException.TOO_MUCH_RECURSION, "Too much recursion:
"+recursionLevel+" > "+ctx.maxRecursionLevel);
this.decompressors = new LinkedList();
parent.addBlock();
- if(isEssential)
- parent.addMustSucceedBlocks(1);
}
/** 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, Metadata newMeta,
GetCompletionCallback callback, FetcherContext ctx2) throws FetchException {
- super(fetcher.key, fetcher.maxRetries, ctx2, fetcher.parent);
+ super(fetcher.key, fetcher.maxRetries, ctx2, fetcher.parent,
callback, false);
logMINOR = Logger.shouldLog(Logger.MINOR, this);
if(logMINOR) Logger.minor(this, "Creating SingleFileFetcher for
"+fetcher.key+" meta="+fetcher.metaStrings.toString(), new Exception("debug"));
this.token = fetcher.token;
@@ -113,7 +107,6 @@
this.metadata = newMeta;
this.metaStrings = new LinkedList();
this.addedMetaStrings = 0;
- this.rcb = callback;
this.recursionLevel = fetcher.recursionLevel + 1;
if(recursionLevel > ctx.maxRecursionLevel)
throw new
FetchException(FetchException.TOO_MUCH_RECURSION);
@@ -127,19 +120,8 @@
public void onSuccess(ClientKeyBlock block, boolean fromStore) {
parent.completedBlock(fromStore);
// Extract data
- Bucket data;
- try {
- data = block.decode(ctx.bucketFactory,
(int)(Math.min(ctx.maxOutputLength, Integer.MAX_VALUE)), false);
- } catch (KeyDecodeException e1) {
- if(logMINOR)
- Logger.minor(this, "Decode failure: "+e1, e1);
- onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR, e1.getMessage()));
- return;
- } catch (IOException e) {
- Logger.error(this, "Could not capture data - disk
full?: "+e, e);
- onFailure(new
FetchException(FetchException.BUCKET_ERROR, e));
- return;
- }
+ Bucket data = extract(block);
+ if(data == null) return; // failed
if(!block.isMetadata()) {
onSuccess(new FetchResult(clientMetadata, data));
} else {
@@ -182,7 +164,7 @@
}
}
- private void onSuccess(FetchResult result) {
+ protected void onSuccess(FetchResult result) {
if(parent.isCancelled()) {
result.asBucket().free();
onFailure(new FetchException(FetchException.CANCELLED));
@@ -544,69 +526,6 @@
}
- final void onFailure(FetchException e) {
- onFailure(e, false);
- }
-
- // Real onFailure
- protected void onFailure(FetchException e, boolean forceFatal) {
- if(parent.isCancelled() || cancelled) {
- if(logMINOR) Logger.minor(this, "Failing: cancelled");
- e = new FetchException(FetchException.CANCELLED);
- forceFatal = true;
- }
- if(!(e.isFatal() || forceFatal) ) {
- if(retry()) return;
- }
- // :(
- if(e.isFatal() || forceFatal)
- parent.fatallyFailedBlock();
- else
- parent.failedBlock();
- rcb.onFailure(e, this);
- }
-
- // Translate it, then call the real onFailure
- public void onFailure(LowLevelGetException e) {
- switch(e.code) {
- case LowLevelGetException.DATA_NOT_FOUND:
- onFailure(new
FetchException(FetchException.DATA_NOT_FOUND));
- return;
- case LowLevelGetException.DATA_NOT_FOUND_IN_STORE:
- onFailure(new
FetchException(FetchException.DATA_NOT_FOUND));
- return;
- case LowLevelGetException.DECODE_FAILED:
- onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR));
- return;
- case LowLevelGetException.INTERNAL_ERROR:
- onFailure(new
FetchException(FetchException.INTERNAL_ERROR));
- return;
- case LowLevelGetException.REJECTED_OVERLOAD:
- onFailure(new
FetchException(FetchException.REJECTED_OVERLOAD));
- return;
- case LowLevelGetException.ROUTE_NOT_FOUND:
- onFailure(new
FetchException(FetchException.ROUTE_NOT_FOUND));
- return;
- case LowLevelGetException.TRANSFER_FAILED:
- onFailure(new
FetchException(FetchException.TRANSFER_FAILED));
- return;
- case LowLevelGetException.VERIFY_FAILED:
- onFailure(new
FetchException(FetchException.BLOCK_DECODE_ERROR));
- return;
- case LowLevelGetException.CANCELLED:
- onFailure(new FetchException(FetchException.CANCELLED));
- return;
- default:
- Logger.error(this, "Unknown LowLevelGetException code:
"+e.code);
- onFailure(new
FetchException(FetchException.INTERNAL_ERROR));
- return;
- }
- }
-
- public void schedule() {
- super.schedule();
- }
-
public Object getToken() {
return token;
}
@@ -615,8 +534,18 @@
return ctx.ignoreStore;
}
- public static ClientGetState create(BaseClientGetter parent,
GetCompletionCallback cb, ClientMetadata clientMetadata, FreenetURI uri,
FetcherContext ctx, ArchiveContext actx, int maxRetries, int recursionLevel,
boolean dontTellClientGet, Object token, boolean isEssential, Bucket
returnBucket, boolean isFinal) throws MalformedURLException, FetchException {
+ /**
+ * Create a fetcher for a key.
+ */
+ public static ClientGetState create(BaseClientGetter parent,
GetCompletionCallback cb,
+ ClientMetadata clientMetadata, FreenetURI uri,
FetcherContext ctx, ArchiveContext actx,
+ int maxRetries, int recursionLevel, boolean
dontTellClientGet, Object token, boolean isEssential,
+ Bucket returnBucket, boolean isFinal) throws
MalformedURLException, FetchException {
BaseClientKey key = BaseClientKey.getBaseKey(uri);
+ if((clientMetadata == null || clientMetadata.isTrivial()) &&
(!uri.hasMetaStrings()) &&
+ ctx.allowSplitfiles == false &&
ctx.followRedirects == true && token == null &&
+ returnBucket == null && key instanceof
ClientKey)
+ return new SimpleSingleFileFetcher((ClientKey)key,
maxRetries, ctx, parent, cb, isEssential);
if(key instanceof ClientKey)
return new SingleFileFetcher(parent, cb,
clientMetadata, (ClientKey)key, uri.listMetaStrings(), uri, 0, ctx, actx,
maxRetries, recursionLevel, dontTellClientGet, token, isEssential,
returnBucket, isFinal);
else {
Modified: trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
2007-02-15 17:52:36 UTC (rev 11802)
+++ trunk/freenet/src/freenet/client/async/SplitFileFetcherSegment.java
2007-02-15 19:40:47 UTC (rev 11803)
@@ -16,6 +16,7 @@
import freenet.client.Metadata;
import freenet.client.MetadataParseException;
import freenet.client.SplitfileBlock;
+import freenet.keys.CHKBlock;
import freenet.keys.FreenetURI;
import freenet.support.Logger;
import freenet.support.api.Bucket;
@@ -31,8 +32,8 @@
final short splitfileType;
final FreenetURI[] dataBlocks;
final FreenetURI[] checkBlocks;
- final SingleFileFetcher[] dataBlockStatus;
- final SingleFileFetcher[] checkBlockStatus;
+ final BaseSingleFileFetcher[] dataBlockStatus;
+ final BaseSingleFileFetcher[] checkBlockStatus;
final MinimalSplitfileBlock[] dataBuckets;
final MinimalSplitfileBlock[] checkBuckets;
final int minFetched;
@@ -175,11 +176,11 @@
startedDecode = true;
}
for(int i=0;i<dataBlockStatus.length;i++) {
- SingleFileFetcher f = dataBlockStatus[i];
+ BaseSingleFileFetcher f = dataBlockStatus[i];
if(f != null) f.cancel();
}
for(int i=0;i<checkBlockStatus.length;i++) {
- SingleFileFetcher f = checkBlockStatus[i];
+ BaseSingleFileFetcher f = checkBlockStatus[i];
if(f != null) f.cancel();
}
Runnable r = new Decoder();
@@ -205,8 +206,7 @@
FECCodec codec = FECCodec.getCodec(splitfileType,
dataBlocks.length, checkBlocks.length);
try {
if(splitfileType !=
Metadata.SPLITFILE_NONREDUNDANT) {
- // FIXME hardcoded block size below.
- codec.decode(dataBuckets, checkBuckets,
32768, fetcherContext.bucketFactory);
+ codec.decode(dataBuckets, checkBuckets,
CHKBlock.DATA_LENGTH, fetcherContext.bucketFactory);
// Now have all the data blocks (not
necessarily all the check blocks)
}
@@ -252,7 +252,7 @@
for(int i=0;i<dataBlockStatus.length;i++) {
boolean heal = false;
if(!dataBlocksSucceeded[i]) {
- SingleFileFetcher fetcher =
dataBlockStatus[i];
+ BaseSingleFileFetcher fetcher =
dataBlockStatus[i];
if(fetcher.getRetryCount() > 0)
heal = true;
}
@@ -269,7 +269,7 @@
for(int i=0;i<checkBlockStatus.length;i++) {
boolean heal = false;
if(!checkBlocksSucceeded[i]) {
- SingleFileFetcher fetcher =
checkBlockStatus[i];
+ BaseSingleFileFetcher fetcher =
checkBlockStatus[i];
if(fetcher.getRetryCount() > 0)
heal = true;
}
@@ -337,7 +337,7 @@
return;
}
for(int i=0;i<dataBlockStatus.length;i++) {
- SingleFileFetcher f = dataBlockStatus[i];
+ BaseSingleFileFetcher f = dataBlockStatus[i];
if(f != null)
f.cancel();
MinimalSplitfileBlock b = dataBuckets[i];
@@ -348,7 +348,7 @@
dataBuckets[i] = null;
}
for(int i=0;i<checkBlockStatus.length;i++) {
- SingleFileFetcher f = checkBlockStatus[i];
+ BaseSingleFileFetcher f = checkBlockStatus[i];
if(f != null)
f.cancel();
MinimalSplitfileBlock b = checkBuckets[i];
Modified: trunk/freenet/src/freenet/keys/FreenetURI.java
===================================================================
--- trunk/freenet/src/freenet/keys/FreenetURI.java 2007-02-15 17:52:36 UTC
(rev 11802)
+++ trunk/freenet/src/freenet/keys/FreenetURI.java 2007-02-15 19:40:47 UTC
(rev 11803)
@@ -399,6 +399,10 @@
public String[] getAllMetaStrings() {
return metaStr;
}
+
+ public boolean hasMetaStrings() {
+ return metaStr == null || metaStr.length == 0;
+ }
public byte[] getRoutingKey() {
return routingKey;
Modified: trunk/freenet/src/freenet/node/SendableRequest.java
===================================================================
--- trunk/freenet/src/freenet/node/SendableRequest.java 2007-02-15 17:52:36 UTC
(rev 11802)
+++ trunk/freenet/src/freenet/node/SendableRequest.java 2007-02-15 19:40:47 UTC
(rev 11803)
@@ -9,11 +9,13 @@
*/
public interface SendableRequest extends RandomGrabArrayItem {
+ /** Get the priority class of the request. */
public short getPriorityClass();
public int getRetryCount();
- /** ONLY called by RequestStarter */
+ /** ONLY called by RequestStarter. Start the actual request using the
NodeClientCore
+ * provided. The request has been removed from the structure already. */
public void send(NodeClientCore node);
/** Get client context object */