Author: toad
Date: 2006-08-05 21:42:00 +0000 (Sat, 05 Aug 2006)
New Revision: 9917

Modified:
   trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java
   trunk/freenet/src/freenet/node/TextModeClientInterface.java
   trunk/freenet/src/freenet/node/updater/NodeUpdater.java
   
trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java
Log:
NodeUpdater: Less locking, support updating to newer versions than the first 
successfully fetched.

Modified: trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java  2006-08-05 
21:31:00 UTC (rev 9916)
+++ trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java  2006-08-05 
21:42:00 UTC (rev 9917)
@@ -76,8 +76,8 @@

                        writeReply(ctx, 200, "text/html", "OK", buf.toString());
                        Logger.normal(this, "Node is updating/restarting");
-                       // FIXME run on separate thread
-                       node.getNodeUpdater().Update();
+                       node.ps.queueTimedJob(new Runnable() {
+                               public void run() { 
node.getNodeUpdater().Update(); }}, 0);
                        return;
                }else if (request.getParam("restart").length() > 0) {
                        ctx.getPageMaker().makeHead(buf, "Node Restart");

Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-08-05 
21:31:00 UTC (rev 9916)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-08-05 
21:42:00 UTC (rev 9917)
@@ -311,7 +311,11 @@
     } else if(uline.startsWith("UPDATE")) {
                outsb.append("starting the update process");
                // FIXME run on separate thread
-               n.getNodeUpdater().Update();
+               n.ps.queueTimedJob(new Runnable() {
+                       public void run() {
+                               n.getNodeUpdater().Update();
+                       }
+               }, 0);
                return false;
     }else if(uline.startsWith("BLOW")) {
                        n.getNodeUpdater().blow("caught an  IOException : 
(Incompetent Operator) :p");

Modified: trunk/freenet/src/freenet/node/updater/NodeUpdater.java
===================================================================
--- trunk/freenet/src/freenet/node/updater/NodeUpdater.java     2006-08-05 
21:31:00 UTC (rev 9916)
+++ trunk/freenet/src/freenet/node/updater/NodeUpdater.java     2006-08-05 
21:42:00 UTC (rev 9917)
@@ -51,6 +51,7 @@

        private final int currentVersion;
        private int availableVersion;
+       private int fetchingVersion;

        private String revocationMessage;
        private boolean hasBeenBlown;
@@ -129,41 +130,56 @@
                }
        }

