Closes #711, Remove support for nested transactions
This commit is contained in:
parent
e584dbf5dd
commit
14d435b8d8
23 changed files with 862 additions and 856 deletions
|
@ -9,14 +9,15 @@ describe("Zotero.DB", function() {
|
|||
});
|
||||
beforeEach(function* () {
|
||||
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
});
|
||||
after(function* () {
|
||||
yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tmpTable);
|
||||
});
|
||||
|
||||
describe("#executeTransaction()", function () {
|
||||
it("should nest concurrent transactions", Zotero.Promise.coroutine(function* () {
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
it("should serialize concurrent transactions", Zotero.Promise.coroutine(function* () {
|
||||
this.timeout(1000);
|
||||
|
||||
var resolve1, resolve2, reject1, reject2;
|
||||
var promise1 = new Promise(function (resolve, reject) {
|
||||
|
@ -29,18 +30,21 @@ describe("Zotero.DB", function() {
|
|||
});
|
||||
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.Promise.delay(100);
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
yield Zotero.Promise.delay(250);
|
||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(num, 0);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
assert.ok(Zotero.DB.inTransaction());
|
||||
})
|
||||
.then(resolve1)
|
||||
.catch(reject1);
|
||||
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 1);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(num, 1);
|
||||
yield Zotero.Promise.delay(500);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
assert.ok(Zotero.DB.inTransaction());
|
||||
})
|
||||
.then(resolve2)
|
||||
.catch(reject2);
|
||||
|
@ -48,10 +52,8 @@ describe("Zotero.DB", function() {
|
|||
yield Zotero.Promise.all([promise1, promise2]);
|
||||
}));
|
||||
|
||||
it("shouldn't nest transactions if an exclusive transaction is open", Zotero.Promise.coroutine(function* () {
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
|
||||
var resolve1, resolve2, reject1, reject2;
|
||||
it("should serialize queued transactions", function* () {
|
||||
var resolve1, resolve2, reject1, reject2, resolve3, reject3;
|
||||
var promise1 = new Promise(function (resolve, reject) {
|
||||
resolve1 = resolve;
|
||||
reject1 = reject;
|
||||
|
@ -60,66 +62,48 @@ describe("Zotero.DB", function() {
|
|||
resolve2 = resolve;
|
||||
reject2 = reject;
|
||||
});
|
||||
var promise3 = new Promise(function (resolve, reject) {
|
||||
resolve3 = resolve;
|
||||
reject3 = reject;
|
||||
});
|
||||
|
||||
// Start a transaction and have it delay
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.Promise.delay(100);
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
}, { exclusive: true })
|
||||
.then(resolve1)
|
||||
.catch(reject1);
|
||||
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(num, 1);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
})
|
||||
.then(resolve2)
|
||||
.catch(reject2);
|
||||
|
||||
yield Zotero.Promise.all([promise1, promise2]);
|
||||
}));
|
||||
|
||||
it("shouldn't nest an exclusive transaction if another transaction is open", Zotero.Promise.coroutine(function* () {
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
|
||||
var resolve1, resolve2, reject1, reject2;
|
||||
var promise1 = new Promise(function (resolve, reject) {
|
||||
resolve1 = resolve;
|
||||
reject1 = reject;
|
||||
});
|
||||
var promise2 = new Promise(function (resolve, reject) {
|
||||
resolve2 = resolve;
|
||||
reject2 = reject;
|
||||
});
|
||||
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.Promise.delay(100);
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
||||
assert.equal(num, 0);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
assert.ok(Zotero.DB.inTransaction());
|
||||
})
|
||||
.then(resolve1)
|
||||
.catch(reject1);
|
||||
|
||||
// Start two more transactions, which should wait on the first
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
assert.equal(Zotero.DB._asyncTransactionNestingLevel, 0);
|
||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(num, 1);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
Zotero.DB.transactionDate; // Make sure we're still in a transaction
|
||||
}, { exclusive: true })
|
||||
assert.ok(Zotero.DB.inTransaction());
|
||||
})
|
||||
.then(resolve2)
|
||||
.catch(reject2);
|
||||
|
||||
yield Zotero.Promise.all([promise1, promise2]);
|
||||
}));
|
||||
Zotero.DB.executeTransaction(function* () {
|
||||
var num = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(num, 2);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (3)");
|
||||
// But make sure the second queued transaction doesn't start at the same time,
|
||||
// such that the first queued transaction gets closed while the second is still
|
||||
// running
|
||||
assert.ok(Zotero.DB.inTransaction());
|
||||
})
|
||||
.then(resolve3)
|
||||
.catch(reject3);
|
||||
|
||||
yield Zotero.Promise.all([promise1, promise2, promise3]);
|
||||
})
|
||||
|
||||
it("should roll back on error", function* () {
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
try {
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
|
@ -141,7 +125,6 @@ describe("Zotero.DB", function() {
|
|||
|
||||
it("should run onRollback callbacks", function* () {
|
||||
var callbackRan = false;
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
try {
|
||||
yield Zotero.DB.executeTransaction(
|
||||
function* () {
|
||||
|
@ -163,25 +146,31 @@ describe("Zotero.DB", function() {
|
|||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
||||
});
|
||||
|
||||
it("should run onRollback callbacks for nested transactions", function* () {
|
||||
it("should time out on nested transactions", function* () {
|
||||
var e;
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
e = yield getPromiseError(
|
||||
Zotero.DB.executeTransaction(function* () {}).timeout(250)
|
||||
);
|
||||
});
|
||||
assert.ok(e);
|
||||
assert.equal(e.name, "TimeoutError");
|
||||
});
|
||||
|
||||
it("should run onRollback callbacks for timed-out nested transactions", function* () {
|
||||
var callback1Ran = false;
|
||||
var callback2Ran = false;
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
try {
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
yield Zotero.DB.executeTransaction(
|
||||
function* () {
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
|
||||
throw 'Aborting transaction -- ignore';
|
||||
},
|
||||
function* () {},
|
||||
{
|
||||
waitTimeout: 100,
|
||||
onRollback: function () {
|
||||
callback1Ran = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
},
|
||||
{
|
||||
onRollback: function () {
|
||||
|
@ -190,32 +179,10 @@ describe("Zotero.DB", function() {
|
|||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e;
|
||||
if (e.name != "TimeoutError") throw e;
|
||||
}
|
||||
assert.ok(callback1Ran);
|
||||
assert.ok(callback2Ran);
|
||||
|
||||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
||||
});
|
||||
|
||||
it("should not commit nested transactions", function* () {
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE " + tmpTable + " (foo INT)");
|
||||
try {
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (1)");
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
yield Zotero.DB.queryAsync("INSERT INTO " + tmpTable + " VALUES (2)");
|
||||
throw 'Aborting transaction -- ignore';
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof e != 'string' || !e.startsWith('Aborting transaction')) throw e;
|
||||
}
|
||||
var count = yield Zotero.DB.valueQueryAsync("SELECT COUNT(*) FROM " + tmpTable);
|
||||
assert.equal(count, 0);
|
||||
|
||||
yield Zotero.DB.queryAsync("DROP TABLE " + tmpTable);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue