www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 532d48579314dcbfe350cd5d95a0b99d5ad9be86
parent 6ccfed24886370d2cb6312f542cf5dc07ababd6d
Author: Dan Stillman <dstillman@zotero.org>
Date:   Sat, 31 Oct 2015 15:19:50 -0400

Delete older versions of processed objects in cache

And recover from "Sync cache had later version than remote" error, which
shouldn't actually happen...

Diffstat:
Mchrome/content/zotero/xpcom/data/dataObject.js | 4+++-
Mchrome/content/zotero/xpcom/sync/syncEngine.js | 10+++++++---
Mchrome/content/zotero/xpcom/sync/syncLocal.js | 45++++++++++++++++++++++++++++++++++++++-------
Mtest/tests/syncLocalTest.js | 41+++++++++++++++++++++++++++++++++++++----
4 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/chrome/content/zotero/xpcom/data/dataObject.js b/chrome/content/zotero/xpcom/data/dataObject.js @@ -1193,7 +1193,9 @@ Zotero.DataObject.prototype._initErase = Zotero.Promise.method(function (env) { Zotero.DataObject.prototype._finalizeErase = Zotero.Promise.coroutine(function* (env) { // Delete versions from sync cache - yield Zotero.Sync.Data.Local.deleteCacheObject(this.objectType, this._libraryID, this._key); + yield Zotero.Sync.Data.Local.deleteCacheObjectVersions( + this.objectType, this._libraryID, this._key + ); Zotero.DB.addCurrentCallback("commit", function () { this.ObjectsClass.unload(env.deletedObjectIDs || this.id); diff --git a/chrome/content/zotero/xpcom/sync/syncEngine.js b/chrome/content/zotero/xpcom/sync/syncEngine.js @@ -1054,10 +1054,14 @@ Zotero.Sync.Data.Engine.prototype._fullSync = Zotero.Promise.coroutine(function* if (cacheVersion == version) { continue; } + // This should never happen, but recover if it does if (cacheVersion > version) { - throw new Error("Sync cache had later version than remote for " - + objectType + + this.libraryID + "/" + key - + "(" + cacheVersion + " > " + version + ")"); + Zotero.logError("Sync cache had later version than remote for " + + objectType + " " + this.libraryID + "/" + key + + " (" + cacheVersion + " > " + version + ") -- deleting"); + yield Zotero.Sync.Data.Local.deleteCacheObjectVersions( + objectType, this.libraryID, key, cacheVersion, cacheVersion + ); } if (obj) { diff --git a/chrome/content/zotero/xpcom/sync/syncLocal.js b/chrome/content/zotero/xpcom/sync/syncLocal.js @@ -521,11 +521,18 @@ Zotero.Sync.Data.Local = { let saved = yield this._saveObjectFromJSON( obj, jsonData, options, { skipCache } ); - // Mark updated attachments for download - if (saved && objectType == 'item' && obj.isImportedAttachment()) { - yield this._checkAttachmentForDownload( - obj, jsonData.mtime, isNewObject + if (saved) { + // Delete older versions of the item in the cache + yield this.deleteCacheObjectVersions( + objectType, libraryID, jsonData.key, null, jsonData.version - 1 ); + + // Mark updated attachments for download + if (objectType == 'item' && obj.isImportedAttachment()) { + yield this._checkAttachmentForDownload( + obj, jsonData.mtime, isNewObject + ); + } } if (saved) { @@ -647,11 +654,35 @@ Zotero.Sync.Data.Local = { }), - deleteCacheObject: function (objectType, libraryID, key) { + /** + * Delete one or more versions of an object from the sync cache + * + * @param {String} objectType + * @param {Integer} libraryID + * @param {String} key + * @param {Integer} [minVersion] + * @param {Integer} [maxVersion] + */ + deleteCacheObjectVersions: function (objectType, libraryID, key, minVersion, maxVersion) { var sql = "DELETE FROM syncCache WHERE libraryID=? AND key=? " + "AND syncObjectTypeID IN (SELECT syncObjectTypeID FROM " - + "syncObjectTypes WHERE name=?)";; - return Zotero.DB.queryAsync(sql, [libraryID, key, objectType]); + + "syncObjectTypes WHERE name=?)"; + var params = [libraryID, key, objectType]; + if (minVersion && minVersion == maxVersion) { + sql += " AND version=?"; + params.push(minVersion); + } + else { + if (minVersion) { + sql += " AND version>=?"; + params.push(minVersion); + } + if (maxVersion) { + sql += " AND version<=?"; + params.push(maxVersion); + } + } + return Zotero.DB.queryAsync(sql, params); }, diff --git a/test/tests/syncLocalTest.js b/test/tests/syncLocalTest.js @@ -34,7 +34,6 @@ describe("Zotero.Sync.Data.Local", function() { var libraryID = Zotero.Libraries.userLibraryID; var type = 'item'; - let objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type); let obj = yield createDataObject(type, { version: 5 }); let data = yield obj.toJSON(); yield Zotero.Sync.Data.Local.saveCacheObjects( @@ -66,6 +65,43 @@ describe("Zotero.Sync.Data.Local", function() { assert.equal(obj.getField('place'), changedPlace); }) + it("should delete older versions in sync cache after processing", function* () { + var libraryID = Zotero.Libraries.userLibraryID; + + for (let type of types) { + let obj = yield createDataObject(type, { version: 5 }); + let data = yield obj.toJSON(); + yield Zotero.Sync.Data.Local.saveCacheObjects( + type, libraryID, [data] + ); + } + + for (let type of types) { + let objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type); + + let obj = yield createDataObject(type, { version: 10 }); + let data = yield obj.toJSON(); + yield Zotero.Sync.Data.Local.saveCacheObjects( + type, libraryID, [data] + ); + yield Zotero.Sync.Data.Local.processSyncCacheForObjectType( + libraryID, type, { stopOnError: true } + ); + + let localObj = objectsClass.getByLibraryAndKey(libraryID, obj.key); + assert.equal(localObj.version, 10); + + let versions = yield Zotero.Sync.Data.Local.getCacheObjectVersions( + type, libraryID, obj.key + ); + assert.sameMembers( + versions, + [10], + "should have only latest version of " + type + " in cache" + ); + } + }) + it("should mark new attachment items for download", function* () { var libraryID = Zotero.Libraries.userLibraryID; Zotero.Sync.Storage.Local.setModeForLibrary(libraryID, 'zfs'); @@ -200,8 +236,6 @@ describe("Zotero.Sync.Data.Local", function() { var libraryID = Zotero.Libraries.userLibraryID; var type = 'item'; - var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type); - var objects = []; var values = []; var dateAdded = Date.now() - 86400000; @@ -279,7 +313,6 @@ describe("Zotero.Sync.Data.Local", function() { var libraryID = Zotero.Libraries.userLibraryID; var type = 'item'; - var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(type); var objects = []; var values = [];