-       public synchronized void maybeUpdate(){
-               try{
-                       Logger.minor(this, "maybeUpdate: 
isFetching="+isFetching+", isRunning="+isRunning+", 
isUpdatable="+isUpdatable()+", availableVersion="+availableVersion);
-                       if(isFetching || (!isRunning) || (!isUpdatable())) 
return;
-               }catch (PrivkeyHasBeenBlownException e){
-                       // Handled in blow().
-                       isRunning=false;
-                       return;
+       public void maybeUpdate(){
+               ClientGetter toStart = null;
+               synchronized(this) {
+                       try{
+                               Logger.minor(this, "maybeUpdate: 
isFetching="+isFetching+", isRunning="+isRunning+", 
isUpdatable="+isUpdatable()+", availableVersion="+availableVersion);
+                               if(isFetching || (!isRunning) || 
(!isUpdatable())) return;
+                       }catch (PrivkeyHasBeenBlownException e){
+                               // Handled in blow().
+                               isRunning=false;
+                               return;
+                       }
+                       
+                       
+                       fetchingVersion = availableVersion;
+                       alert.set(availableVersion,fetchingVersion,false);
+                       alert.isValid(true);
+                       Logger.normal(this,"Starting the update process 
("+availableVersion+")");
+                       System.err.println("Starting the update process: found 
the update ("+availableVersion+"), now fetching it.");
+                       // We fetch it
+                       try{
+                               if((cg==null)||cg.isCancelled()){
+                                       Logger.minor(this, "Scheduling request 
for "+URI.setSuggestedEdition(availableVersion));
+                                       cg = new ClientGetter(this, 
node.chkFetchScheduler, node.sskFetchScheduler, 
+                                                       
URI.setSuggestedEdition(availableVersion), ctx, 
RequestStarter.UPDATE_PRIORITY_CLASS, 
+                                                       this, new 
ArrayBucket());
+                                       toStart = cg;
+                               }
+                               isFetching = true;
+                               queueFetchRevocation(0);
+                       }catch (Exception e) {
+                               Logger.error(this, "Error while starting the 
fetching: "+e, e);
+                               isFetching=false;
+                       }
                }
-
-
-               alert.set(availableVersion,false);
-               alert.isValid(true);
-               Logger.normal(this,"Starting the update process 
("+availableVersion+")");
-               System.err.println("Starting the update process: found the 
update ("+availableVersion+"), now fetching it.");
-//             We fetch it
-               try{
-                       if((cg==null)||cg.isCancelled()){
-                               Logger.minor(this, "Scheduling request for 
"+URI.setSuggestedEdition(availableVersion));
-                               cg = new ClientGetter(this, 
node.chkFetchScheduler, node.sskFetchScheduler, 
-                                               
URI.setSuggestedEdition(availableVersion), ctx, 
RequestStarter.UPDATE_PRIORITY_CLASS, 
-                                               this, new ArrayBucket());
-                               cg.start();
+               if(toStart != null)
+                       try {
+                               toStart.start();
+                       } catch (FetchException e) {
+                               Logger.error(this, "Error while starting the 
fetching: "+e, e);
+                               synchronized(this) {
+                                       isFetching=false;
+                               }
                        }
-                       isFetching = true;
-                       queueFetchRevocation(0);
-               }catch (Exception e) {
-                       Logger.error(this, "Error while starting the fetching: 
"+e, e);
-                       isFetching=false;
-               }
        }

+       /** Synchronization object only used by Update(); simply a mutex on the
+        * innerUpdate() method, which can block for some time. */
        private volatile Object updateSync = new Object();

-       public synchronized void Update() {
+       public void Update() {

                if(!WrapperManager.isControlledByNativeWrapper()) {
                        Logger.error(this, "Cannot update because not running 
under wrapper");
@@ -171,7 +187,9 @@
                        return;
                }

-               if(!isRunning) return;
+               synchronized(this) {
+                       if(!isRunning) return;
+               }

                synchronized(updateSync) {
                        innerUpdate();
@@ -182,29 +200,30 @@
         * We try to update the node :p
         * Must run on its own thread.
         */
-       private synchronized void innerUpdate(){
+       private void innerUpdate(){
                Logger.minor(this, "Update() called");
-               if((result == null) || hasBeenBlown) {
-                       Logger.minor(this, "Returning: result="+result+", 
isAutoUpdateAllowed="+isAutoUpdateAllowed+", hasBeenBlown="+hasBeenBlown);
-                       return;
-               }
-
-               this.revocationDNFCounter = 0;
-               this.finalCheck = true;
-
-
-               System.err.println("Searching for revocation key");
-               this.queueFetchRevocation(100);
-               while(revocationDNFCounter < NodeUpdater.REVOCATION_DNF_MIN) {
-                       System.err.println("Revocation counter: 
"+revocationDNFCounter);
-                       if(this.hasBeenBlown) {
-                               Logger.error(this, "The revocation key has been 
found on the network : blocking auto-update");
+               synchronized(this) {
+                       if((result == null) || hasBeenBlown) {
+                               Logger.minor(this, "Returning: 
result="+result+", isAutoUpdateAllowed="+isAutoUpdateAllowed+", 
hasBeenBlown="+hasBeenBlown);
                                return;
                        }
-                       try {
-                               wait(100*1000);
-                       } catch (InterruptedException e) {
-                               // Ignore
+                       
+                       this.revocationDNFCounter = 0;
+                       this.finalCheck = true;
+
+                       System.err.println("Searching for revocation key");
+                       this.queueFetchRevocation(100);
+                       while(revocationDNFCounter < 
NodeUpdater.REVOCATION_DNF_MIN) {
+                               System.err.println("Revocation counter: 
"+revocationDNFCounter);
+                               if(this.hasBeenBlown) {
+                                       Logger.error(this, "The revocation key 
has been found on the network : blocking auto-update");
+                                       return;
+                               }
+                               try {
+                                       wait(100*1000);
+                               } catch (InterruptedException e) {
+                                       // Ignore
+                               }
                        }
                }

@@ -353,15 +372,23 @@

        public synchronized void onSuccess(FetchResult result, ClientGetter 
state) {
                if(!state.getURI().equals(revocationURI)){
-                       System.out.println("Found "+availableVersion);
-                       Logger.normal(this, "Found a new version! (" + 
availableVersion + ", setting up a new UpdatedVersionAviableUserAlert");
-                       alert.set(availableVersion,true);
-                       alert.isValid(true);            
+                       System.out.println("Found "+fetchingVersion);
+                       Logger.normal(this, "Found a new version! (" + 
fetchingVersion + ", setting up a new UpdatedVersionAviableUserAlert");
+                       alert.set(availableVersion,fetchingVersion,true);
+                       alert.isValid(true);
                        this.cg = state;
                        if(this.result != null) this.result.asBucket().free();
                        this.result = result;
-                       if(this.isAutoUpdateAllowed)
+                       if(this.isAutoUpdateAllowed) {
                                scheduleUpdate();
+                       } else {
+                               isFetching = false;
+                               if(availableVersion > fetchingVersion) {
+                                       node.ps.queueTimedJob(new Runnable() {
+                                               public void run() { 
maybeUpdate(); }
+                                       }, 0);
+                               }
+                       }
                }else{
                        // The key has been blown !
                        // FIXME: maybe we need a bigger warning message.
@@ -383,14 +410,16 @@
                }
        }

-       public synchronized void onFailure(FetchException e, ClientGetter 
state) {
+       public void onFailure(FetchException e, ClientGetter state) {
                int errorCode = e.getMode();

                if(!state.getURI().equals(revocationURI)){
                        Logger.minor(this, "onFailure("+e+","+state+")");
-                       this.cg = state;
-                       isFetching=false;
-                       cg.cancel();
+                       synchronized(this) {
+                               this.cg = state;
+                               isFetching=false;
+                       }
+                       state.cancel();
                        if((errorCode == FetchException.DATA_NOT_FOUND) ||
                                        (errorCode == 
FetchException.ROUTE_NOT_FOUND) ||
                                        (errorCode == 
FetchException.PERMANENT_REDIRECT) ||
@@ -403,21 +432,25 @@
                        }
                }else{
                        Logger.minor(this, "Revocation fetch failed: "+e);
-                       if(errorCode == FetchException.DATA_NOT_FOUND){
-                               revocationDNFCounter++;
-                               Logger.minor(this, "Incremented DNF counter to 
"+revocationDNFCounter);
+                       synchronized(this) {
+                               if(errorCode == FetchException.DATA_NOT_FOUND){
+                                       revocationDNFCounter++;
+                                       Logger.minor(this, "Incremented DNF 
counter to "+revocationDNFCounter);
+                               }
                        }
                        if(e.isFatal()) this.blow("Permanent error fetching 
revocation (invalid data inserted?): "+e.toString());
                        // Start it again
-                       if(this.finalCheck) {
-                               if(revocationDNFCounter < 3)
-                                       queueFetchRevocation(1000);
-                               else
-                                       notifyAll();
-                       } else {
-                               boolean pause = (revocationDNFCounter == 3);
-                               if(pause) revocationDNFCounter = 0;
-                               queueFetchRevocation(pause ? 60*60*1000 : 5000);
+                       synchronized(this) {
+                               if(this.finalCheck) {
+                                       if(revocationDNFCounter < 3)
+                                               queueFetchRevocation(1000);
+                                       else
+                                               notifyAll();
+                               } else {
+                                       boolean pause = (revocationDNFCounter 
== 3);
+                                       if(pause) revocationDNFCounter = 0;
+                                       queueFetchRevocation(pause ? 60*60*1000 
: 5000);
+                               }
                        }
                }
        }
@@ -487,13 +520,18 @@
                return isRunning;
        }

-       protected synchronized void kill(){
-               isRunning = false;
+       protected void kill(){
                try{
-                       USK 
myUsk=USK.create(URI.setSuggestedEdition(currentVersion));
-                       ctx.uskManager.unsubscribe(myUsk, this, true);
-                       cg.cancel();
-                       revocationGetter.cancel();
+                       ClientGetter c, r;
+                       synchronized(this) {
+                               isRunning = false;
+                               USK 
myUsk=USK.create(URI.setSuggestedEdition(currentVersion));
+                               ctx.uskManager.unsubscribe(myUsk, this, true);
+                               c = cg;
+                               r = revocationGetter;
+                       }
+                       c.cancel();
+                       r.cancel();
                }catch(Exception e){
                }
        }

Modified: 
trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java
===================================================================
--- 
trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java 
    2006-08-05 21:31:00 UTC (rev 9916)
+++ 
trunk/freenet/src/freenet/node/useralerts/UpdatedVersionAvailableUserAlert.java 
    2006-08-05 21:42:00 UTC (rev 9917)
@@ -6,6 +6,7 @@
        private boolean isValid, isReady;
        private final NodeUpdater updater;
        private int version;
+       private int readyVersion;

        public UpdatedVersionAvailableUserAlert(int version, NodeUpdater 
updater){
                this.version=version;
@@ -14,8 +15,9 @@
                this.updater = updater;
        }

-       public synchronized void set(int v, boolean ready){
-               version = v;
+       public synchronized void set(int availableVersion, int readyVersion, 
boolean ready){
+               version = availableVersion;
+               this.readyVersion = readyVersion;
                isReady = ready;
        }

@@ -32,10 +34,12 @@
                "Updating to "+version+" is advised. ";

                if(updater.inFinalCheck()) {
-                       return s + "Your node is currently doing a final check 
to verify the security of the update. 
("+updater.getRevocationDNFCounter()+"/"+NodeUpdater.REVOCATION_DNF_MIN+")";
+                       return s + "Your node is currently doing a final check 
to verify the security of the update"+
+                       (version == readyVersion ? "" : (" to "+readyVersion)) +
+                       ". 
("+updater.getRevocationDNFCounter()+"/"+NodeUpdater.REVOCATION_DNF_MIN+")";
                } else {
                        if(isReady) return s+
-                               " <form action=\"/\" method=\"post\"><input 
type=\"submit\" name=\"update\" value=\"Update Now\" /></form>";
+                               " <form action=\"/\" method=\"post\"><input 
type=\"submit\" name=\"update\" value=\"Update to "+readyVersion+" Now\" 
/></form>";
                        else return s+
                                "Your node is currently fetching the update and 
will ask you whether you want to update or not when it's ready.";
                }


Reply via email to