From 049ea125f8697c5ec49320c10c4ffe8bea8b7221 Mon Sep 17 00:00:00 2001
From: Tristan Cavelier <tristan.cavelier@tiolive.com>
Date: Tue, 19 Feb 2013 17:37:34 +0100
Subject: [PATCH] synchro prototype #2

---
 src/jio.storage/synchro2.js | 240 ++++++++++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)
 create mode 100644 src/jio.storage/synchro2.js

diff --git a/src/jio.storage/synchro2.js b/src/jio.storage/synchro2.js
new file mode 100644
index 0000000..6a9bda6
--- /dev/null
+++ b/src/jio.storage/synchro2.js
@@ -0,0 +1,240 @@
+var that = {};
+var priv = {};
+var RESPONSES = {"put":[],"get":[]};
+var todo = function (string) {
+  global.todo = global.todo || {};
+  if (!global.todo[string]) {
+    global.todo[string] = true;
+    console.log('TODO: ' + string);
+  }
+};
+priv.clone = function (object) {
+  var tmp = JSON.stringify(object);
+  if (tmp === undefined) {
+    return undefined;
+  }
+  return JSON.parse(tmp);
+};
+that.addJob = function (method, storage_spec, doc, option, success, error) {
+  console.log(method + " "+ JSON.stringify(storage_spec) +
+              " " + JSON.stringify(doc) + " " + JSON.stringify(option));
+  var r = RESPONSES[method].shift();
+  setTimeout(function () {
+    if (r.ok === true) {
+      success(r);
+    } else {
+      error(r);
+    }
+  }, Math.floor(Math.random() * 500)); // {0..500}
+};
+priv.send = function (method, index, doc, option, callback) {
+  console.log("send " + method + " " +
+              JSON.stringify(priv.storage_list[index]) + " " +
+              JSON.stringify(doc) + " " + JSON.stringify(option));
+  var wrapped_callback_success, wrapped_callback_error;
+  callback = callback || priv.emptyFunction;
+  wrapped_callback_success = function (response) {
+    callback(method, index, undefined, response);
+  };
+  wrapped_callback_error = function (err) {
+    callback(method, index, err, undefined);
+  };
+  that.addJob(
+    method,
+    priv.storage_list[index],
+    doc,
+    option,
+    wrapped_callback_success,
+    wrapped_callback_error
+  );
+};
+priv.sendToAll = function (method, doc, option, callback) {
+  console.log("sendToAll " + method + " " + JSON.stringify(doc) + " " +
+              JSON.stringify(option));
+  var i;
+  for (i = 0; i < priv.storage_list.length; i += 1) {
+    priv.send(method, i, doc, option, callback);
+  }
+};
+priv.emptyFunction = function () {};
+////////////////////////////////////////////////////////////////////////////////
+// NEW
+priv.replicateRevToDistantRev = function (revision, storage_index) {
+  throw {"name": "NotImplementedError", "message": "replicateRevToDistantRev"};
+};
+// Check pass only if:
+// - all the substorages answer the requests
+// - they respond exactly the same thing
+// - consistency is correct
+// Consistency is correct if:
+// - it has a correct revision
+// If answers differ, the good answer is the first one which is more returned
+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) {
+  callback = callback || priv.emptyFunction;
+  option = option || {};
+  var begin = function () {
+    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]]
+        ]
+      }
+    };
+    getAllDocuments(param);
+  },
+  getAllDocuments = function (param) {
+    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) {
+      doc._rev = priv.replicateRevToDistantRev(doc._rev, i);
+      priv.send("get", i, doc, option, dealResults(param));
+    }
+  },
+  dealResults = function (param) {
+    var deal_result_state = "ok";
+    return function (method, index, err, response) {
+      if (deal_result_state !== "ok") {
+        // deal result is in a wrong state, exit
+        return;
+      }
+      if (err) {
+        if (err.status !== 404) {
+          // get document failed, exit
+          deal_result_state = "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;
+      param.responses.revs[response._rev] = response;
+      if (param.responses.count !== param.responses.list.length) {
+        // this is not the last response, wait for the next response
+        return;
+      }
+      // this is now the last response
+
+      makeResponsesStats(param.responses);
+      if (param.responses.stats_items.length === 1) {
+        // the responses are equals!
+        callback(undefined, {
+          "ok": true,
+          "id": param.doc._id,
+          "rev": priv.distantRevToReplicateRev(
+            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
+      synchronizeAllSubStorage(param);
+    };
+  },
+  makeResponsesStats = function (responses) {
+    var i;
+    for (i = 0; i < responses.count; i += 1) {
+      var 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_responses]
+        );
+      }
+      responses.stats[str_response].push(i);
+    }
+  },
+  synchronizeAllSubStorage = function (param) {
+    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) {
+          synchronizeAllSubStorage(
+            param,
+            param.responses.stats_items[i][0],
+            param.responses.stats_items[j][1]
+          );
+        }
+      }
+    }
+  },
+  synchronizeResponseToSubStorage = function (param, response, storage_list) {
+    throw {"name": "NotImplementedError", "message": "synchronizeResponseToSubStorage"};
+  };
+  begin();
+};
+////////////////////////////////////////////////////////////////////////////////
+// TEST
+
+
+RESPONSES.get.push({"_id": "doc1", "_rev": "2-222"});
+priv.storage_list = ["revision1"];
+priv.repair({"_id": "doc1", "_rev": "2-2"}, {}, function (err, response) {
+  console.log("END");
+  console.log(err || response);
+});
+
+// priv.storage_list = ["revision1", "revision2", "revision3"];
+// priv.repair({"_id": "doc1", "_rev": "2-222"}, function (err, response) {
+//   console.log("END");
+//   console.log(err || response);
+// });
-- 
2.30.9