Author: toad
Date: 2006-03-03 16:00:53 +0000 (Fri, 03 Mar 2006)
New Revision: 8143

Modified:
   trunk/freenet/src/freenet/client/FailureCodeTracker.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/node/fcp/ClientGet.java
   trunk/freenet/src/freenet/node/fcp/ClientPut.java
   trunk/freenet/src/freenet/node/fcp/FCPClient.java
   trunk/freenet/src/freenet/node/fcp/GetFailedMessage.java
   trunk/freenet/src/freenet/node/fcp/PutFailedMessage.java
   trunk/freenet/src/freenet/support/SimpleFieldSet.java
Log:
482:
Serialize completion state on ClientPut.
Persistent, completed inserts will no longer restart on startup.
We now store the completion state, and the generated URI (but not the last 
SimpleProgress, as this would interfere with later plans).

Modified: trunk/freenet/src/freenet/client/FailureCodeTracker.java
===================================================================
--- trunk/freenet/src/freenet/client/FailureCodeTracker.java    2006-03-03 
14:24:00 UTC (rev 8142)
+++ trunk/freenet/src/freenet/client/FailureCodeTracker.java    2006-03-03 
16:00:53 UTC (rev 8143)
@@ -19,7 +19,36 @@
                this.insert = insert;
        }

