提交 3d206afc authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Fix two-phase commit in MVStore

上级 6bde4590
...@@ -344,6 +344,7 @@ public class TransactionStore { ...@@ -344,6 +344,7 @@ public class TransactionStore {
} }
// TODO could synchronize on blocks (100 at a time or so) // TODO could synchronize on blocks (100 at a time or so)
rwLock.writeLock().lock(); rwLock.writeLock().lock();
int oldStatus = t.status;
try { try {
t.setStatus(Transaction.STATUS_COMMITTING); t.setStatus(Transaction.STATUS_COMMITTING);
for (long logId = 0; logId < maxLogId; logId++) { for (long logId = 0; logId < maxLogId; logId++) {
...@@ -383,7 +384,7 @@ public class TransactionStore { ...@@ -383,7 +384,7 @@ public class TransactionStore {
} finally { } finally {
rwLock.writeLock().unlock(); rwLock.writeLock().unlock();
} }
endTransaction(t); endTransaction(t, oldStatus);
} }
/** /**
...@@ -467,14 +468,15 @@ public class TransactionStore { ...@@ -467,14 +468,15 @@ public class TransactionStore {
* End this transaction * End this transaction
* *
* @param t the transaction * @param t the transaction
* @param previous status of this transaction
*/ */
synchronized void endTransaction(Transaction t) { synchronized void endTransaction(Transaction t, int oldStatus) {
if (t.getStatus() == Transaction.STATUS_PREPARED) { if (oldStatus == Transaction.STATUS_PREPARED) {
preparedTransactions.remove(t.getId()); preparedTransactions.remove(t.getId());
} }
t.setStatus(Transaction.STATUS_CLOSED); t.setStatus(Transaction.STATUS_CLOSED);
openTransactions.clear(t.transactionId); openTransactions.clear(t.transactionId);
if (store.getAutoCommitDelay() == 0) { if (oldStatus == Transaction.STATUS_PREPARED || store.getAutoCommitDelay() == 0) {
store.commit(); store.commit();
return; return;
} }
...@@ -825,7 +827,7 @@ public class TransactionStore { ...@@ -825,7 +827,7 @@ public class TransactionStore {
public void rollback() { public void rollback() {
checkNotClosed(); checkNotClosed();
store.rollbackTo(this, logId, 0); store.rollbackTo(this, logId, 0);
store.endTransaction(this); store.endTransaction(this, status);
} }
/** /**
......
...@@ -48,6 +48,7 @@ public class TestTransaction extends TestBase { ...@@ -48,6 +48,7 @@ public class TestTransaction extends TestBase {
testReferential(); testReferential();
testSavepoint(); testSavepoint();
testIsolation(); testIsolation();
testTwoPhaseCommit();
deleteDb("transaction"); deleteDb("transaction");
} }
...@@ -543,4 +544,42 @@ public class TestTransaction extends TestBase { ...@@ -543,4 +544,42 @@ public class TestTransaction extends TestBase {
stat.execute(sql); stat.execute(sql);
} }
private void testTwoPhaseCommit() throws SQLException {
if (config.memory) {
return;
}
deleteDb("transaction2pc");
Connection conn = getConnection("transaction2pc");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID INT PRIMARY KEY)");
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (1)");
stat.execute("PREPARE COMMIT \"#1\"");
conn.commit();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("transaction2pc");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.setAutoCommit(false);
stat.execute("INSERT INTO TEST VALUES (2)");
stat.execute("PREPARE COMMIT \"#2\"");
conn.rollback();
stat.execute("SHUTDOWN IMMEDIATELY");
conn = getConnection("transaction2pc");
stat = conn.createStatement();
rs = stat.executeQuery("SELECT TRANSACTION, STATE FROM INFORMATION_SCHEMA.IN_DOUBT");
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
conn.close();
deleteDb("transaction2pc");
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论