Commit d7fcbbaf authored by Tristan Cavelier's avatar Tristan Cavelier

Revision storage redesigned to avoid some unknown errors

parent 049ea125
......@@ -187,6 +187,253 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
}
};
////////////////////////////////////////////////////////////////////////////////
that.check = function (command) {
priv.check(
command.cloneDoc(),
command.cloneOption(),
that.success,
that.error
);
};
that.repair = function (command) {
priv.repair(
command.cloneDoc(),
command.cloneOption(),
true,
that.success,
that.error
);
};
priv.check = function (doc, option, success, error) {
priv.repair(doc, option, false, success, error);
};
priv.repair = function (doc, option, repair, callback) {
var functions = {};
// console.log("priv.repair");
callback = callback || priv.emptyFunction;
option = option || {};
functions.begin = function () {
// console.log("repair begin");
functions.getAllDocuments(functions.newParam(
doc,
option,
repair
));
};
functions.newParam = function (doc, option, repair) {
// console.log("repair new param");
var param = {
"doc": doc,
"option": option,
"repair": repair,
"responses": {
"count": 0,
"list": [
// 0: response0
// 1: response1
// 2: response2
],
"stats": {
// responseA: [0, 1]
// responseB: [2]
},
"stats_items": [
// 0: [responseA, [0, 1]]
// 1: [responseB, [2]]
]
},
"conflicts": {
// revC: true
// revD: true
},
"deal_result_state": "ok",
"my_rev": undefined
};
param.responses.list.length = priv.storage_list.length;
return param;
};
functions.getAllDocuments = function (param) {
// console.log("repair getAllDocument");
var i, doc = priv.clone(param.doc), option = priv.clone(param.option);
option.conflicts = true;
option.revs = true;
option.revs_info = true;
for (i = 0; i < priv.storage_list.length; i += 1) {
// if the document is not loaded
priv.send("get", i, doc, option, functions.dealResults(param));
}
functions.finished_count += 1;
};
functions.dealResults = function (param) {
// console.log("repair dealResults");
return function (method, index, err, response) {
if (param.deal_result_state !== "ok") {
// deal result is in a wrong state, exit
// console.log("repair dealResults wrong state");
return;
}
if (err) {
if (err.status !== 404) {
// get document failed, exit
param.deal_result_state = "error";
// console.log("repair dealResults error");
callback({
"status": 40,
"statusText": "Check Failed",
"error": "check_failed",
"message": "An error occured on the sub storage",
"reason": err.reason
});
return;
}
}
// success to get the document
// add the response in memory
param.responses.count += 1;
param.responses.list[index] = response;
// add the conflicting revision for other synchronizations
functions.addConflicts(param, (response || {})._conflicts);
if (param.responses.count !== param.responses.list.length) {
// this is not the last response, wait for the next response
// console.log("repair dealResults not last");
return;
}
// console.log("repair dealResults last");
// this is now the last response
functions.makeResponsesStats(param.responses);
if (param.responses.stats_items.length === 1) {
// the responses are equals!
// console.log("repair dealResults OK");
callback(undefined, {
"ok": true,
"id": param.doc._id,
"rev": (typeof param.responses.list[0] === "object" ?
param.responses.list[0]._rev : undefined)
});
return;
}
// the responses are different
if (param.repair === false) {
// do not repair
callback({
"status": 41,
"statusText": "Check Not Ok",
"error": "check_not_ok",
"message": "Some documents are different in the sub storages",
"reason": "Storage contents differ"
});
return;
}
// repair
functions.synchronizeAllSubStorage(param);
if (param.option.synchronize_conflicts !== false) {
functions.synchronizeConflicts(param);
}
};
};
functions.addConflicts = function (param, list) {
// console.log("repair addConflicts");
var i;
list = list || [];
for (i = 0; i < list.length; i += 1) {
param.conflicts[list[i]] = true;
}
};
functions.makeResponsesStats = function (responses) {
// console.log("repair makeResponseStats");
var i, str_response;
for (i = 0; i < responses.count; i += 1) {
str_response = JSON.stringify(responses.list[i]);
if (responses.stats[str_response] === undefined) {
responses.stats[str_response] = [];
responses.stats_items.push([
str_response,
responses.stats[str_response]
]);
}
responses.stats[str_response].push(i);
}
};
functions.synchronizeAllSubStorage = function (param) {
// console.log("repair synchronizeAllSubStorage");
var i, j, len = param.responses.stats_items.length;
for (i = 0; i < len; i += 1) {
// browsing responses
for (j = 0; j < len; j += 1) {
// browsing storage list
if (i !== j) {
functions.synchronizeResponseToSubStorage(
param,
param.responses.stats_items[i][0],
param.responses.stats_items[j][1]
);
}
}
}
functions.finished_count -= 1;
};
functions.synchronizeResponseToSubStorage = function (
param,
response,
storage_list
) {
// console.log("repair synchronizeResponseToSubStorage");
var i, new_doc;
if (response === undefined) {
// no response to sync
return;
}
for (i = 0; i < storage_list.length; i += 1) {
new_doc = JSON.parse(response);
new_doc._revs = new_doc._revisions;
delete new_doc._rev;
delete new_doc._revisions;
delete new_doc._conflicts;
functions.finished_count += 1;
priv.send(
"put",
storage_list[i],
new_doc,
param.option,
functions.finished
);
}
};
functions.synchronizeConflicts = function (param) {
// console.log("repair synchronizeConflicts");
var rev, new_doc, new_option;
new_option = priv.clone(param.option);
new_option.synchronize_conflict = false;
for (rev in param.conflicts) {
if (param.conflicts.hasOwnProperty(rev)) {
new_doc = priv.clone(param.doc);
new_doc._rev = rev;
// no need to synchronize all the conflicts again, do it once
functions.getAllDocuments(functions.newParam(
new_doc,
new_option,
param.repair
));
}
}
};
functions.finished_count = 0;
functions.finished = function () {
// console.log("repair finished " + functions.finished_count);
functions.finished_count -= 1;
if (functions.finished_count === 0) {
// console.log("repair ended");
callback(undefined, {"ok": true, "id": doc._id});
}
};
functions.begin();
};
////////////////////////////////////////////////////////////////////////////////
/**
* Post the document metadata to all sub storages
* @method post
......@@ -397,6 +644,9 @@ jIO.addStorageType('replicaterevision', function (spec, my) {
}
}
that.success(response);
setTimeout(function () {
priv.repair({"_id": doc._id}, command.cloneOption(), true);
});
};
functions.error_count = 0;
functions.error = function (err) {
......
This diff is collapsed.
This diff is collapsed.
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