Commit d8602cf1 authored by Tristan Cavelier's avatar Tristan Cavelier

indexstorage.js: check & repair + tests

parent 86c22afe
...@@ -98,6 +98,12 @@ ...@@ -98,6 +98,12 @@
"statusText": "Conflicts", "statusText": "Conflicts",
"error": "conflicts", "error": "conflicts",
"reason": "already exist" "reason": "already exist"
},
"Different Index": {
"status": 40,
"statusText": "Check failed",
"error": "check_failed",
"reason": "incomplete database"
} }
}; };
...@@ -279,7 +285,7 @@ ...@@ -279,7 +285,7 @@
}; };
/** /**
* Checks if the index document is correct * Checks if the index database document is correct
* *
* @method check * @method check
*/ */
...@@ -305,6 +311,43 @@ ...@@ -305,6 +311,43 @@
} }
}; };
that.equals = function (json_index) {
function equalsDirection(a, b) {
var k;
for (k in a._location) {
if (a._location.hasOwnProperty(k)) {
if (b._location[k] === undefined ||
JSON.stringify(b._database[b._location[k]]) !==
JSON.stringify(a._database[a._location[k]])) {
return false;
}
}
}
return true;
}
if (!equalsDirection(that, json_index)) {
return false;
}
if (!equalsDirection(json_index, that)) {
return false;
}
return true;
};
that.checkDocument = function (doc) {
var i, key, db_doc;
if (typeof that._location[doc._id] !== "number" ||
(db_doc = that._database(that._location[doc._id])._id) !== doc._id) {
throw new TypeError("Different Index");
}
for (i = 0; i < that._indexing.length; i += 1) {
key = that._indexing[i];
if (doc[key] !== db_doc[key]) {
throw new TypeError("Different Index");
}
}
};
/** /**
* Recreates database indices and remove free space * Recreates database indices and remove free space
* *
...@@ -679,35 +722,11 @@ ...@@ -679,35 +722,11 @@
}; };
that.check = function (command) { that.check = function (command) {
todo that.repair(command, true);
var database_index = -1, i;
for (i = 0; i < priv.indices.length; i += 1) {
if (priv.indices[i].id === command.getDocId()) {
database_index = i;
break;
}
}
that.addJob(
"check",
priv.sub_storage,
command.cloneDoc(),
command.cloneOption(),
function (response) {
if (database_index !== -1) {
// check index database
} else {
// regular document
}
},
function (err) {
err.message = "Could not repair sub storage";
that.error(err);
}
);
}; };
priv.repairIndexDatabase = function (command, index) { priv.repairIndexDatabase = function (command, index, just_check) {
var i; var i, option = command.cloneOption();
that.addJob( that.addJob(
'allDocs', 'allDocs',
priv.sub_storage, priv.sub_storage,
...@@ -722,9 +741,22 @@ ...@@ -722,9 +741,22 @@
db.put(response.rows[i].doc); db.put(response.rows[i].doc);
} }
db_list[index] = db; db_list[index] = db;
priv.storeIndexDatabaseList(db_list, {}, function () { if (just_check) {
that.success({"ok": true, "_id": command.getDocId()}); priv.getIndexDatabase(option, index, function (current_db) {
}); if (db.equals(current_db)) {
return that.success({"ok": true, "_id": command.getDocId()});
}
return that.error(generateErrorObject(
"Different Index",
"Check failed",
"corrupt index database"
));
});
} else {
priv.storeIndexDatabaseList(db_list, {}, function () {
that.success({"ok": true, "_id": command.getDocId()});
});
}
}, },
function (err) { function (err) {
err.message = "Unable to repair the index database"; err.message = "Unable to repair the index database";
...@@ -733,7 +765,7 @@ ...@@ -733,7 +765,7 @@
); );
}; };
priv.repairDocument = function (command) { priv.repairDocument = function (command, just_check) {
var i, option = command.cloneOption(); var i, option = command.cloneOption();
that.addJob( that.addJob(
"get", "get",
...@@ -743,12 +775,27 @@ ...@@ -743,12 +775,27 @@
function (response) { function (response) {
response._id = command.getDocId(); response._id = command.getDocId();
priv.getIndexDatabaseList(option, function (database_list) { priv.getIndexDatabaseList(option, function (database_list) {
for (i = 0; i < database_list.length; i += 1) { if (just_check) {
database_list[i].put(response); for (i = 0; i < database_list.length; i += 1) {
try {
database_list[i].checkDocument(response);
} catch (e) {
return that.error(generateErrorObject(
e.message,
"Check failed",
"corrupt index database"
));
}
}
that.success({"_id": command.getDocId(), "ok": true});
} else {
for (i = 0; i < database_list.length; i += 1) {
database_list[i].put(response);
}
priv.storeIndexDatabaseList(database_list, option, function () {
that.success({"ok": true, "id": command.getDocId()});
});
} }
priv.storeIndexDatabaseList(database_list, option, function () {
that.success({"ok": true, "id": command.getDocId()});
});
}); });
}, },
function (err) { function (err) {
...@@ -758,7 +805,7 @@ ...@@ -758,7 +805,7 @@
); );
}; };
that.repair = function (command) { that.repair = function (command, just_check) {
var database_index = -1, i; var database_index = -1, i;
for (i = 0; i < priv.indices.length; i += 1) { for (i = 0; i < priv.indices.length; i += 1) {
if (priv.indices[i].id === command.getDocId()) { if (priv.indices[i].id === command.getDocId()) {
...@@ -773,9 +820,9 @@ ...@@ -773,9 +820,9 @@
command.cloneOption(), command.cloneOption(),
function (response) { function (response) {
if (database_index !== -1) { if (database_index !== -1) {
priv.repairIndexDatabase(command, database_index); priv.repairIndexDatabase(command, database_index, just_check);
} else { } else {
priv.repairDocument(command); priv.repairDocument(command, just_check);
} }
}, },
function (err) { function (err) {
......
...@@ -4520,7 +4520,7 @@ test ("Put", function(){ ...@@ -4520,7 +4520,7 @@ test ("Put", function(){
o.jio.stop(); o.jio.stop();
}); });
test("Repair", function () { test("Check & Repair", function () {
var o = generateTools(this), i; var o = generateTools(this), i;
o.jio = JIO.newJio({ o.jio = JIO.newJio({
...@@ -4564,6 +4564,14 @@ test("Repair", function () { ...@@ -4564,6 +4564,14 @@ test("Repair", function () {
} }
o.clock.tick(5000); o.clock.tick(5000);
o.spy(o, "status", 40, "Check database");
o.jio.check({"_id": "A"}, o.f);
o.tick(o);
o.spy(o, "status", 40, "Check database");
o.jio.check({"_id": "B"}, o.f);
o.tick(o);
o.spy(o, "value", {"_id": "A", "ok": true}, "Repair database"); o.spy(o, "value", {"_id": "A", "ok": true}, "Repair database");
o.jio.repair({"_id": "A"}, o.f); o.jio.repair({"_id": "A"}, o.f);
o.tick(o); o.tick(o);
...@@ -4572,8 +4580,16 @@ test("Repair", function () { ...@@ -4572,8 +4580,16 @@ test("Repair", function () {
o.jio.repair({"_id": "B"}, o.f); o.jio.repair({"_id": "B"}, o.f);
o.tick(o); o.tick(o);
o.spy(o, "value", {"_id": "A", "ok": true}, "Check database again");
o.jio.check({"_id": "A"}, o.f);
o.tick(o);
o.spy(o, "value", {"_id": "B", "ok": true}, "Check database again");
o.jio.check({"_id": "B"}, o.f);
o.tick(o);
// check index file // check index file
o.spy(o, "value", o.fakeIndexA, "Check index file"); o.spy(o, "value", o.fakeIndexA, "Manually check index file");
o.jio.get({"_id": "A"}, function (err, response) { o.jio.get({"_id": "A"}, function (err, response) {
if (response) { if (response) {
delete response.location; delete response.location;
...@@ -4585,7 +4601,7 @@ test("Repair", function () { ...@@ -4585,7 +4601,7 @@ test("Repair", function () {
}); });
o.tick(o); o.tick(o);
o.spy(o, "value", o.fakeIndexB, "Check index file"); o.spy(o, "value", o.fakeIndexB, "Manually check index file");
o.jio.get({"_id": "B"}, function (err, response) { o.jio.get({"_id": "B"}, function (err, response) {
if (response) { if (response) {
delete response.location; delete response.location;
...@@ -4606,12 +4622,20 @@ test("Repair", function () { ...@@ -4606,12 +4622,20 @@ test("Repair", function () {
o.fakeIndexA.database.unshift({"_id": "blah", "director": "d"}); o.fakeIndexA.database.unshift({"_id": "blah", "director": "d"});
o.fakeIndexB.database.unshift({"_id": "blah", "year": "y"}); o.fakeIndexB.database.unshift({"_id": "blah", "year": "y"});
o.spy(o, "status", 40, "Check Document");
o.jio.check({"_id": "blah"}, o.f)
o.tick(o);
o.spy(o, "value", {"id": "blah", "ok": true}, "Repair Document"); o.spy(o, "value", {"id": "blah", "ok": true}, "Repair Document");
o.jio.repair({"_id": "blah"}, o.f) o.jio.repair({"_id": "blah"}, o.f)
o.tick(o); o.tick(o);
o.spy(o, "value", {"id": "blah", "ok": true}, "Check Document again");
o.jio.repair({"_id": "blah"}, o.f)
o.tick(o);
// check index file // check index file
o.spy(o, "value", o.fakeIndexA, "Check index file"); o.spy(o, "value", o.fakeIndexA, "Manually check index file");
o.jio.get({"_id": "A"}, function (err, response) { o.jio.get({"_id": "A"}, function (err, response) {
if (response) { if (response) {
delete response.location; delete response.location;
...@@ -4623,7 +4647,7 @@ test("Repair", function () { ...@@ -4623,7 +4647,7 @@ test("Repair", function () {
}); });
o.tick(o); o.tick(o);
o.spy(o, "value", o.fakeIndexB, "Check index file"); o.spy(o, "value", o.fakeIndexB, "Manually check index file");
o.jio.get({"_id": "B"}, function (err, response) { o.jio.get({"_id": "B"}, function (err, response) {
if (response) { if (response) {
delete response.location; delete response.location;
......
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