Commit 34ecf915 authored by Tristan Cavelier's avatar Tristan Cavelier

replicate synchronizes on allDocs

parent 1f85aad6
...@@ -44,9 +44,7 @@ ...@@ -44,9 +44,7 @@
resolve = require('rsvp').resolve, resolve = require('rsvp').resolve,
addStorageFunction = require('jio').addStorage, addStorageFunction = require('jio').addStorage,
uniqueJSONStringify = require('jio').util.uniqueJSONStringify, uniqueJSONStringify = require('jio').util.uniqueJSONStringify,
forEach = require('jio').util.forEach,
chain = resolve(), chain = resolve(),
resolved = chain,
cache = {}; cache = {};
function logandreturn() { function logandreturn() {
...@@ -65,6 +63,52 @@ ...@@ -65,6 +63,52 @@
return promise.then(null, function (reason) { return reason; }); return promise.then(null, function (reason) { return reason; });
} }
//////////////////////////////////////////////////////////////////////
function RowFIFO() {
this.index = 0;
this.end = 0;
this.length = 0;
this.ids = {};
}
RowFIFO.prototype.extend = function (array) {
var i, l, value;
for (i = 0, l = array.length; i < l; i += 1) {
value = array[i];
if (this.ids[value.id]) { return; }
this.ids[value.id] = true;
this[this.end] = value;
this.end += 1;
this.length += 1;
}
return this;
};
RowFIFO.prototype.push = function () {
this.extend([].slice.call(arguments));
return this.length;
};
RowFIFO.prototype.shift = function () {
if (this.index >= this.end) { return; }
this.length -= 1;
var val = this[this.index];
delete this[this.index];
delete this.ids[val.id];
this.index += 1;
return val;
};
function exportAllDocsRowsToFIFO(this_storage, allDocs) {
var fifo;
fifo = this_storage._cache.rowsToSynchronize =
this_storage._cache.rowsToSynchronize || new RowFIFO();
fifo.extend(allDocs.data.rows);
}
//////////////////////////////////////////////////////////////////////
/** /**
* firstFulfilled(promises): promises< last_fulfilment_value > * firstFulfilled(promises): promises< last_fulfilment_value >
* *
...@@ -151,6 +195,36 @@ ...@@ -151,6 +195,36 @@
}, onCancel); }, onCancel);
} }
function arrayShifter(array, callback) {
var cancelled, p1 = resolve(), p2;
return new Promise(function (done, fail, notify) {
var value;
function next() {
if (array.length) {
try {
value = callback.call(null, array.shift(), array);
} catch (e) {
return fail(e);
}
if (cancelled) { return; }
if (value && typeof value.then === "function") {
p1 = value;
p2 = value.then(next, fail, notify);
} else {
p2 = p2.then(next, fail, notify);
}
return;
}
done();
}
p2 = p1.then(next);
}, function () {
cancelled = true;
if (typeof p1.cancel === "function") { p1.cancel(); }
if (typeof p2.cancel === "function") { p2.cancel(); }
});
}
// ////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////
// /** // /**
...@@ -237,13 +311,12 @@ ...@@ -237,13 +311,12 @@
} }
} }
ReplicateStorage.prototype.syncAllDocs = function (command, alldocs) { ReplicateStorage.prototype.syncRowFIFO = function (command) {
if (this._cache.syncAllDocs) { if (this._cache.syncRowFIFO) {
return this._cache.syncAllDocs; return this._cache.syncRowFIFO;
} }
console.log('syncing');
var storage_list = this._storage_list, it = this, cache_storage; var storage_list = this._storage_list, it = this, cache_storage, p;
if (this._cache_storage) { if (this._cache_storage) {
cache_storage = command.storage(this._cache_storage); cache_storage = command.storage(this._cache_storage);
} }
...@@ -252,18 +325,19 @@ ...@@ -252,18 +325,19 @@
return command.storage(description); return command.storage(description);
}); });
function doNothing() {
function returnThe404ReasonsElseNull(reason) { return;
if (reason.status === 404) {
return 404;
}
return null;
} }
function getSubStoragesDocument(id) { function getSubStoragesDocument(id) {
return all(storage_list.map(function (storage) { return all(storage_list.map(function (storage) {
return storage.get({"_id": id}). return success(storage.get({"_id": id}));
then(null, returnThe404ReasonsElseNull); }));
}
function removeSubStorageDocuments(id) {
return all(storage_list.map(function (storage) {
return success(storage.remove({"_id": id}));
})); }));
} }
...@@ -271,22 +345,34 @@ ...@@ -271,22 +345,34 @@
return it.syncGetAnswerList(command, answers); return it.syncGetAnswerList(command, answers);
} }
function is404Answer(answer) {
return answer.status === 404;
}
function isSuccessAnswer(answer) {
return answer.result === "success";
}
function checkAnswers(id, answers) { function checkAnswers(id, answers) {
if (cache_storage) { if (cache_storage) {
if (answers.every(function (answer) { if (answers.every(is404Answer)) {
return answer.status === 404;
})) {
cache_storage.remove({"_id": id}); cache_storage.remove({"_id": id});
} else if (answers.every(function (answer) { } else if (answers.every(isSuccessAnswer)) {
return answer.result === "success";
})) {
cache_storage.remove({"_id": id}); cache_storage.remove({"_id": id});
} }
} }
} }
function deleteCache() { function deleteCache() {
delete it._cache.syncAllDocs; delete it._cache.syncRowFIFO;
}
if (cache_storage) {
p = cache_storage.allDocs().then(function (answer) {
exportAllDocsRowsToFIFO(it, answer);
});
} else {
p = chain;
} }
/* /*
...@@ -300,33 +386,34 @@ ...@@ -300,33 +386,34 @@
* - a ko > b ok * - a ko > b ok
* - a ko > b ko * - a ko > b ko
*/ */
this._cache.syncAllDocs = p = p.then(function () {
forEach(alldocs.data.rows, function (row) { return arrayShifter(it._cache.rowsToSynchronize, function (row) {
if (cache_storage) {
return cache_storage.get({"_id": row.id}).then(function (answer) {
if (answer.data.state === "Deleted") {
return removeSubStorageDocuments(row.id).
then(checkAnswers.bind(null, row.id), doNothing);
}
return getSubStoragesDocument(row.id).
then(synchronizeDocument).
then(checkAnswers.bind(null, row.id), doNothing);
}, function (reason) {
if (reason.status === 404) {
return getSubStoragesDocument(row.id).
then(synchronizeDocument).
then(checkAnswers.bind(null, row.id), doNothing);
}
throw reason;
});
}
return getSubStoragesDocument(row.id). return getSubStoragesDocument(row.id).
then(synchronizeDocument). then(synchronizeDocument).
then(checkAnswers.bind(null, row.id)); then(null, doNothing);
}); });
if (cache_storage) { });
this._cache.syncAllDocs = this._cache.syncAllDocs.then(function () { p.then(deleteCache, deleteCache);
return cache_storage.allDocs({"include_docs": true}); this._cache.syncRowFIFO = p;
}).then(function (answers) { return p;
console.log(answers);
forEach(answers.data.rows, function (row) {
if (row.doc.state === "Deleted") {
return it._remove(command, {"_id": row.id}).
then(null, returnThe404ReasonsElseNull).
then(function () {
cache_storage.remove({"_id": row.id});
}).then(null, function () { return; }); // ignore error
}
return getSubStoragesDocument(row.id).
then(synchronizeDocument).
then(checkAnswers.bind(null, row.id));
});
}).then(null, function () { return; }); // ignore error
}
this._cache.syncAllDocs.then(deleteCache, deleteCache);
return this._cache.syncAllDocs;
}; };
ReplicateStorage.prototype.syncGetAnswerList = function (command, ReplicateStorage.prototype.syncGetAnswerList = function (command,
...@@ -336,7 +423,7 @@ ...@@ -336,7 +423,7 @@
/*jslint continue: true */ /*jslint continue: true */
for (i = 0, l = answer_list.length; i < l; i += 1) { for (i = 0, l = answer_list.length; i < l; i += 1) {
answer = answer_list[i]; answer = answer_list[i];
if (!answer || answer === 404) { continue; } if (!answer || answer.result !== "success") { continue; }
if (!winner) { if (!winner) {
winner = answer; winner = answer;
winner_index = i; winner_index = i;
...@@ -361,9 +448,15 @@ ...@@ -361,9 +448,15 @@
// document synchronisation // document synchronisation
for (i = 0, l = answer_list.length; i < l; i += 1) { for (i = 0, l = answer_list.length; i < l; i += 1) {
answer = answer_list[i]; answer = answer_list[i];
if (!answer) { continue; } if (!answer) {
if (i === winner_index) { continue; } promise_list.push(resolve({"status": 0}));
if (answer === 404) { continue;
}
if (i === winner_index) {
promise_list.push(resolve({"result": "success"}));
continue;
}
if (answer.status === 404) {
delete winner._id; delete winner._id;
promise_list.push(success( promise_list.push(success(
command.storage(this._storage_list[i]).post(winner) command.storage(this._storage_list[i]).post(winner)
...@@ -373,14 +466,18 @@ ...@@ -373,14 +466,18 @@
// resolving the get method. // resolving the get method.
continue; continue;
} }
delete answer._attachments; if (answer.result === "success") {
if (uniqueJSONStringify(answer.data) !== winner_str) { delete answer._attachments;
promise_list.push(success( if (uniqueJSONStringify(answer.data) !== winner_str) {
command.storage(this._storage_list[i]).put(winner) promise_list.push(success(
)); command.storage(this._storage_list[i]).put(winner)
));
continue;
}
promise_list.push(resolve({"result": "success"}));
continue; continue;
} }
promise_list.push(resolved); promise_list.push(resolve({"status": 0}));
} }
return all(promise_list); return all(promise_list);
// XXX .then synchronize attachments // XXX .then synchronize attachments
...@@ -404,6 +501,13 @@ ...@@ -404,6 +501,13 @@
if (typeof metadata._id !== "string" || metadata._id === "") { if (typeof metadata._id !== "string" || metadata._id === "") {
metadata._id = a.id; metadata._id = a.id;
} }
if (thiz._cache_storage && cache_promise === 0) {
// the metadata is set, but the cache needs to be updated
cache_promise = command.storage(thiz._cache_storage).put({
"_id": metadata._id,
"state": "Updated"
});
}
done(a); done(a);
return a; return a;
}, function (e) { }, function (e) {
...@@ -413,6 +517,8 @@ ...@@ -413,6 +517,8 @@
"_id": metadata._id, "_id": metadata._id,
"state": "Updated" "state": "Updated"
}); });
} else {
cache_promise = 0;
} }
error_count += 1; error_count += 1;
if (error_count === promises.length) { if (error_count === promises.length) {
...@@ -660,7 +766,7 @@ ...@@ -660,7 +766,7 @@
}; };
ReplicateStorage.prototype._allDocs = function (command, param, option) { ReplicateStorage.prototype._allDocs = function (command, param, option) {
var promise_list = [], index, length = this._storage_list.length; var promise_list = [], index, me = this, length = me._storage_list.length;
for (index = 0; index < length; index += 1) { for (index = 0; index < length; index += 1) {
promise_list[index] = promise_list[index] =
command.storage(this._storage_list[index]).allDocs(option); command.storage(this._storage_list[index]).allDocs(option);
...@@ -696,16 +802,15 @@ ...@@ -696,16 +802,15 @@
} }
} }
return {"data": {"total_rows": (rows || []).length, "rows": rows || []}}; return {"data": {"total_rows": (rows || []).length, "rows": rows || []}};
}).then(function (answer) {
exportAllDocsRowsToFIFO(me, answer);
me.syncRowFIFO(command);
return answer;
}); });
}; };
ReplicateStorage.prototype.allDocs = function (command, param, option) { ReplicateStorage.prototype.allDocs = function (command, param, option) {
var this_ = this;
return this._allDocs(command, param, option). return this._allDocs(command, param, option).
then(function (answer) {
this_.syncAllDocs(command, answer);
return answer;
}).
then(command.success, command.error, command.notify); then(command.success, command.error, command.notify);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment