make a more concerted attempt at doing a fresh start on various server conditions, such as missing keys, etc. clear local caches (makes it so Fx doesn't need to be restarted after a server wipe). set the lastsync pref here instead of having the window do it
authorDan Mills <thunder@mozilla.com>
Thu, 19 Feb 2009 04:09:55 -0800
changeset 45275 3b8905140ae47790b43e162d25ac5931e25ba255
parent 45274 61b1ad2729c707533bc150a747c595b6580ed436
child 45276 0f707e68a9151a82b18f3cc24e313d89d7dad626
push idunknown
push userunknown
push dateunknown
make a more concerted attempt at doing a fresh start on various server conditions, such as missing keys, etc. clear local caches (makes it so Fx doesn't need to be restarted after a server wipe). set the lastsync pref here instead of having the window do it
services/sync/modules/service.js
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -68,16 +68,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://weave/log4moz.js");
 Cu.import("resource://weave/constants.js");
 Cu.import("resource://weave/util.js");
 Cu.import("resource://weave/wrap.js");
 Cu.import("resource://weave/faultTolerance.js");
 Cu.import("resource://weave/auth.js");
 Cu.import("resource://weave/resource.js");
 Cu.import("resource://weave/base_records/wbo.js");
+Cu.import("resource://weave/base_records/crypto.js");
 Cu.import("resource://weave/base_records/keys.js");
 Cu.import("resource://weave/engines.js");
 Cu.import("resource://weave/oauth.js");
 Cu.import("resource://weave/identity.js");
 Cu.import("resource://weave/async.js");
 Cu.import("resource://weave/engines/clientData.js");
 
 Function.prototype.async = Async.sugar;
@@ -314,16 +315,19 @@ WeaveSvc.prototype = {
   // one-time initialization like setting up observers and the like
   // xxx we might need to split some of this out into something we can call
   //     again when username/server/etc changes
   _onStartup: function WeaveSvc__onStartup() {
     let self = yield;
     this._initLogs();
     this._log.info("Weave " + WEAVE_VERSION + " initializing");
 
+    if (WEAVE_VERSION != Svc.Prefs.get("lastversion"))
+      this._wipeClientMetadata();
+
     let ua = Cc["@mozilla.org/network/protocol;1?name=http"].
       getService(Ci.nsIHttpProtocolHandler).userAgent;
     this._log.info(ua);
 
     if (!this._checkCrypto()) {
       this.enabled = false;
       this._log.error("Could not load the Weave crypto component. Disabling " +
 		      "Weave, since it will not work correctly.");
@@ -559,46 +563,46 @@ WeaveSvc.prototype = {
       this._notify("server-wipe", "", this._localLock(cb))).async(this, onComplete);
   },
 
   // stuff we need to to after login, before we can really do
   // anything (e.g. key setup)
   _remoteSetup: function WeaveSvc__remoteSetup() {
     let self = yield;
     let ret = false; // false to abort sync
+    let reset = false;
 
     this._log.debug("Fetching global metadata record");
     let meta = yield Records.import(self.cb, this.clusterURL +
 				    this.username + "/meta/global");
     if (meta) {
       // FIXME: version is a string, and we don't have any version
       // parsing function so we can implement greater-than.  So we
       // just check for != which is wrong!
       if (meta.payload.storageVersion != MIN_SERVER_STORAGE_VERSION) {
-	this._log.debug("Last upload client version too old, wiping server data" +
-			"to ensure consistency");
-	yield this._wipeServer.async(this, self.cb);
+	reset = true;
+	yield this._freshStart.async(this, self.cb);
+	this._log.info("Server data wiped to ensure consistency after client upgrade");
 
-	this._log.debug("Uploading new metadata record");
-	meta.payload.storageVersion = WEAVE_VERSION;
-	let res = new Resource(meta.uri);
-	yield res.put(self.cb, meta.serialize());
+      } else if (!meta.payload.syncID) {
+	reset = true;
+	yield this._freshStart.async(this, self.cb);
+	this._log.info("Server data wiped to ensure consistency after client upgrade");
+
+      } else if (meta.payload.syncID != Clients.syncID) {
+	this._wipeClientMetadata();
+	Clients.syncID = meta.payload.syncID;
+	this._log.info("Cleared local caches after server wipe was detected");
       }
 
     } else {
       if (Records.lastResource.lastChannel.responseStatus == 404) {
-	this._log.debug("Metadata record not found, deleting all server " +
-			"data to ensure consistency");
-	yield this._wipeServer.async(this, self.cb);
-
-	this._log.debug("Uploading new metadata record");
-	meta = new WBORecord(this.clusterURL + this.username + "/meta/global");
-	meta.payload.storageVersion = WEAVE_VERSION;
-	let res = new Resource(meta.uri);
-	yield res.put(self.cb, meta.serialize());
+	reset = true;
+	yield this._freshStart.async(this, self.cb);
+	this._log.info("Metadata record not found, server wiped to ensure consistency");
 
       } else {
 	this._log.debug("Unknown error while downloading metadata record.  " +
 			"Aborting sync.");
 	self.done(false);
 	return;
       }
     }
@@ -627,16 +631,21 @@ WeaveSvc.prototype = {
 
       if (!this._keyGenEnabled) {
 	this._log.warn("Couldn't download keys from server, and key generation" +
 		       "is disabled.  Aborting sync");
 	self.done(false);
 	return;
       }
 
+      if (!reset) {
+	yield this._freshStart.async(this, self.cb);
+	this._log.info("Server data wiped to ensure consistency due to missing keys");
+      }
+
       let pass = yield ID.get('WeaveCryptoID').getPassword(self.cb);
       if (pass) {
         let keys = PubKeys.createKeypair(pass, PubKeys.defaultKeyUri,
                                          PrivKeys.defaultKeyUri);
         try {
 	  yield PubKeys.uploadKeypair(self.cb, keys);
           ret = true;
         } catch (e) {
@@ -679,20 +688,22 @@ WeaveSvc.prototype = {
           continue;
 
 	if (!(yield this._syncEngine.async(this, self.cb, engine))) {
 	  this._log.info("Aborting sync");
 	  break;
 	}
       }
 
-      if (this._syncError)
+      if (!this._syncError) {
+	Svc.Prefs.reset("lastsync");
+	Svc.Prefs.set("lastsync", Date.now());
+	this._log.info("Sync completed successfully");
+      } else
         this._log.warn("Some engines did not sync correctly");
-      else
-        this._log.info("Sync completed successfully");
 
     } finally {
       this.cancelRequested = false;
       this._syncError = false;
     }
   },
   sync: function WeaveSvc_sync(onComplete) {
     this._catchAll(
@@ -755,20 +766,22 @@ WeaveSvc.prototype = {
           // it'll stay until there's something to sync (whereupon we'll sync it,
           // reset the threshold to the initial value, and start over again).
           this._syncThresholds[engine.name] -= THRESHOLD_DECREMENT_STEP;
           if (this._syncThresholds[engine.name] <= 0)
             this._syncThresholds[engine.name] = 1;
         }
       }
 
-      if (this._syncError)
+      if (!this._syncError) {
+	Svc.Prefs.reset("lastsync");
+	Svc.Prefs.set("lastsync", Date.now());
+        this._log.info("Sync completed successfully");
+      } else
         this._log.warn("Some engines did not sync correctly");
-      else
-        this._log.info("Sync completed successfully");
 
     } finally {
       this._cancelRequested = false;
       this._syncError = false;
     }
   },
 
   // returns true if sync should proceed
@@ -782,33 +795,71 @@ WeaveSvc.prototype = {
     }
     catch(e) {
       this._syncError = true;
       if (FaultTolerance.Service.onException(e))
 	self.done(true);
     }
   },
 
+  _freshStart: function WeaveSvc__freshStart() {
+    let self = yield;
+
+    this._wipeClientMetadata();
+    this._log.info("Client metadata wiped, deleting server data");
+    yield this._wipeServer.async(this, self.cb);
+
+    this._log.debug("Uploading new metadata record");
+    meta = new WBORecord(this.clusterURL + this.username + "/meta/global");
+    meta.payload.storageVersion = WEAVE_VERSION;
+    meta.payload.syncID = Clients.syncID;
+    let res = new Resource(meta.uri);
+    yield res.put(self.cb, meta.serialize());
+  },
+
   // XXX deletes all known collections; we should have a way to delete
   //     everything on the server by querying it to get all collections
   _wipeServer: function WeaveSvc__wipeServer() {
     let self = yield;
 
+    Clients.resetSyncID();
+
     let engines = Engines.getAll();
     engines.push(Clients, {name: "keys"}, {name: "crypto"});
     for each (let engine in engines) {
       let url = this.clusterURL + this.username + "/" + engine.name + "/";
       let res = new Resource(url);
       try {
 	yield res.delete(self.cb);
       } catch (e) {
 	this._log.debug("Exception on delete: " + Utils.exceptionStr(e));
       }
       if (engine.resetLastSync)
 	engine.resetLastSync();
     }
   },
-  wipeServer: function WeaveSvc_wipeServer(onComplete) {
-    this._catchAll(
-      this._notify("wipe-server", "",
-                   this._localLock(this._wipeServer))).async(this, onComplete);
+
+  _wipeClientMetadata: function WeaveSvc__wipeClientMetadata() {
+    this.clearLogs();
+    this._log.info("Logs reinitialized");
+
+    PubKeys.clearCache();
+    PrivKeys.clearCache();
+    CryptoMetas.clearCache();
+    Records.clearCache();
+
+    Clients._store.wipe();
+    Engines.get("tabs")._store.wipe();
+
+    try {
+      let cruft = this._dirSvc.get("ProfD", Ci.nsIFile);
+      cruft.QueryInterface(Ci.nsILocalFile);
+      cruft.append("weave");
+      cruft.append("snapshots");
+      if (cruft.exists())
+	cruft.remove(true);
+    } catch (e) {
+      this._log.debug("Could not remove old snapshots: " + Utils.exceptionStr(e));
+    }
   }
 };
+
+