Commit a0c3917a authored by Romain Courteaud's avatar Romain Courteaud

Release Version 3.18.0

Drop bulk prototype.
ReplicateStorage: add signature_sub_storage and signature_hash_key parameters.
parent 7c4c8878
...@@ -8428,6 +8428,15 @@ return new Parser; ...@@ -8428,6 +8428,15 @@ return new Parser;
CONFLICT_KEEP_REMOTE = 2, CONFLICT_KEEP_REMOTE = 2,
CONFLICT_CONTINUE = 3; CONFLICT_CONTINUE = 3;
function SkipError(message) {
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Skip some asynchronous code";
}
SkipError.prototype = new Error();
SkipError.prototype.constructor = SkipError;
/**************************************************** /****************************************************
Use a local jIO to read/write/search documents Use a local jIO to read/write/search documents
Synchronize in background those document with a remote jIO. Synchronize in background those document with a remote jIO.
...@@ -8446,20 +8455,33 @@ return new Parser; ...@@ -8446,20 +8455,33 @@ return new Parser;
function ReplicateStorage(spec) { function ReplicateStorage(spec) {
this._query_options = spec.query || {}; this._query_options = spec.query || {};
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage); this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage); this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
if (spec.hasOwnProperty('signature_sub_storage')) {
this._signature_sub_storage = jIO.createJIO(spec.signature_sub_storage);
this._custom_signature_sub_storage = true;
} else {
this._signature_hash = "_replicate_" + generateHash( this._signature_hash = "_replicate_" + generateHash(
stringify(spec.local_sub_storage) + stringify(spec.local_sub_storage) +
stringify(spec.remote_sub_storage) + stringify(spec.remote_sub_storage) +
stringify(this._query_options) stringify(this._query_options)
); );
this._signature_sub_storage = jIO.createJIO({ this._signature_sub_storage = jIO.createJIO({
type: "query",
sub_storage: {
type: "document", type: "document",
document_id: this._signature_hash, document_id: this._signature_hash,
sub_storage: spec.signature_storage || spec.local_sub_storage sub_storage: spec.local_sub_storage
}
}); });
this._custom_signature_sub_storage = false;
}
this._use_remote_post = spec.use_remote_post || false; this._use_remote_post = spec.use_remote_post || false;
// Number of request we allow browser execution for attachments // Number of request we allow browser execution for attachments
...@@ -8602,15 +8624,8 @@ return new Parser; ...@@ -8602,15 +8624,8 @@ return new Parser;
arguments); arguments);
}; };
ReplicateStorage.prototype.repair = function () { function dispatchQueue(context, function_used, argument_list,
var context = this, number_queue) {
argument_list = arguments,
skip_document_dict = {};
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
function dispatchQueue(function_used, argument_list, number_queue) {
var result_promise_list = [], var result_promise_list = [],
i; i;
...@@ -8637,7 +8652,27 @@ return new Parser; ...@@ -8637,7 +8652,27 @@ return new Parser;
return result_promise_list[0]; return result_promise_list[0];
} }
function propagateAttachmentDeletion(skip_attachment_dict, function callAllDocsOnStorage(context, storage, cache, cache_key) {
return new RSVP.Queue()
.push(function () {
if (!cache.hasOwnProperty(cache_key)) {
return storage.allDocs(context._query_options)
.push(function (result) {
var i,
cache_entry = {};
for (i = 0; i < result.data.total_rows; i += 1) {
cache_entry[result.data.rows[i].id] = result.data.rows[i].value;
}
cache[cache_key] = cache_entry;
});
}
})
.push(function () {
return cache[cache_key];
});
}
function propagateAttachmentDeletion(context, skip_attachment_dict,
destination, destination,
id, name) { id, name) {
return destination.removeAttachment(id, name) return destination.removeAttachment(id, name)
...@@ -8649,7 +8684,7 @@ return new Parser; ...@@ -8649,7 +8684,7 @@ return new Parser;
}); });
} }
function propagateAttachmentModification(skip_attachment_dict, function propagateAttachmentModification(context, skip_attachment_dict,
destination, destination,
blob, hash, id, name) { blob, hash, id, name) {
return destination.putAttachment(id, name, blob) return destination.putAttachment(id, name, blob)
...@@ -8664,7 +8699,8 @@ return new Parser; ...@@ -8664,7 +8699,8 @@ return new Parser;
}); });
} }
function checkAndPropagateAttachment(skip_attachment_dict, function checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob, status_hash, local_hash, blob,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8694,7 +8730,7 @@ return new Parser; ...@@ -8694,7 +8730,7 @@ return new Parser;
// Deleted on both side, drop signature // Deleted on both side, drop signature
return context._signature_sub_storage.removeAttachment(id, name) return context._signature_sub_storage.removeAttachment(id, name)
.push(function () { .push(function () {
skip_attachment_dict[id] = null; skip_attachment_dict[name] = null;
}); });
} }
...@@ -8703,7 +8739,7 @@ return new Parser; ...@@ -8703,7 +8739,7 @@ return new Parser;
hash: local_hash hash: local_hash
})) }))
.push(function () { .push(function () {
skip_document_dict[id] = null; skip_attachment_dict[name] = null;
}); });
} }
...@@ -8711,11 +8747,12 @@ return new Parser; ...@@ -8711,11 +8747,12 @@ return new Parser;
// Modified only locally. No conflict or force // Modified only locally. No conflict or force
if (local_hash === null) { if (local_hash === null) {
// Deleted locally // Deleted locally
return propagateAttachmentDeletion(skip_attachment_dict, return propagateAttachmentDeletion(context, skip_attachment_dict,
destination, destination,
id, name); id, name);
} }
return propagateAttachmentModification(skip_attachment_dict, return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob, destination, blob,
local_hash, id, name); local_hash, id, name);
} }
...@@ -8729,10 +8766,11 @@ return new Parser; ...@@ -8729,10 +8766,11 @@ return new Parser;
// Automatically resolve conflict or force revert // Automatically resolve conflict or force revert
if (remote_hash === null) { if (remote_hash === null) {
// Deleted remotely // Deleted remotely
return propagateAttachmentDeletion(skip_attachment_dict, return propagateAttachmentDeletion(context, skip_attachment_dict,
source, id, name); source, id, name);
} }
return propagateAttachmentModification( return propagateAttachmentModification(
context,
skip_attachment_dict, skip_attachment_dict,
source, source,
remote_blob, remote_blob,
...@@ -8745,7 +8783,8 @@ return new Parser; ...@@ -8745,7 +8783,8 @@ return new Parser;
// Minimize conflict if it can be resolved // Minimize conflict if it can be resolved
if (remote_hash === null) { if (remote_hash === null) {
// Copy remote modification remotely // Copy remote modification remotely
return propagateAttachmentModification(skip_attachment_dict, return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob, destination, blob,
local_hash, id, name); local_hash, id, name);
} }
...@@ -8756,7 +8795,8 @@ return new Parser; ...@@ -8756,7 +8795,8 @@ return new Parser;
}); });
} }
function checkAttachmentSignatureDifference(queue, skip_attachment_dict, function checkAttachmentSignatureDifference(queue, context,
skip_attachment_dict,
source, source,
destination, id, name, destination, id, name,
conflict_force, conflict_force,
...@@ -8798,7 +8838,8 @@ return new Parser; ...@@ -8798,7 +8838,8 @@ return new Parser;
local_hash = generateHashFromArrayBuffer(array_buffer); local_hash = generateHashFromArrayBuffer(array_buffer);
if (local_hash !== status_hash) { if (local_hash !== status_hash) {
return checkAndPropagateAttachment(skip_attachment_dict, return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob, status_hash, local_hash, blob,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8807,7 +8848,8 @@ return new Parser; ...@@ -8807,7 +8848,8 @@ return new Parser;
}); });
} }
function checkAttachmentLocalDeletion(queue, skip_attachment_dict, function checkAttachmentLocalDeletion(queue, context,
skip_attachment_dict,
destination, id, name, source, destination, id, name, source,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore) { conflict_ignore) {
...@@ -8819,7 +8861,8 @@ return new Parser; ...@@ -8819,7 +8861,8 @@ return new Parser;
}) })
.push(function (result) { .push(function (result) {
status_hash = result.hash; status_hash = result.hash;
return checkAndPropagateAttachment(skip_attachment_dict, return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, null, null, status_hash, null, null,
source, destination, id, name, source, destination, id, name,
conflict_force, conflict_revert, conflict_force, conflict_revert,
...@@ -8827,24 +8870,13 @@ return new Parser; ...@@ -8827,24 +8870,13 @@ return new Parser;
}); });
} }
function pushDocumentAttachment(skip_attachment_dict, id, source, function pushDocumentAttachment(context,
destination, options) { skip_attachment_dict, id, source,
var queue = new RSVP.Queue(), destination, signature_allAttachments,
local_dict = {}, options) {
var local_dict = {},
signature_dict = {}; signature_dict = {};
return source.allAttachments(id)
return queue
.push(function () {
return RSVP.all([
source.allAttachments(id)
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
}),
context._signature_sub_storage.allAttachments(id)
.push(undefined, function (error) { .push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) && if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) { (error.status_code === 404)) {
...@@ -8852,22 +8884,20 @@ return new Parser; ...@@ -8852,22 +8884,20 @@ return new Parser;
} }
throw error; throw error;
}) })
]); .push(function (source_allAttachments) {
})
.push(function (result_list) {
var is_modification, var is_modification,
is_creation, is_creation,
key, key,
argument_list = []; argument_list = [];
for (key in result_list[0]) { for (key in source_allAttachments) {
if (result_list[0].hasOwnProperty(key)) { if (source_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) { if (!skip_attachment_dict.hasOwnProperty(key)) {
local_dict[key] = null; local_dict[key] = null;
} }
} }
} }
for (key in result_list[1]) { for (key in signature_allAttachments) {
if (result_list[1].hasOwnProperty(key)) { if (signature_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) { if (!skip_attachment_dict.hasOwnProperty(key)) {
signature_dict[key] = null; signature_dict[key] = null;
} }
...@@ -8882,6 +8912,7 @@ return new Parser; ...@@ -8882,6 +8912,7 @@ return new Parser;
&& options.check_creation; && options.check_creation;
if (is_modification === true || is_creation === true) { if (is_modification === true || is_creation === true) {
argument_list.push([undefined, argument_list.push([undefined,
context,
skip_attachment_dict, skip_attachment_dict,
source, source,
destination, id, key, destination, id, key,
...@@ -8894,6 +8925,7 @@ return new Parser; ...@@ -8894,6 +8925,7 @@ return new Parser;
} }
} }
return dispatchQueue( return dispatchQueue(
context,
checkAttachmentSignatureDifference, checkAttachmentSignatureDifference,
argument_list, argument_list,
context._parallel_operation_attachment_amount context._parallel_operation_attachment_amount
...@@ -8906,6 +8938,7 @@ return new Parser; ...@@ -8906,6 +8938,7 @@ return new Parser;
if (signature_dict.hasOwnProperty(key)) { if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) { if (!local_dict.hasOwnProperty(key)) {
argument_list.push([undefined, argument_list.push([undefined,
context,
skip_attachment_dict, skip_attachment_dict,
destination, id, key, destination, id, key,
source, source,
...@@ -8916,6 +8949,7 @@ return new Parser; ...@@ -8916,6 +8949,7 @@ return new Parser;
} }
} }
return dispatchQueue( return dispatchQueue(
context,
checkAttachmentLocalDeletion, checkAttachmentLocalDeletion,
argument_list, argument_list,
context._parallel_operation_attachment_amount context._parallel_operation_attachment_amount
...@@ -8924,19 +8958,38 @@ return new Parser; ...@@ -8924,19 +8958,38 @@ return new Parser;
}); });
} }
function repairDocumentAttachment(context, id) {
function repairDocumentAttachment(id) {
var skip_attachment_dict = {}; var skip_attachment_dict = {};
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if (context._check_local_attachment_modification ||
context._check_local_attachment_creation ||
context._check_local_attachment_deletion ||
context._check_remote_attachment_modification ||
context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) {
return context._signature_sub_storage.allAttachments(id);
}
return {};
})
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
})
.push(function (signature_allAttachments) {
if (context._check_local_attachment_modification || if (context._check_local_attachment_modification ||
context._check_local_attachment_creation || context._check_local_attachment_creation ||
context._check_local_attachment_deletion) { context._check_local_attachment_deletion) {
return pushDocumentAttachment( return pushDocumentAttachment(
context,
skip_attachment_dict, skip_attachment_dict,
id, id,
context._local_sub_storage, context._local_sub_storage,
context._remote_sub_storage, context._remote_sub_storage,
signature_allAttachments,
{ {
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_LOCAL), CONFLICT_KEEP_LOCAL),
...@@ -8949,18 +9002,24 @@ return new Parser; ...@@ -8949,18 +9002,24 @@ return new Parser;
check_creation: context._check_local_attachment_creation, check_creation: context._check_local_attachment_creation,
check_deletion: context._check_local_attachment_deletion check_deletion: context._check_local_attachment_deletion
} }
); )
.push(function () {
return signature_allAttachments;
});
} }
return signature_allAttachments;
}) })
.push(function () { .push(function (signature_allAttachments) {
if (context._check_remote_attachment_modification || if (context._check_remote_attachment_modification ||
context._check_remote_attachment_creation || context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) { context._check_remote_attachment_deletion) {
return pushDocumentAttachment( return pushDocumentAttachment(
context,
skip_attachment_dict, skip_attachment_dict,
id, id,
context._remote_sub_storage, context._remote_sub_storage,
context._local_sub_storage, context._local_sub_storage,
signature_allAttachments,
{ {
use_revert_post: context._use_remote_post, use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
...@@ -8979,16 +9038,35 @@ return new Parser; ...@@ -8979,16 +9038,35 @@ return new Parser;
}); });
} }
function propagateModification(source, destination, doc, hash, id, function propagateModification(context, source, destination, doc, hash, id,
skip_document_dict,
options) { options) {
var result, var result = new RSVP.Queue(),
post_id, post_id,
to_skip = true; to_skip = true;
if (options === undefined) { if (options === undefined) {
options = {}; options = {};
} }
if (doc === null) {
result
.push(function () {
return source.get(id);
})
.push(function (source_doc) {
doc = source_doc;
}, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
throw new SkipError(id);
}
throw error;
});
}
if (options.use_post) { if (options.use_post) {
result = destination.post(doc) result
.push(function () {
return destination.post(doc);
})
.push(function (new_id) { .push(function (new_id) {
to_skip = false; to_skip = false;
post_id = new_id; post_id = new_id;
...@@ -9037,7 +9115,10 @@ return new Parser; ...@@ -9037,7 +9115,10 @@ return new Parser;
skip_document_dict[post_id] = null; skip_document_dict[post_id] = null;
}); });
} else { } else {
result = destination.put(id, doc) result
.push(function () {
return destination.put(id, doc);
})
.push(function () { .push(function () {
return context._signature_sub_storage.put(id, { return context._signature_sub_storage.put(id, {
"hash": hash "hash": hash
...@@ -9049,15 +9130,21 @@ return new Parser; ...@@ -9049,15 +9130,21 @@ return new Parser;
if (to_skip) { if (to_skip) {
skip_document_dict[id] = null; skip_document_dict[id] = null;
} }
})
.push(undefined, function (error) {
if (error instanceof SkipError) {
return;
}
throw error;
}); });
} }
function propagateDeletion(destination, id) { function propagateDeletion(context, destination, id, skip_document_dict) {
// Do not delete a document if it has an attachment // Do not delete a document if it has an attachment
// ie, replication should prevent losing user data // ie, replication should prevent losing user data
// Synchronize attachments before, to ensure // Synchronize attachments before, to ensure
// all of them will be deleted too // all of them will be deleted too
return repairDocumentAttachment(id) return repairDocumentAttachment(context, id)
.push(function () { .push(function () {
return destination.allAttachments(id); return destination.allAttachments(id);
}) })
...@@ -9080,11 +9167,25 @@ return new Parser; ...@@ -9080,11 +9167,25 @@ return new Parser;
}); });
} }
function checkAndPropagate(status_hash, local_hash, doc, function checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
options) { options) {
return new RSVP.Queue()
.push(function () {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
}
return destination.get(id) return destination.get(id)
.push(function (remote_doc) { .push(function (remote_doc) {
return [remote_doc, generateHash(stringify(remote_doc))]; return [remote_doc, generateHash(stringify(remote_doc))];
...@@ -9094,11 +9195,12 @@ return new Parser; ...@@ -9094,11 +9195,12 @@ return new Parser;
return [null, null]; return [null, null];
} }
throw error; throw error;
});
}) })
.push(function (remote_list) { .push(function (remote_list) {
var remote_doc = remote_list[0], var remote_doc = remote_list[0],
remote_hash = remote_list[1]; remote_hash = remote_list[1];
if (local_hash === remote_hash) { if (local_hash === remote_hash) {
// Same modifications on both side // Same modifications on both side
if (local_hash === null) { if (local_hash === null) {
...@@ -9121,10 +9223,11 @@ return new Parser; ...@@ -9121,10 +9223,11 @@ return new Parser;
// Modified only locally. No conflict or force // Modified only locally. No conflict or force
if (local_hash === null) { if (local_hash === null) {
// Deleted locally // Deleted locally
return propagateDeletion(destination, id); return propagateDeletion(context, destination, id,
skip_document_dict);
} }
return propagateModification(source, destination, doc, return propagateModification(context, source, destination, doc,
local_hash, id, local_hash, id, skip_document_dict,
{use_post: ((options.use_post) && {use_post: ((options.use_post) &&
(remote_hash === null))}); (remote_hash === null))});
} }
...@@ -9138,14 +9241,16 @@ return new Parser; ...@@ -9138,14 +9241,16 @@ return new Parser;
// Automatically resolve conflict or force revert // Automatically resolve conflict or force revert
if (remote_hash === null) { if (remote_hash === null) {
// Deleted remotely // Deleted remotely
return propagateDeletion(source, id); return propagateDeletion(context, source, id, skip_document_dict);
} }
return propagateModification( return propagateModification(
context,
destination, destination,
source, source,
remote_doc, remote_doc,
remote_hash, remote_hash,
id, id,
skip_document_dict,
{use_post: ((options.use_revert_post) && {use_post: ((options.use_revert_post) &&
(local_hash === null))} (local_hash === null))}
); );
...@@ -9154,18 +9259,22 @@ return new Parser; ...@@ -9154,18 +9259,22 @@ return new Parser;
// Minimize conflict if it can be resolved // Minimize conflict if it can be resolved
if (remote_hash === null) { if (remote_hash === null) {
// Copy remote modification remotely // Copy remote modification remotely
return propagateModification(source, destination, doc, return propagateModification(context, source, destination, doc,
local_hash, id, local_hash, id, skip_document_dict,
{use_post: options.use_post}); {use_post: options.use_post});
} }
doc = doc || local_hash;
remote_doc = remote_doc || remote_hash;
throw new jIO.util.jIOError("Conflict on '" + id + "': " + throw new jIO.util.jIOError("Conflict on '" + id + "': " +
stringify(doc || '') + " !== " + stringify(doc) + " !== " +
stringify(remote_doc || ''), stringify(remote_doc),
409); 409);
}); });
} }
function checkLocalDeletion(queue, destination, id, source, function checkLocalDeletion(queue, context, skip_document_dict,
cache, destination_key,
destination, id, source,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, options) { conflict_ignore, options) {
var status_hash; var status_hash;
...@@ -9175,7 +9284,9 @@ return new Parser; ...@@ -9175,7 +9284,9 @@ return new Parser;
}) })
.push(function (result) { .push(function (result) {
status_hash = result.hash; status_hash = result.hash;
return checkAndPropagate(status_hash, null, null, return checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, null, null,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
...@@ -9183,37 +9294,31 @@ return new Parser; ...@@ -9183,37 +9294,31 @@ return new Parser;
}); });
} }
function checkSignatureDifference(queue, source, destination, id, function checkSignatureDifference(queue, context, skip_document_dict,
cache, destination_key,
source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
is_creation, is_modification, local_hash, status_hash,
getMethod, options) { options) {
queue queue
.push(function () { .push(function () {
// Optimisation to save a get call to signature storage if (local_hash === null) {
if (is_creation === true) { // Hash was not provided by the allDocs query
return RSVP.all([ return source.get(id);
getMethod(id),
{hash: null}
]);
}
if (is_modification === true) {
return RSVP.all([
getMethod(id),
context._signature_sub_storage.get(id)
]);
} }
throw new jIO.util.jIOError("Unexpected call of" return null;
+ " checkSignatureDifference",
409);
}) })
.push(function (result_list) { .push(function (doc) {
var doc = result_list[0], if (local_hash === null) {
local_hash = generateHash(stringify(doc)), // Hash was not provided by the allDocs query
status_hash = result_list[1].hash; local_hash = generateHash(stringify(doc));
}
if (local_hash !== status_hash) { if (local_hash !== status_hash) {
return checkAndPropagate(status_hash, local_hash, doc, return checkAndPropagate(context, skip_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id, source, destination, id,
conflict_force, conflict_revert, conflict_force, conflict_revert,
conflict_ignore, conflict_ignore,
...@@ -9222,47 +9327,10 @@ return new Parser; ...@@ -9222,47 +9327,10 @@ return new Parser;
}); });
} }
function checkBulkSignatureDifference(queue, source, destination, id_list, function pushStorage(context, skip_document_dict,
document_status_list, options, cache, source_key, destination_key,
conflict_force, conflict_revert, source, destination, signature_allDocs, options) {
conflict_ignore) { var argument_list = [],
queue
.push(function () {
return source.bulk(id_list);
})
.push(function (result_list) {
var i,
argument_list = [];
function getResult(j) {
return function (id) {
if (id !== id_list[j].parameter_list[0]) {
throw new Error("Does not access expected ID " + id);
}
return result_list[j];
};
}
for (i = 0; i < result_list.length; i += 1) {
argument_list[i] = [undefined, source, destination,
id_list[i].parameter_list[0],
conflict_force, conflict_revert,
conflict_ignore,
document_status_list[i].is_creation,
document_status_list[i].is_modification,
getResult(i), options];
}
return dispatchQueue(
checkSignatureDifference,
argument_list,
options.operation_amount
);
});
}
function pushStorage(source, destination, options) {
var queue = new RSVP.Queue(),
argument_list = [],
argument_list_deletion = []; argument_list_deletion = [];
if (!options.hasOwnProperty("use_post")) { if (!options.hasOwnProperty("use_post")) {
options.use_post = false; options.use_post = false;
...@@ -9270,127 +9338,150 @@ return new Parser; ...@@ -9270,127 +9338,150 @@ return new Parser;
if (!options.hasOwnProperty("use_revert_post")) { if (!options.hasOwnProperty("use_revert_post")) {
options.use_revert_post = false; options.use_revert_post = false;
} }
return queue return callAllDocsOnStorage(context, source, cache, source_key)
.push(function () { .push(function (source_allDocs) {
return RSVP.all([
source.allDocs(context._query_options),
context._signature_sub_storage.allDocs()
]);
})
.push(function (result_list) {
var i, var i,
local_dict = {}, local_dict = {},
document_list = [],
document_status_list = [],
signature_dict = {}, signature_dict = {},
is_modification, is_modification,
is_creation, is_creation,
key; status_hash,
for (i = 0; i < result_list[0].data.total_rows; i += 1) { local_hash,
key,
queue = new RSVP.Queue();
for (key in source_allDocs) {
if (source_allDocs.hasOwnProperty(key)) {
if (!skip_document_dict.hasOwnProperty(key)) {
local_dict[key] = source_allDocs[key];
}
}
}
/*
for (i = 0; i < source_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty( if (!skip_document_dict.hasOwnProperty(
result_list[0].data.rows[i].id source_allDocs.data.rows[i].id
)) { )) {
local_dict[result_list[0].data.rows[i].id] = i; local_dict[source_allDocs.data.rows[i].id] =
source_allDocs.data.rows[i].value;
} }
} }
for (i = 0; i < result_list[1].data.total_rows; i += 1) { */
for (i = 0; i < signature_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty( if (!skip_document_dict.hasOwnProperty(
result_list[1].data.rows[i].id signature_allDocs.data.rows[i].id
)) { )) {
signature_dict[result_list[1].data.rows[i].id] = i; signature_dict[signature_allDocs.data.rows[i].id] =
signature_allDocs.data.rows[i].value.hash;
} }
} }
i = 0;
for (key in local_dict) { for (key in local_dict) {
if (local_dict.hasOwnProperty(key)) { if (local_dict.hasOwnProperty(key)) {
is_modification = signature_dict.hasOwnProperty(key) is_modification = signature_dict.hasOwnProperty(key)
&& options.check_modification; && options.check_modification;
is_creation = !signature_dict.hasOwnProperty(key) is_creation = !signature_dict.hasOwnProperty(key)
&& options.check_creation; && options.check_creation;
if (is_creation === true) {
status_hash = null;
} else if (is_modification === true) {
status_hash = signature_dict[key];
}
local_hash = null;
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
is_modification = false;
if (local_hash !== status_hash) {
is_modification = true;
}
}
}
if (is_modification === true || is_creation === true) { if (is_modification === true || is_creation === true) {
if (options.use_bulk_get === true) { argument_list.push([undefined, context, skip_document_dict,
document_list.push({ cache, destination_key,
method: "get", source, destination,
parameter_list: [key]
});
document_status_list.push({
is_creation: is_creation,
is_modification: is_modification
});
} else {
argument_list[i] = [undefined, source, destination,
key, key,
options.conflict_force, options.conflict_force,
options.conflict_revert, options.conflict_revert,
options.conflict_ignore, options.conflict_ignore,
is_creation, is_modification, local_hash, status_hash,
source.get.bind(source), options]);
options];
i += 1;
}
} }
} }
} }
queue queue
.push(function () { .push(function () {
return dispatchQueue( return dispatchQueue(
context,
checkSignatureDifference, checkSignatureDifference,
argument_list, argument_list,
options.operation_amount options.operation_amount
); );
}); });
if (options.check_deletion === true) { if (options.check_deletion === true) {
i = 0;
for (key in signature_dict) { for (key in signature_dict) {
if (signature_dict.hasOwnProperty(key)) { if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) { if (!local_dict.hasOwnProperty(key)) {
argument_list_deletion[i] = [undefined, argument_list_deletion.push([undefined,
context,
skip_document_dict,
cache, destination_key,
destination, key, destination, key,
source, source,
options.conflict_force, options.conflict_force,
options.conflict_revert, options.conflict_revert,
options.conflict_ignore, options.conflict_ignore,
options]; options]);
i += 1;
} }
} }
} }
queue.push(function () { queue.push(function () {
return dispatchQueue( return dispatchQueue(
context,
checkLocalDeletion, checkLocalDeletion,
argument_list_deletion, argument_list_deletion,
options.operation_amount options.operation_amount
); );
}); });
} }
if ((options.use_bulk_get === true) && (document_list.length !== 0)) { return queue;
checkBulkSignatureDifference(queue, source, destination,
document_list, document_status_list,
options,
options.conflict_force,
options.conflict_revert,
options.conflict_ignore);
}
}); });
} }
function repairDocument(queue, id) { function repairDocument(queue, context, id) {
queue.push(function () { queue.push(function () {
return repairDocumentAttachment(id); return repairDocumentAttachment(context, id);
}); });
} }
ReplicateStorage.prototype.repair = function () {
var context = this,
argument_list = arguments,
skip_document_dict = {},
cache = {};
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
// Ensure that the document storage is usable // Ensure that the document storage is usable
return context._signature_sub_storage.__storage._sub_storage.get( if (context._custom_signature_sub_storage === false) {
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.get(
context._signature_hash context._signature_hash
); );
}
}) })
.push(undefined, function (error) { .push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) && if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) { (error.status_code === 404)) {
return context._signature_sub_storage.__storage._sub_storage.put( return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.put(
context._signature_hash, context._signature_hash,
{} {}
); );
...@@ -9417,11 +9508,27 @@ return new Parser; ...@@ -9417,11 +9508,27 @@ return new Parser;
}) })
.push(function () { .push(function () {
if (context._check_local_modification ||
context._check_local_creation ||
context._check_local_deletion ||
context._check_remote_modification ||
context._check_remote_creation ||
context._check_remote_deletion) {
return context._signature_sub_storage.allDocs({
select_list: ['hash']
});
}
})
.push(function (signature_allDocs) {
if (context._check_local_modification || if (context._check_local_modification ||
context._check_local_creation || context._check_local_creation ||
context._check_local_deletion) { context._check_local_deletion) {
return pushStorage(context._local_sub_storage, return pushStorage(context, skip_document_dict,
cache, 'local', 'remote',
context._local_sub_storage,
context._remote_sub_storage, context._remote_sub_storage,
signature_allDocs,
{ {
use_post: context._use_remote_post, use_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
...@@ -9433,28 +9540,24 @@ return new Parser; ...@@ -9433,28 +9540,24 @@ return new Parser;
check_modification: context._check_local_modification, check_modification: context._check_local_modification,
check_creation: context._check_local_creation, check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion, check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount operation_amount: context._parallel_operation_amount,
}); signature_hash_key: context._signature_hash_key
}
}) })
.push(function () { .push(function () {
// Autoactivate bulk if substorage implements it return signature_allDocs;
// Keep it like this until the bulk API is stabilized });
var use_bulk_get = false;
try {
use_bulk_get = context._remote_sub_storage.hasCapacity("bulk_get");
} catch (error) {
if (!((error instanceof jIO.util.jIOError) &&
(error.status_code === 501))) {
throw error;
}
} }
return signature_allDocs;
})
.push(function (signature_allDocs) {
if (context._check_remote_modification || if (context._check_remote_modification ||
context._check_remote_creation || context._check_remote_creation ||
context._check_remote_deletion) { context._check_remote_deletion) {
return pushStorage(context._remote_sub_storage, return pushStorage(context, skip_document_dict,
context._local_sub_storage, { cache, 'remote', 'local',
use_bulk_get: use_bulk_get, context._remote_sub_storage,
context._local_sub_storage,
signature_allDocs, {
use_revert_post: context._use_remote_post, use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling === conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_REMOTE), CONFLICT_KEEP_REMOTE),
...@@ -9465,7 +9568,8 @@ return new Parser; ...@@ -9465,7 +9568,8 @@ return new Parser;
check_modification: context._check_remote_modification, check_modification: context._check_remote_modification,
check_creation: context._check_remote_creation, check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion, check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount operation_amount: context._parallel_operation_amount,
signature_hash_key: context._signature_hash_key
}); });
} }
}) })
...@@ -9481,17 +9585,18 @@ return new Parser; ...@@ -9481,17 +9585,18 @@ return new Parser;
return context._signature_sub_storage.allDocs() return context._signature_sub_storage.allDocs()
.push(function (result) { .push(function (result) {
var i, var i,
argument_list = [], local_argument_list = [],
len = result.data.total_rows; len = result.data.total_rows;
for (i = 0; i < len; i += 1) { for (i = 0; i < len; i += 1) {
argument_list.push( local_argument_list.push(
[undefined, result.data.rows[i].id] [undefined, context, result.data.rows[i].id]
); );
} }
return dispatchQueue( return dispatchQueue(
context,
repairDocument, repairDocument,
argument_list, local_argument_list,
context._parallel_operation_amount context._parallel_operation_amount
); );
}); });
...@@ -11154,56 +11259,6 @@ return new Parser; ...@@ -11154,56 +11259,6 @@ return new Parser;
}); });
}; };
ERP5Storage.prototype.bulk = function (request_list) {
var i,
storage = this,
bulk_list = [];
for (i = 0; i < request_list.length; i += 1) {
if (request_list[i].method !== "get") {
throw new Error("ERP5Storage: not supported " +
request_list[i].method + " in bulk");
}
bulk_list.push({
relative_url: request_list[i].parameter_list[0],
view: storage._default_view_reference
});
}
return getSiteDocument(storage)
.push(function (site_hal) {
var form_data = new FormData();
form_data.append("bulk_list", JSON.stringify(bulk_list));
return jIO.util.ajax({
"type": "POST",
"url": site_hal._actions.bulk.href,
"data": form_data,
// "headers": {
// "Content-Type": "application/json"
// },
"xhrFields": {
withCredentials: true
}
});
})
.push(function (response) {
var result_list = [],
hateoas = JSON.parse(response.target.responseText);
function pushResult(json) {
return extractPropertyFromFormJSON(json)
.push(function (json2) {
return convertJSONToGet(json2);
});
}
for (i = 0; i < hateoas.result_list.length; i += 1) {
result_list.push(pushResult(hateoas.result_list[i]));
}
return RSVP.all(result_list);
});
};
ERP5Storage.prototype.post = function (data) { ERP5Storage.prototype.post = function (data) {
var context = this, var context = this,
new_id; new_id;
...@@ -11430,7 +11485,7 @@ return new Parser; ...@@ -11430,7 +11485,7 @@ return new Parser;
ERP5Storage.prototype.hasCapacity = function (name) { ERP5Storage.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query") || return ((name === "list") || (name === "query") ||
(name === "select") || (name === "limit") || (name === "select") || (name === "limit") ||
(name === "sort")) || (name === "bulk_get"); (name === "sort"));
}; };
function isSingleLocalRoles(parsed_query) { function isSingleLocalRoles(parsed_query) {
...@@ -13007,12 +13062,12 @@ return new Parser; ...@@ -13007,12 +13062,12 @@ return new Parser;
}) })
.push(function (dataURL) { .push(function (dataURL) {
//string->arraybuffer //string->arraybuffer
var strLen = dataURL.currentTarget.result.length, var strLen = dataURL.target.result.length,
buf = new ArrayBuffer(strLen), buf = new ArrayBuffer(strLen),
bufView = new Uint8Array(buf), bufView = new Uint8Array(buf),
i; i;
dataURL = dataURL.currentTarget.result; dataURL = dataURL.target.result;
for (i = 0; i < strLen; i += 1) { for (i = 0; i < strLen; i += 1) {
bufView[i] = dataURL.charCodeAt(i); bufView[i] = dataURL.charCodeAt(i);
} }
...@@ -13049,7 +13104,7 @@ return new Parser; ...@@ -13049,7 +13104,7 @@ return new Parser;
.push(function (coded) { .push(function (coded) {
var initializaton_vector; var initializaton_vector;
coded = coded.currentTarget.result; coded = coded.target.result;
initializaton_vector = new Uint8Array(coded.slice(0, 12)); initializaton_vector = new Uint8Array(coded.slice(0, 12));
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
...@@ -13268,7 +13323,7 @@ return new Parser; ...@@ -13268,7 +13323,7 @@ return new Parser;
return jIO.util.readBlobAsDataURL(blob); return jIO.util.readBlobAsDataURL(blob);
}) })
.push(function (strBlob) { .push(function (strBlob) {
argument_list[index + 2].push(strBlob.currentTarget.result); argument_list[index + 2].push(strBlob.target.result);
return; return;
}); });
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{ {
"name": "jio", "name": "jio",
"version": "v3.17.0", "version": "v3.18.0",
"license": "LGPLv3", "license": "LGPLv3",
"author": "Nexedi SA", "author": "Nexedi SA",
"contributors": [ "contributors": [
......
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