Author: toad
Date: 2006-09-29 18:38:41 +0000 (Fri, 29 Sep 2006)
New Revision: 10573
Modified:
trunk/freenet/src/freenet/client/async/ClientGetter.java
trunk/freenet/src/freenet/client/async/ClientPutter.java
trunk/freenet/src/freenet/clients/http/QueueToadlet.java
trunk/freenet/src/freenet/node/fcp/ClientGet.java
trunk/freenet/src/freenet/node/fcp/ClientPut.java
trunk/freenet/src/freenet/node/fcp/ClientPutBase.java
trunk/freenet/src/freenet/node/fcp/ClientPutDir.java
trunk/freenet/src/freenet/node/fcp/ClientRequest.java
trunk/freenet/src/freenet/node/fcp/FCPClient.java
trunk/freenet/src/freenet/node/fcp/FCPServer.java
trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
Log:
Allow the user to restart finished, failed requests from the queue page. (Get,
put tested, putdir not tested).
Get: If the persistent temp-file doesn't exist, or is too short, treat it as a
bucket error, rather than failing to load that request.
Don't automatically restart finished persistent requests on startup.
Minor refactoring.
Modified: trunk/freenet/src/freenet/client/async/ClientGetter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientGetter.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/client/async/ClientGetter.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -57,11 +57,20 @@
}
public void start() throws FetchException {
+ start(false);
+ }
+
+ public boolean start(boolean restart) throws FetchException {
try {
// FIXME synchronization is probably unnecessary.
// But we DEFINITELY do not want to synchronize while
calling currentState.schedule(),
// which can call onSuccess and thereby almost anything.
synchronized(this) {
+ if(finished) {
+ if(!restart) return false;
+ currentState = null;
+ cancelled = false;
+ }
currentState = SingleFileFetcher.create(this,
this, new ClientMetadata(),
uri, ctx, actx,
ctx.maxNonSplitfileRetries, 0, false, null, true,
returnBucket);
@@ -73,6 +82,7 @@
} catch (MalformedURLException e) {
throw new FetchException(FetchException.INVALID_URI, e);
}
+ return true;
}
public void onSuccess(FetchResult result, ClientGetState state) {
@@ -171,4 +181,16 @@
}
+ public boolean canRestart() {
+ if(currentState != null && !finished) {
+ Logger.minor(this, "Cannot restart because not finished
for "+uri);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean restart() throws FetchException {
+ return start(true);
+ }
+
}
Modified: trunk/freenet/src/freenet/client/async/ClientPutter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientPutter.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/client/async/ClientPutter.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -63,6 +63,10 @@
}
public void start() throws InserterException {
+ start(false);
+ }
+
+ public boolean start(boolean restart) throws InserterException {
if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Starting "+this);
try {
@@ -70,9 +74,12 @@
boolean cancel = false;
synchronized(this) {
- if(startedStarting) return;
+ if(restart) {
+ if(currentState != null && !finished)
return false;
+ }
+ if(startedStarting) return false;
startedStarting = true;
- if(currentState != null) return;
+ if(currentState != null) return false;
cancel = this.cancelled;
if(!cancel) {
currentState =
@@ -82,7 +89,7 @@
if(cancel) {
onFailure(new
InserterException(InserterException.CANCELLED), null);
oldProgress = null;
- return;
+ return false;
}
synchronized(this) {
cancel = cancelled;
@@ -90,7 +97,7 @@
if(cancel) {
onFailure(new
InserterException(InserterException.CANCELLED), null);
oldProgress = null;
- return;
+ return false;
}
((SingleFileInserter)currentState).start(oldProgress);
synchronized(this) {
@@ -99,7 +106,7 @@
}
if(cancel) {
onFailure(new
InserterException(InserterException.CANCELLED), null);
- return;
+ return false;
}
} catch (InserterException e) {
Logger.error(this, "Failed to start insert: "+e, e);
@@ -115,6 +122,7 @@
}
if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Started "+this);
+ return true;
}
public void onSuccess(ClientPutState state) {
@@ -203,5 +211,17 @@
public void onFetchable(ClientPutState state) {
client.onFetchable(this);
}
+
+ public boolean canRestart() {
+ if(currentState != null && !finished) {
+ Logger.minor(this, "Cannot restart because not finished
for "+uri);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean restart() throws InserterException {
+ return start(true);
+ }
}
Modified: trunk/freenet/src/freenet/clients/http/QueueToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/QueueToadlet.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/clients/http/QueueToadlet.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -97,7 +97,21 @@
}
writePermanentRedirect(ctx, "Done", "/queue/");
return;
- }else if(request.isParameterSet("remove_AllRequests")
&& (request.getParam("remove_AllRequests").length() > 0)) {
+ } else if(request.isParameterSet("restart_request") &&
(request.getParam("restart_request").length() > 0)) {
+ String identifier =
request.getParam("identifier");
+ if(logMINOR) Logger.minor(this, "Restarting
"+identifier);
+ ClientRequest[] clientRequests =
fcp.getGlobalRequests();
+ for (int requestIndex = 0, requestCount =
clientRequests.length; requestIndex < requestCount; requestIndex++) {
+ ClientRequest clientRequest =
clientRequests[requestIndex];
+ if
(clientRequest.getIdentifier().equals(identifier)) {
+ if(!clientRequest.restart()) {
+ sendErrorPage(ctx, 200,
"FAiled to restart request", "Failed to restart "+identifier);
+ }
+ }
+ }
+ writePermanentRedirect(ctx, "Done", "/queue/");
+ return;
+ } else if(request.isParameterSet("remove_AllRequests")
&& (request.getParam("remove_AllRequests").length() > 0)) {
ClientRequest[] reqs = fcp.getGlobalRequests();
if(logMINOR) Logger.minor(this, "Request count:
"+reqs.length);
@@ -669,12 +683,22 @@
return priorityCell;
}
- private HTMLNode createDeleteCell(PageMaker pageMaker, String
identifier) {
+ private HTMLNode createDeleteCell(PageMaker pageMaker, String
identifier, ClientRequest clientRequest) {
HTMLNode deleteNode = new HTMLNode("td", "class",
"request-delete");
HTMLNode deleteForm = deleteNode.addChild("form", new String[]
{ "action", "method" }, new String[] { "/queue/", "post" });
deleteForm.addChild(pageMaker.createFormPasswordInput(core.formPassword));
deleteForm.addChild("input", new String[] { "type", "name",
"value" }, new String[] { "hidden", "identifier", identifier });
deleteForm.addChild("input", new String[] { "type", "name",
"value" }, new String[] { "submit", "remove_request", "Delete" });
+
+ // If it's failed, offer to restart it
+
+ if(clientRequest.hasFinished() && !clientRequest.hasSucceeded()
&& clientRequest.canRestart()) {
+ HTMLNode retryForm = deleteNode.addChild("form", new
String[] { "action", "method" }, new String[] { "/queue/", "post" });
+
retryForm.addChild(pageMaker.createFormPasswordInput(core.formPassword));
+ retryForm.addChild("input", new String[] { "type",
"name", "value" }, new String[] { "hidden", "identifier", identifier });
+ retryForm.addChild("input", new String[] { "type",
"name", "value" }, new String[] { "submit", "restart_request", "Retry" });
+ }
+
return deleteNode;
}
@@ -805,7 +829,7 @@
ClientRequest clientRequest = (ClientRequest)
requestItems.next();
HTMLNode requestRow = table.addChild("tr", "class",
"priority" + clientRequest.getPriority());
- requestRow.addChild(createDeleteCell(pageMaker,
clientRequest.getIdentifier()));
+ requestRow.addChild(createDeleteCell(pageMaker,
clientRequest.getIdentifier(), clientRequest));
for (int columnIndex = 0, columnCount = columns.length;
columnIndex < columnCount; columnIndex++) {
int column = columns[columnIndex];
if (column == LIST_IDENTIFIER) {
Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java 2006-09-29 17:08:59 UTC
(rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java 2006-09-29 18:38:41 UTC
(rev 10573)
@@ -236,10 +236,23 @@
} else if(returnType == ClientGetMessage.RETURN_TYPE_DIRECT) {
byte[] key =
HexUtil.hexToBytes(fs.get("ReturnBucket.DecryptKey"));
String fnam = fs.get("ReturnBucket.Filename");
- ret =
client.server.core.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key, succeeded ? foundDataLength : 0);
+ try {
+ ret =
client.server.core.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key, succeeded ? foundDataLength : 0);
+ } catch (IOException e) {
+ Logger.error(this, "Caught "+e, e);
+ succeeded = false;
+ getFailedMessage = new GetFailedMessage(new
FetchException(FetchException.BUCKET_ERROR, e), identifier);
+ ret =
client.server.core.persistentTempBucketFactory.registerEncryptedBucket(fnam,
key, 0);
+ }
} else {
throw new IllegalArgumentException();
}
+ if(succeeded) {
+ if(foundDataLength < ret.size()) {
+ Logger.error(this, "Failing "+identifier+"
because lost data");
+ succeeded = false;
+ }
+ }
returnBucket = ret;
getter = new ClientGetter(this,
client.core.requestStarters.chkFetchScheduler,
client.core.requestStarters.sskFetchScheduler, uri, fctx, priorityClass,
client, returnBucket);
@@ -247,6 +260,8 @@
FCPMessage msg = persistentTagMessage();
client.queueClientRequestMessage(msg, 0);
}
+ if(finished && !succeeded)
+ started = true;
}
public void start() {
@@ -270,6 +285,7 @@
}
public void onSuccess(FetchResult result, ClientGetter state) {
+ Logger.minor(this, "Succeeded: "+identifier);
Bucket data = result.asBucket();
if(returnBucket != data)
Logger.error(this, "returnBucket = "+returnBucket+" but
onSuccess() data = "+data);
@@ -596,4 +612,39 @@
// Ignore, we don't insert
}
+ public boolean canRestart() {
+ if(!finished) {
+ Logger.minor(this, "Cannot restart because not finished
for "+identifier);
+ return false;
+ }
+ if(succeeded) {
+ Logger.minor(this, "Cannot restart because succeeded
for "+identifier);
+ return false;
+ }
+ return getter.canRestart();
+ }
+
+ public boolean restart() {
+ if(!canRestart()) return false;
+ synchronized(this) {
+ finished = false;
+ this.getFailedMessage = null;
+ this.allDataPending = null;
+ this.postFetchProtocolErrorMessage = null;
+ this.progressPending = null;
+ started = false;
+ }
+ try {
+ if(getter.restart()) {
+ synchronized(this) {
+ started = true;
+ }
+ }
+ return true;
+ } catch (FetchException e) {
+ onFailure(e, null);
+ return false;
+ }
+ }
+
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientPut.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-09-29 17:08:59 UTC
(rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-09-29 18:38:41 UTC
(rev 10573)
@@ -8,6 +8,7 @@
import freenet.client.ClientMetadata;
import freenet.client.DefaultMIMETypes;
+import freenet.client.FetchException;
import freenet.client.InserterException;
import freenet.client.Metadata;
import freenet.client.MetadataUnresolvedException;
@@ -365,4 +366,33 @@
return clientMetadata.getMIMEType();
}
+ public boolean canRestart() {
+ if(!finished) {
+ Logger.minor(this, "Cannot restart because not finished
for "+identifier);
+ return false;
+ }
+ if(succeeded) {
+ Logger.minor(this, "Cannot restart because succeeded
for "+identifier);
+ return false;
+ }
+ return inserter.canRestart();
+ }
+
+ public boolean restart() {
+ if(!canRestart()) return false;
+ setVarsRestart();
+ try {
+ if(inserter.restart()) {
+ synchronized(this) {
+ generatedURI = null;
+ started = true;
+ }
+ }
+ return true;
+ } catch (InserterException e) {
+ onFailure(e, null);
+ return false;
+ }
+ }
+
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientPutBase.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutBase.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutBase.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -334,4 +334,12 @@
return s;
}
+ public void setVarsRestart() {
+ synchronized(this) {
+ finished = false;
+ this.putFailedMessage = null;
+ this.progressMessage = null;
+ started = false;
+ }
+ }
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientPutDir.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutDir.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutDir.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -26,7 +26,7 @@
public class ClientPutDir extends ClientPutBase implements
ClientEventListener, ClientCallback {
private final HashMap manifestElements;
- private final SimpleManifestPutter putter;
+ private SimpleManifestPutter putter;
private final String defaultName;
private final long totalSize;
private final int numberOfFiles;
@@ -40,22 +40,7 @@
logMINOR = Logger.shouldLog(Logger.MINOR, this);
this.manifestElements = manifestElements;
this.defaultName = message.defaultName;
- SimpleManifestPutter p;
- try {
- p = new SimpleManifestPutter(this,
client.core.requestStarters.chkPutScheduler,
client.core.requestStarters.sskPutScheduler,
- manifestElements, priorityClass, uri,
defaultName, ctx, message.getCHKOnly, client);
- } catch (InserterException e) {
- onFailure(e, null);
- p = null;
- }
- if(p != null) {
- numberOfFiles = p.countFiles();
- totalSize = p.totalSize();
- } else {
- numberOfFiles = -1;
- totalSize = -1;
- }
- putter = p;
+ makePutter();
if(persistenceType != PERSIST_CONNECTION) {
client.register(this, false);
FCPMessage msg = persistentTagMessage();
@@ -63,9 +48,28 @@
if(handler != null && (!handler.isGlobalSubscribed()))
handler.outputHandler.queue(msg);
}
+ if(putter != null) {
+ numberOfFiles = putter.countFiles();
+ totalSize = putter.totalSize();
+ } else {
+ numberOfFiles = -1;
+ totalSize = -1;
+ }
if(logMINOR) Logger.minor(this, "Putting dir "+identifier+" :
"+priorityClass);
}
+ private void makePutter() {
+ SimpleManifestPutter p;
+ try {
+ p = new SimpleManifestPutter(this,
client.core.requestStarters.chkPutScheduler,
client.core.requestStarters.sskPutScheduler,
+ manifestElements, priorityClass, uri,
defaultName, ctx, getCHKOnly, client);
+ } catch (InserterException e) {
+ onFailure(e, null);
+ p = null;
+ }
+ putter = p;
+ }
+
public ClientPutDir(SimpleFieldSet fs, FCPClient client) throws
PersistenceParseException, IOException {
super(fs, client);
logMINOR = Logger.shouldLog(Logger.MINOR, this);
@@ -267,4 +271,24 @@
return totalSize;
}
+ public boolean canRestart() {
+ if(!finished) {
+ Logger.minor(this, "Cannot restart because not finished
for "+identifier);
+ return false;
+ }
+ if(succeeded) {
+ Logger.minor(this, "Cannot restart because succeeded
for "+identifier);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean restart() {
+ if(!canRestart()) return false;
+ setVarsRestart();
+ makePutter();
+ start();
+ return true;
+ }
+
}
Modified: trunk/freenet/src/freenet/node/fcp/ClientRequest.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientRequest.java 2006-09-29
17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/ClientRequest.java 2006-09-29
18:38:41 UTC (rev 10573)
@@ -281,5 +281,11 @@
public boolean isStarted() {
return started;
}
+
+ public abstract boolean hasSucceeded();
+
+ public abstract boolean canRestart();
+
+ public abstract boolean restart();
}
Modified: trunk/freenet/src/freenet/node/fcp/FCPClient.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPClient.java 2006-09-29 17:08:59 UTC
(rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/FCPClient.java 2006-09-29 18:38:41 UTC
(rev 10573)
@@ -137,13 +137,13 @@
ClientRequest old = (ClientRequest)
clientRequestsByIdentifier.get(ident);
if((old != null) && (old != cg))
throw new IdentifierCollisionException();
- if(cg.hasFinished())
+ if(cg.hasFinished()) {
completedUnackedRequests.push(cg);
- else
+ } else {
runningPersistentRequests.add(cg);
+ toStart.add(cg);
+ }
clientRequestsByIdentifier.put(ident, cg);
- if(startLater)
- toStart.add(cg);
}
}
Modified: trunk/freenet/src/freenet/node/fcp/FCPServer.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPServer.java 2006-09-29 17:08:59 UTC
(rev 10572)
+++ trunk/freenet/src/freenet/node/fcp/FCPServer.java 2006-09-29 18:38:41 UTC
(rev 10573)
@@ -94,7 +94,6 @@
this.core = core;
clientsByName = new WeakHashMap();
-
// This one is only used to get the default settings.
Individual FCP conns
// will make their own.
HighLevelSimpleClient client = core.makeClient((short)0);
Modified: trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-09-29 17:08:59 UTC (rev 10572)
+++ trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-09-29 18:38:41 UTC (rev 10573)
@@ -72,9 +72,12 @@
/**
* Called by a client to fetch the bucket denoted by a specific
filename,
* and to register this fact so that it is not deleted on startup
completion.
+ * @throws IOException
*/
- public Bucket register(String filename) {
+ public Bucket register(String filename, boolean mustExist) throws
IOException {
File f = new File(dir, filename);
+ if(mustExist && !f.exists())
+ throw new IOException("File does not exist (deleted?):
"+f);
Bucket b = new FileBucket(f, false, false, false, true);
originalFiles.remove(f);
return b;
@@ -110,8 +113,16 @@
return new PaddedEphemerallyEncryptedBucket(b, 1024, rand,
false);
}
+ /**
+ * Restore an encrypted temp bucket from last time.
+ * @param filename The filename. Must exist unless len=0.
+ * @param key The encryption key for the bucket.
+ * @param len The data length. The file must be of at least this length.
+ * @return
+ * @throws IOException If the file doesn't exist or if it is too short.
+ */
public Bucket registerEncryptedBucket(String filename, byte[] key, long
len) throws IOException {
- Bucket fileBucket = register(filename);
+ Bucket fileBucket = register(filename, len > 0);
return new PaddedEphemerallyEncryptedBucket(fileBucket, 1024,
len, key, rand);
}