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.";
}