Commit f6786d3e authored by Romain Courteaud's avatar Romain Courteaud

DocumentStorage: allow to automatically garbage collect all broken attachments.

Activate it by adding the 'repair_attachment' parameter in the storage description.
Then, call the repair method.
parent a6d76543
......@@ -12,6 +12,7 @@
function DocumentStorage(spec) {
this._sub_storage = jIO.createJIO(spec.sub_storage);
this._document_id = spec.document_id;
this._repair_attachment = spec.repair_attachment || false;
}
var DOCUMENT_EXTENSION = ".json",
......@@ -98,7 +99,76 @@
};
DocumentStorage.prototype.repair = function () {
return this._sub_storage.repair.apply(this._sub_storage, arguments);
var context = this;
return this._sub_storage.repair.apply(this._sub_storage, arguments)
.push(function (result) {
if (context._repair_attachment) {
return context._sub_storage.allAttachments(context._document_id)
.push(function (result_dict) {
var promise_list = [],
id_dict = {},
attachment_dict = {},
id,
attachment,
exec,
key;
for (key in result_dict) {
if (result_dict.hasOwnProperty(key)) {
id = undefined;
attachment = undefined;
if (DOCUMENT_REGEXP.test(key)) {
try {
id = atob(DOCUMENT_REGEXP.exec(key)[1]);
} catch (error) {
// Check if unable to decode base64 data
if (!error instanceof ReferenceError) {
throw error;
}
}
if (id !== undefined) {
id_dict[id] = null;
}
} else if (ATTACHMENT_REGEXP.test(key)) {
exec = ATTACHMENT_REGEXP.exec(key);
try {
id = atob(exec[1]);
attachment = atob(exec[2]);
} catch (error) {
// Check if unable to decode base64 data
if (!error instanceof ReferenceError) {
throw error;
}
}
if (attachment !== undefined) {
if (!id_dict.hasOwnProperty(id)) {
if (!attachment_dict.hasOwnProperty(id)) {
attachment_dict[id] = {};
}
attachment_dict[id][attachment] = null;
}
}
}
}
}
for (id in attachment_dict) {
if (attachment_dict.hasOwnProperty(id)) {
if (!id_dict.hasOwnProperty(id)) {
for (attachment in attachment_dict[id]) {
if (attachment_dict[id].hasOwnProperty(attachment)) {
promise_list.push(context.removeAttachment(
id,
attachment
));
}
}
}
}
}
return RSVP.all(promise_list);
});
}
return result;
});
};
DocumentStorage.prototype.hasCapacity = function (capacity) {
......
......@@ -34,9 +34,23 @@
ok(jio.__storage._sub_storage instanceof jio.constructor);
equal(jio.__storage._sub_storage.__type, "documentstorage200");
equal(jio.__storage._repair_attachment, false);
});
test("accept parameters", function () {
var jio = jIO.createJIO({
type: "document",
document_id: "foo",
repair_attachment: true,
sub_storage: {
type: "documentstorage200"
}
});
equal(jio.__storage._repair_attachment, true);
});
/////////////////////////////////////////////////////////////////
// documentStorage.get
/////////////////////////////////////////////////////////////////
......@@ -532,11 +546,30 @@
}),
expected_options = {foo: "bar"};
Storage200.prototype.repair = function (options) {
function StorageSimpleRepair() {
return this;
}
StorageSimpleRepair.prototype.allAttachments = function () {
ok(false, "allAttachments 200 called");
};
StorageSimpleRepair.prototype.repair = function (options) {
deepEqual(options, expected_options, "repair 200 called");
return "OK";
};
jIO.addStorage('documentstoragesimplerepair',
StorageSimpleRepair);
jio = jIO.createJIO({
type: "document",
document_id: "foo",
sub_storage: {
type: "documentstoragesimplerepair"
}
});
jio.repair(expected_options)
.then(function (result) {
equal(result, "OK");
......@@ -549,4 +582,82 @@
});
});
test("repair clean all garbage left from a previous bug", function () {
stop();
expect(7);
var i = 0,
jio;
function StorageRepairWithGarbage() {
return this;
}
StorageRepairWithGarbage.prototype.allAttachments = function (id) {
equal(id, "foo", "allAttachments 200 called");
var result = {};
// Not matching attachment
result.notmatchingfoo = {};
// Standalone document
result['jio_document/' + btoa("standalonefoo") + '.json'] = {};
// Document with attachments
result['jio_document/' + btoa("withdocfoo") + '.json'] = {};
result['jio_attachment/' + btoa("withdocfoo") + "/" +
btoa("bar1")] = {};
result['jio_attachment/' + btoa("withdocfoo") + "/" +
btoa("bar2")] = {};
// Garbage attachments
result['jio_attachment/' + btoa("garbagefoo1") + "/" +
btoa("foo3")] = {};
result['jio_attachment/' + btoa("garbagefoo2") + "/" +
btoa("foo4")] = {};
return result;
};
StorageRepairWithGarbage.prototype.removeAttachment =
function (id, name) {
if (i === 0) {
equal(id, "foo", "removeAttachment called");
equal(name, 'jio_attachment/' + btoa("garbagefoo1") + "/" +
btoa("foo3"));
} else if (i === 1) {
equal(id, "foo", "removeAttachment called");
equal(name, 'jio_attachment/' + btoa("garbagefoo2") + "/" +
btoa("foo4"));
} else {
ok(false, "Unexpected removeAttachment call: " + id + " " + name);
}
i += 1;
return name;
};
StorageRepairWithGarbage.prototype.repair = function () {
ok(true, "repair called");
return "OK";
};
jIO.addStorage('documentstoragerepairwithgarbage',
StorageRepairWithGarbage);
jio = jIO.createJIO({
type: "document",
document_id: "foo",
sub_storage: {
type: "documentstoragerepairwithgarbage"
},
repair_attachment: true
});
jio.repair()
.then(function (result) {
deepEqual(result, [
"jio_attachment/Z2FyYmFnZWZvbzE=/Zm9vMw==",
"jio_attachment/Z2FyYmFnZWZvbzI=/Zm9vNA=="
]);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
}(jIO, QUnit, Blob, btoa));
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