Fix issue with race condition when alternating UUIDs, removing locally, and mapping

This commit is contained in:
Mo Bitar
2017-11-03 18:24:09 -05:00
parent 9c406b3e96
commit c66089a55c
4 changed files with 41 additions and 18 deletions

View File

@@ -6,6 +6,7 @@ class ModelManager {
this.tags = [];
this.itemSyncObservers = [];
this.itemChangeObservers = [];
this.itemsPendingRemoval = [];
this.items = [];
this._extensions = [];
this.acceptableContentTypes = ["Note", "Tag", "Extension", "SN|Editor", "SN|Theme", "SN|Component", "SF|Extension"];
@@ -30,7 +31,7 @@ class ModelManager {
})
}
alternateUUIDForItem(item, callback) {
alternateUUIDForItem(item, callback, removeOriginal) {
// we need to clone this item and give it a new uuid, then delete item with old uuid from db (you can't mofidy uuid's in our indexeddb setup)
var newItem = this.createItem(item);
@@ -41,12 +42,20 @@ class ModelManager {
this.informModelsOfUUIDChangeForItem(newItem, item.uuid, newItem.uuid);
this.removeItemLocally(item, function(){
var block = () => {
this.addItem(newItem);
newItem.setDirty(true);
newItem.markAllReferencesDirty();
callback();
}.bind(this));
}
if(removeOriginal) {
this.removeItemLocally(item, function(){
block();
});
} else {
block();
}
}
informModelsOfUUIDChangeForItem(newItem, oldUUID, newUUID) {
@@ -94,15 +103,23 @@ class ModelManager {
// first loop should add and process items
for (var json_obj of items) {
json_obj = _.omit(json_obj, omitFields || [])
var item = this.findItem(json_obj["uuid"]);
_.omit(json_obj, omitFields);
var item = this.findItem(json_obj.uuid);
if(item) {
item.updateFromJSON(json_obj);
}
if(json_obj["deleted"] == true || !_.includes(this.acceptableContentTypes, json_obj["content_type"])) {
if(!json_obj.content && !item) {
// A new incoming item must have a content field. If not, something has set an invalid state.
console.error("Content is missing for new item.");
}
if(this.itemsPendingRemoval.includes(json_obj.uuid)) {
_.pull(this.itemsPendingRemoval, json_obj.uuid);
continue;
}
if(json_obj.deleted == true || !_.includes(this.acceptableContentTypes, json_obj["content_type"])) {
if(item) {
allModels.push(item);
this.removeItemLocally(item)
@@ -302,6 +319,8 @@ class ModelManager {
item.isBeingRemovedLocally();
this.itemsPendingRemoval.push(item.uuid);
if(item.content_type == "Tag") {
_.pull(this.tags, item);
} else if(item.content_type == "Note") {

View File

@@ -75,13 +75,16 @@ class SyncManager {
Alternating here forces us to to create duplicates of the items instead.
*/
markAllItemsDirtyAndSaveOffline(callback, alternateUUIDs) {
var originalItems = this.modelManager.allItems;
var block = (items) => {
for(var item of items) {
// use a copy, as alternating uuid will affect array
var originalItems = this.modelManager.allItems.slice();
var block = () => {
var allItems = this.modelManager.allItems;
for(var item of allItems) {
item.setDirty(true);
}
this.writeItemsToLocalStorage(items, false, callback);
this.writeItemsToLocalStorage(allItems, false, callback);
}
if(alternateUUIDs) {
@@ -90,18 +93,19 @@ class SyncManager {
let alternateNextItem = () => {
if(index >= originalItems.length) {
// We don't use originalItems as altnerating UUID will have deleted them.
block(this.modelManager.allItems);
block();
return;
}
var item = originalItems[index];
this.modelManager.alternateUUIDForItem(item, alternateNextItem);
++index;
index++;
// false => dont remove original. We want to keep both copies
this.modelManager.alternateUUIDForItem(item, alternateNextItem, false);
}
alternateNextItem();
} else {
block(originalItems);
block();
}
}
@@ -361,7 +365,7 @@ class SyncManager {
// UUID conflicts can occur if a user attempts to
// import an old data archive with uuids from the old account into a new account
handled = true;
this.modelManager.alternateUUIDForItem(item, handleNext);
this.modelManager.alternateUUIDForItem(item, handleNext, true);
}
else if(error.tag === "sync_conflict") {