re-enable tracker in the first-sync case just to add all the guids; add some debugging messages; when reconciling throw out records which are identical on the client and server (even if we thought they had changed)
re-enable tracker in the first-sync case just to add all the guids; add some debugging messages; when reconciling throw out records which are identical on the client and server (even if we thought they had changed)
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -399,18 +399,21 @@ SyncEngine.prototype = {
let self = yield;
this._log.debug("Calculating client changes");
// first sync special case: upload all items
if (!this.lastSync) {
this._log.info("First sync, uploading all items");
let all = yield this._getAllIDs.async(this, self.cb);
- for (let key in all)
+ this._tracker.enable();
+ for (let key in all) {
this._tracker.addChangedID(key);
+ }
+ this._tracker.disable();
}
// generate queue from changed items list
// NOTE we want changed items -> outgoing -> server to be as atomic as
// possible, so we clear the changed IDs after we upload the changed records
// NOTE2 don't encrypt, we'll do that before uploading instead
for (let id in this._tracker.changedIDs) {
this.outgoing.push(yield this._createRecord.async(this, self.cb, id, false));
@@ -476,26 +479,36 @@ SyncEngine.prototype = {
// bookmarks imported, every bookmark will match this condition.
// When two items with different IDs are "the same" we change the local ID to
// match the remote one.
_reconcile: function SyncEngine__reconcile() {
let self = yield;
this._log.debug("Reconciling server/client changes");
+ this._log.debug(this.incoming.length + " items coming in, " +
+ this.outgoing.length + " items going out");
+
// Check for the same item (same ID) on both incoming & outgoing queues
let conflicts = [];
for (let i = 0; i < this.incoming.length; i++) {
- for each (let out in this.outgoing) {
- if (this.incoming[i].id == out.id) {
- conflicts.push({in: this.incoming[i], out: out});
+ for (let o = 0; o < this.outgoing.length; o++) {
+ if (this.incoming[i].id == this.outgoing[o].id) {
+ // Only consider it a conflict if there are actual differences
+ // otherwise, just remove the outgoing record as well
+ if (!Utils.deepEquals(this.incoming[i].cleartext,
+ this.outgoing[o].cleartext))
+ conflicts.push({in: this.incoming[i], out: this.outgoing[o]});
+ else
+ delete this.outgoing[o];
delete this.incoming[i];
break;
}
}
+ this._outgoing = this.outgoing.filter(function(n) n); // removes any holes
}
this._incoming = this.incoming.filter(function(n) n); // removes any holes
if (conflicts.length)
this._log.debug("Conflicts found. Conflicting server changes discarded");
// Check for items with different IDs which we think are the same one
for (let i = 0; i < this.incoming.length; i++) {
for (let o = 0; o < this.outgoing.length; o++) {
@@ -511,16 +524,20 @@ SyncEngine.prototype = {
delete this.incoming[i];
delete this.outgoing[o];
break;
}
}
this._outgoing = this.outgoing.filter(function(n) n); // removes any holes
}
this._incoming = this.incoming.filter(function(n) n); // removes any holes
+
+ this._log.debug("Reconciliation complete");
+ this._log.debug(this.incoming.length + " items coming in, " +
+ this.outgoing.length + " items going out");
},
// Apply incoming records
_applyIncoming: function SyncEngine__applyIncoming() {
let self = yield;
if (this.incoming.length) {
this._log.debug("Applying server changes");
let inc;
@@ -547,17 +564,17 @@ SyncEngine.prototype = {
if (up.data.modified > this.lastSync)
this.lastSync = up.data.modified;
}
this._tracker.clearChangedIDs();
},
// Any cleanup necessary.
// Save the current snapshot so as to calculate changes at next sync
- _syncFinish: function SyncEngine__syncFinish() {
+ _syncFinish: function SyncEngine__syncFinish(error) {
let self = yield;
this._log.debug("Finishing up sync");
this._tracker.resetScore();
this._tracker.enable();
},
_sync: function SyncEngine__sync() {
let self = yield;
@@ -571,22 +588,25 @@ SyncEngine.prototype = {
// Decrypt and sort incoming records, then reconcile
yield this._processIncoming.async(this, self.cb);
yield this._reconcile.async(this, self.cb);
// Apply incoming records, upload outgoing records
yield this._applyIncoming.async(this, self.cb);
yield this._uploadOutgoing.async(this, self.cb);
+
+ yield this._syncFinish.async(this, self.cb);
}
catch (e) {
+ this._log.warn("Sync failed");
throw e;
}
finally {
- yield this._syncFinish.async(this, self.cb);
+ this._tracker.enable();
}
},
_resetServer: function SyncEngine__resetServer() {
let self = yield;
let all = new Resource(this.engineURL);
yield all.delete(self.cb);
}