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);
        }



Reply via email to