-       public class Item {
+       /**
+        * Create a FailureCodeTracker from a SimpleFieldSet.
+        * @param isInsert Whether this is an insert.
+        * @param fs The SimpleFieldSet containing the FieldSet (non-verbose) 
form of 
+        * the tracker.
+        */
+       public FailureCodeTracker(boolean isInsert, SimpleFieldSet fs) {
+               this.insert = isInsert;
+               Iterator i = fs.directSubsetNameIterator();
+               while(i.hasNext()) {
+                       String name = (String) i.next();
+                       SimpleFieldSet f = fs.subset(name);
+                       // We ignore the Description, if there is one; we just 
want the count
+                       int num = Integer.parseInt(name);
+                       int count = Integer.parseInt(f.get("Count"));
+                       if(count < 0) throw new IllegalArgumentException("Count 
< 0");
+                       map.put(new Integer(num), new Item(count));
+                       total += count;
+               }
+       }
+       
+       class Item {
+               Item(int count) {
+                       this.x = count;
+               }
+
+               Item() {
+                       this.x = 0;
+               }
+
                int x;
        }

@@ -85,7 +114,7 @@
        }

        /** Copy verbosely to a SimpleFieldSet */
-       public synchronized void copyToFieldSet(SimpleFieldSet sfs, String 
prefix) {
+       public synchronized void copyToFieldSet(SimpleFieldSet sfs, String 
prefix, boolean verbose) {
                Iterator keys = map.keySet().iterator();
                while(keys.hasNext()) {
                        Integer k = (Integer) keys.next();
@@ -93,9 +122,10 @@
                        int code = k.intValue();
                        // prefix.num.Description=<code description>
                        // prefix.num.Count=<count>
-                       
sfs.put(prefix+Integer.toHexString(code)+".Description", 
-                                       insert ? 
InserterException.getMessage(code) : FetchException.getMessage(code));
-                       sfs.put(prefix+Integer.toHexString(code)+".Count", 
Integer.toHexString(item.x));
+                       if(verbose)
+                               
sfs.put(prefix+Integer.toString(code)+".Description", 
+                                               insert ? 
InserterException.getMessage(code) : FetchException.getMessage(code));
+                       sfs.put(prefix+Integer.toString(code)+".Count", 
Integer.toString(item.x));
                }
        }


Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-03 14:24:00 UTC (rev 
8142)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-03 16:00:53 UTC (rev 
8143)
@@ -20,7 +20,7 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       private static final int buildNumber = 481;
+       private static final int buildNumber = 482;

        /** Oldest build of Fred we will talk to */
        private static final int lastGoodBuild = 475;

Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-03 14:24:00 UTC 
(rev 8142)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-03 16:00:53 UTC 
(rev 8143)
@@ -117,11 +117,7 @@
                else
                        tempFile = null;
                clientToken = fs.get("ClientToken");
-                if(fs.get("Finished").equalsIgnoreCase("true")){
-                       finished = true;
-               }else{
-                       finished = false;
-               }
+               finished = Fields.stringToBool(fs.get("Finished"), false);
                boolean ignoreDS = Fields.stringToBool(fs.get("IgnoreDS"), 
false);
                boolean dsOnly = Fields.stringToBool(fs.get("DSOnly"), false);
                int maxRetries = Integer.parseInt(fs.get("MaxRetries"));

Modified: trunk/freenet/src/freenet/node/fcp/ClientPut.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPut.java   2006-03-03 14:24:00 UTC 
(rev 8142)
+++ trunk/freenet/src/freenet/node/fcp/ClientPut.java   2006-03-03 16:00:53 UTC 
(rev 8143)
@@ -23,6 +23,7 @@
 import freenet.client.events.StartedCompressionEvent;
 import freenet.keys.FreenetURI;
 import freenet.support.Bucket;
+import freenet.support.Fields;
 import freenet.support.Logger;
 import freenet.support.SimpleFieldSet;
 import freenet.support.io.FileBucket;
@@ -56,9 +57,18 @@
        private int VERBOSITY_COMPRESSION_START_END = 512;

        // Stuff waiting for reconnection
-       private FCPMessage finalMessage;
-       private FCPMessage generatedURIMessage;
-       // This could be a SimpleProgress, or it could be started/finished 
compression
+       /** Has the request succeeded? */
+       private boolean succeeded;
+       /** If the request failed, how did it fail? PutFailedMessage is the most
+        * convenient way to store this (InserterException has a stack trace!).
+        */
+       private PutFailedMessage putFailedMessage;
+       /** URI generated for the insert. */
+       private FreenetURI generatedURI;
+       // This could be a SimpleProgress, or it could be started/finished 
compression.
+       // Not that important, so not saved on persistence.
+       // Probably saving it would conflict with later changes (full 
persistence at
+       // ClientPutter level).
        private FCPMessage progressMessage;

        public ClientPut(FCPConnectionHandler handler, ClientPutMessage 
message) {
@@ -125,8 +135,16 @@
                ctx.eventProducer.addEventListener(this);
                ctx.maxInsertRetries = maxRetries;
                block = new InsertBlock(data, new ClientMetadata(mimeType), 
uri);
+               finished = Fields.stringToBool(fs.get("Finished"), false);
+               succeeded = Fields.stringToBool(fs.get("Succeeded"), false);
+               String genURI = fs.get("GeneratedURI");
+               if(genURI != null)
+                       generatedURI = new FreenetURI(genURI);
+               if(finished && (!succeeded))
+                       putFailedMessage = new 
PutFailedMessage(fs.subset("PutFailed"), false);
                inserter = new ClientPutter(this, data, uri, new 
ClientMetadata(mimeType), ctx, client.node.putScheduler, priorityClass, 
getCHKOnly, false, client);
-               start();
+               if(!finished)
+                       start();
        }

        void start() {
@@ -149,23 +167,26 @@

        public void onSuccess(BaseClientPutter state) {
                progressMessage = null;
+               succeeded = true;
                finished = true;
-               FCPMessage msg = new PutSuccessfulMessage(identifier, 
state.getURI());
-               trySendFinalMessage(msg);
+               trySendFinalMessage();
                block.getData().free();
                finish();
        }

        public void onFailure(InserterException e, BaseClientPutter state) {
                finished = true;
-               FCPMessage msg = new PutFailedMessage(e, identifier);
-               trySendFinalMessage(msg);
+               putFailedMessage = new PutFailedMessage(e, identifier);
+               trySendFinalMessage();
                block.getData().free();
                finish();
        }

        public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
-               trySendGeneratedURIMessage(new URIGeneratedMessage(uri, 
identifier));
+               if(generatedURI != null && !uri.equals(generatedURI))
+                       Logger.error(this, "onGeneratedURI("+uri+","+state+") 
but already set generatedURI to "+generatedURI);
+               generatedURI = uri;
+               trySendGeneratedURIMessage();
        }

        public void onSuccess(FetchResult result, ClientGetter state) {
@@ -199,17 +220,27 @@
                }
        }

-       private void trySendFinalMessage(FCPMessage msg) {
-               if(persistenceType != PERSIST_CONNECTION)
-                       finalMessage = msg;
-               FCPConnectionHandler conn = client.getConnection();
-               if(conn != null)
-                       conn.outputHandler.queue(msg);
+       private void trySendFinalMessage() {
+               
+               FCPMessage msg;
+               
+               if(succeeded) {
+                       msg = new PutSuccessfulMessage(identifier, 
generatedURI);
+               } else {
+                       msg = putFailedMessage;
+               }
+               
+               if(msg == null) {
+                       Logger.error(this, "Trying to send null message on 
"+this, new Exception("error"));
+               } else {
+                       FCPConnectionHandler conn = client.getConnection();
+                       if(conn != null)
+                               conn.outputHandler.queue(msg);
+               }
        }

-       private void trySendGeneratedURIMessage(URIGeneratedMessage msg) {
-               if(persistenceType != PERSIST_CONNECTION)
-                       generatedURIMessage = msg;
+       private void trySendGeneratedURIMessage() {
+               FCPMessage msg = new URIGeneratedMessage(generatedURI, 
identifier);
                FCPConnectionHandler conn = client.getConnection();
                if(conn != null)
                        conn.outputHandler.queue(msg);
@@ -232,12 +263,12 @@
                        FCPMessage msg = new PersistentPut(identifier, uri, 
verbosity, priorityClass, fromDisk, persistenceType, origFilename, 
block.clientMetadata.getMIMEType());
                        handler.queue(msg);
                }
-               if(generatedURIMessage != null)
-                       handler.queue(generatedURIMessage);
+               if(generatedURI != null)
+                       trySendGeneratedURIMessage();
                if(progressMessage != null)
                        handler.queue(progressMessage);
-               if(finalMessage != null)
-                       handler.queue(finalMessage);
+               if(finished)
+                       trySendFinalMessage();
        }

        /** Request completed. But we may have to stick around until we are 
acked. */
@@ -289,6 +320,13 @@
                fs.put("Filename", origFilename.getPath());
                fs.put("DontCompress", Boolean.toString(ctx.dontCompress));
                fs.put("MaxRetries", Integer.toString(ctx.maxInsertRetries));
+               fs.put("Finished", Boolean.toString(finished));
+               fs.put("Succeeded", Boolean.toString(succeeded));
+               if(generatedURI != null)
+                       fs.put("GeneratedURI", generatedURI.toString(false));
+               if(finished && (!succeeded))
+                       // Should have a putFailedMessage... unless there is a 
race condition.
+                       fs.put("PutFailed", 
putFailedMessage.getFieldSet(false));
                return fs;
        }


Modified: trunk/freenet/src/freenet/node/fcp/FCPClient.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPClient.java   2006-03-03 14:24:00 UTC 
(rev 8142)
+++ trunk/freenet/src/freenet/node/fcp/FCPClient.java   2006-03-03 16:00:53 UTC 
(rev 8143)
@@ -80,6 +80,8 @@
                }
                if(dropped != null)
                        dropped.dropped();
+               if(get.isPersistentForever())
+                       server.forceStorePersistentRequests();
        }

        /**
@@ -124,10 +126,10 @@
                        req = (ClientRequest) 
clientRequestsByIdentifier.get(identifier);
                        if(req == null)
                                throw new 
MessageInvalidException(ProtocolErrorMessage.NO_SUCH_IDENTIFIER, null, 
identifier);
-                       if(runningPersistentRequests.remove(req) || 
completedUnackedRequests.remove(req))
-                               return;
-                       throw new 
MessageInvalidException(ProtocolErrorMessage.NO_SUCH_IDENTIFIER, null, 
identifier);
+                       else if(!(runningPersistentRequests.remove(req) || 
completedUnackedRequests.remove(req)))
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.NO_SUCH_IDENTIFIER, null, 
identifier);
                }
+               server.forceStorePersistentRequests();
        }

        public boolean hasPersistentRequests() {

Modified: trunk/freenet/src/freenet/node/fcp/GetFailedMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/GetFailedMessage.java    2006-03-03 
14:24:00 UTC (rev 8142)
+++ trunk/freenet/src/freenet/node/fcp/GetFailedMessage.java    2006-03-03 
16:00:53 UTC (rev 8143)
@@ -26,16 +26,29 @@
        }

        public SimpleFieldSet getFieldSet() {
+               return getFieldSet(true);
+       }
+       
+       /**
+        * Write to a SimpleFieldSet for storage or transmission.
+        * @param verbose If true, include fields which derive directly from 
static
+        * stuff on InserterException (and therefore can be omitted if talking 
to self
+        * or another node).
+        */
+       public SimpleFieldSet getFieldSet(boolean verbose) {
                SimpleFieldSet sfs = new SimpleFieldSet(false);
                sfs.put("Code", Integer.toString(code));
-               sfs.put("CodeDescription", codeDescription);
+               if(verbose)
+                       sfs.put("CodeDescription", codeDescription);
                if(extraDescription != null)
                        sfs.put("ExtraDescription", extraDescription);
-               sfs.put("Fatal", Boolean.toString(isFatal));
+               if(verbose)
+                       sfs.put("Fatal", Boolean.toString(isFatal));
                if(tracker != null) {
-                       tracker.copyToFieldSet(sfs, "Errors.");
+                       tracker.copyToFieldSet(sfs, "Errors.", verbose);
                }
-               sfs.put("ShortCodeDescription", shortCodeDescription);
+               if(verbose)
+                       sfs.put("ShortCodeDescription", shortCodeDescription);
                sfs.put("Identifier", identifier);
                return sfs;
        }

Modified: trunk/freenet/src/freenet/node/fcp/PutFailedMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/PutFailedMessage.java    2006-03-03 
14:24:00 UTC (rev 8142)
+++ trunk/freenet/src/freenet/node/fcp/PutFailedMessage.java    2006-03-03 
16:00:53 UTC (rev 8143)
@@ -1,9 +1,12 @@
 package freenet.node.fcp;

+import java.net.MalformedURLException;
+
 import freenet.client.FailureCodeTracker;
 import freenet.client.InserterException;
 import freenet.keys.FreenetURI;
 import freenet.node.Node;
+import freenet.support.Fields;
 import freenet.support.SimpleFieldSet;

 public class PutFailedMessage extends FCPMessage {
@@ -25,21 +28,62 @@
                this.tracker = e.errorCodes;
                this.expectedURI = e.uri;
                this.identifier = identifier;
-               this.isFatal = e.isFatal();
+               this.isFatal = InserterException.isFatal(code);
        }

+       /**
+        * Construct from a fieldset. Used in serialization of persistent 
requests.
+        * Will need to be made more tolerant of syntax errors if is used in an 
FCP
+        * client library. FIXME.
+        * @param useVerboseFields If true, read in verbose fields 
(CodeDescription
+        * etc), if false, reconstruct them from the error code.
+        * @throws MalformedURLException 
+        */
+       public PutFailedMessage(SimpleFieldSet fs, boolean useVerboseFields) 
throws MalformedURLException {
+               identifier = fs.get("Identifier");
+               if(identifier == null) throw new NullPointerException();
+               code = Integer.parseInt(fs.get("Code"));
+               
+               if(useVerboseFields) {
+                       codeDescription = fs.get("CodeDescription");
+                       isFatal = Fields.stringToBool(fs.get("Fatal"), false);
+                       codeShortDescription = fs.get("ShortCodeDescription");
+               } else {
+                       codeDescription = InserterException.getMessage(code);
+                       isFatal = InserterException.isFatal(code);
+                       codeShortDescription = 
InserterException.getShortMessage(code);
+               }
+               
+               extraDescription = fs.get("ExtraDescription");
+               String euri = fs.get("ExpectedURI");
+               expectedURI = new FreenetURI(euri);
+               SimpleFieldSet trackerSubset = fs.subset("Errors");
+               if(trackerSubset != null) {
+                       tracker = new FailureCodeTracker(true, trackerSubset);
+               } else {
+                       tracker = null;
+               }
+       }
+
        public SimpleFieldSet getFieldSet() {
+               return getFieldSet(true);
+       }
+       
+       public SimpleFieldSet getFieldSet(boolean verbose) {
                SimpleFieldSet fs = new SimpleFieldSet(false);
                fs.put("Identifier", identifier);
                fs.put("Code", Integer.toString(code));
-               fs.put("CodeDescription", codeDescription);
+               if(verbose)
+                       fs.put("CodeDescription", codeDescription);
                if(extraDescription != null)
                        fs.put("ExtraDescription", extraDescription);
                if(tracker != null) {
-                       tracker.copyToFieldSet(fs, "Errors.");
+                       tracker.copyToFieldSet(fs, "Errors.", verbose);
                }
-               fs.put("Fatal", Boolean.toString(isFatal));
-               fs.put("ShortCodeDescription", codeShortDescription);
+               if(verbose)
+                       fs.put("Fatal", Boolean.toString(isFatal));
+               if(verbose)
+                       fs.put("ShortCodeDescription", codeShortDescription);
                if(expectedURI != null)
                        fs.put("ExpectedURI", expectedURI.toString());
                return fs;

Modified: trunk/freenet/src/freenet/support/SimpleFieldSet.java
===================================================================
--- trunk/freenet/src/freenet/support/SimpleFieldSet.java       2006-03-03 
14:24:00 UTC (rev 8142)
+++ trunk/freenet/src/freenet/support/SimpleFieldSet.java       2006-03-03 
16:00:53 UTC (rev 8143)
@@ -350,4 +350,46 @@
                return map.isEmpty();
        }

+       public Iterator directSubsetNameIterator() {
+               return new DirectSubsetNameIterator();
+       }
+
+       public class DirectSubsetNameIterator implements Iterator {
+
+               Iterator mapIterator;
+               String nextName;
+               
+               DirectSubsetNameIterator() {
+                       mapIterator = map.keySet().iterator();
+                       fetchNext();
+               }
+               
+               public boolean hasNext() {
+                       return nextName != null;
+               }
+
+               public Object next() {
+                       String next = nextName;
+                       fetchNext();
+                       return next;
+               }
+
+               public void remove() {
+                       throw new UnsupportedOperationException();
+               }
+               
+               void fetchNext() {
+                       // Maybe more efficient with Entry's???
+                       while(mapIterator.hasNext()) {
+                               String name = (String) mapIterator.next();
+                               Object target = map.get(name);
+                               if(target instanceof SimpleFieldSet) {
+                                       nextName = name;
+                                       return;
+                               }
+                       }
+                       nextName = null;
+               }
+       }
+
 }


Reply via email to