diff options
author | Michael Cahill <michael.cahill@wiredtiger.com> | 2012-06-20 12:40:17 +1000 |
---|---|---|
committer | Michael Cahill <michael.cahill@wiredtiger.com> | 2012-06-20 15:32:48 +1000 |
commit | 3c4adbdbb247106841132bf903eccf8fef43f563 (patch) | |
tree | 323bbddecd0e27e651528be2ac15ccdfa460c157 | |
parent | 41dce09ac64bc8f0d4849699c2e7bb4a4213cedc (diff) | |
download | mongo-3c4adbdbb247106841132bf903eccf8fef43f563.tar.gz |
Fix two bugs with snapshot isolation:
1. reset the isolation level when the transaction completes;
2. when checking visibility, check item's ID against the maximum snapshot ID
(not the transaction's ID).
-rw-r--r-- | src/include/txn.i | 4 | ||||
-rw-r--r-- | src/txn/txn.c | 4 | ||||
-rw-r--r-- | test/suite/test_txn02.py | 29 |
3 files changed, 30 insertions, 7 deletions
diff --git a/src/include/txn.i b/src/include/txn.i index da9f5af9716..c5b10186cff 100644 --- a/src/include/txn.i +++ b/src/include/txn.i @@ -73,7 +73,7 @@ __wt_txn_visible(WT_SESSION_IMPL *session, wt_txnid_t id) */ if (TXNID_LT(id, txn->snap_min)) return (1); - if (TXNID_LT(txn->id, txn->snap_max)) + if (TXNID_LT(txn->snap_max, id)) return (0); /* @@ -125,7 +125,7 @@ __wt_txn_update_check(WT_SESSION_IMPL *session, WT_UPDATE *upd) WT_TXN *txn; txn = &session->txn; - if (F_ISSET(txn, TXN_RUNNING) && txn->isolation == TXN_ISO_SNAPSHOT) + if (txn->isolation == TXN_ISO_SNAPSHOT) while (upd != NULL && !__wt_txn_visible(session, upd->txnid)) { if (upd->txnid != WT_TXN_ABORTED) return (WT_DEADLOCK); diff --git a/src/txn/txn.c b/src/txn/txn.c index 3e06b5a3e25..8c9b9be6db4 100644 --- a/src/txn/txn.c +++ b/src/txn/txn.c @@ -144,10 +144,14 @@ __txn_release(WT_SESSION_IMPL *session) if (!F_ISSET(txn, TXN_RUNNING)) WT_RET_MSG(session, EINVAL, "No transaction is active"); + /* Clear the transaction's ID from the global table. */ txn_global = &S2C(session)->txn_global; WT_ASSERT(session, txn_global->ids[session->id] != WT_TXN_NONE && txn->id != WT_TXN_NONE); WT_PUBLISH(txn_global->ids[session->id], txn->id = WT_TXN_NONE); + + /* Reset the transaction state to not running. */ + txn->isolation = TXN_ISO_READ_UNCOMMITTED; F_CLR(txn, TXN_ERROR | TXN_RUNNING); return (0); diff --git a/test/suite/test_txn02.py b/test/suite/test_txn02.py index b406ad16b3b..08ced2322ed 100644 --- a/test/suite/test_txn02.py +++ b/test/suite/test_txn02.py @@ -69,8 +69,9 @@ class test_txn02(wttest.WiredTigerTestCase): txn2s = [('t2c', dict(txn2='commit')), ('t2r', dict(txn2='rollback'))] txn3s = [('t3c', dict(txn3='commit')), ('t3r', dict(txn3='rollback'))] txn4s = [('t4c', dict(txn4='commit')), ('t4r', dict(txn4='rollback'))] + scenarios = number_scenarios(multiply_scenarios('.', types, - op1s, txn1s, op2s, txn2s, op3s, txn3s, op4s, txn4s)) + op1s, txn1s, op2s, txn2s, op3s, txn3s, op4s, txn4s)) # [:1] # Overrides WiredTigerTestCase def setUpConnectionOpen(self, dir): @@ -78,12 +79,17 @@ class test_txn02(wttest.WiredTigerTestCase): ('error_prefix="%s: ",' % self.shortid()) + 'transactional,') self.pr(`conn`) + self.session2 = conn.open_session() return conn - def check(self, expected): - c = self.session.open_cursor(self.uri, None) + def check(self, session, txn_config, expected): + if txn_config: + session.begin_transaction(txn_config) + c = session.open_cursor(self.uri, None) actual = dict((k, v) for k, v in c if v != 0) c.close() + if txn_config: + session.commit_transaction() self.assertEqual(actual, expected) def test_ops(self): @@ -100,34 +106,47 @@ class test_txn02(wttest.WiredTigerTestCase): ops = (self.op1, self.op2, self.op3, self.op4) txns = (self.txn1, self.txn2, self.txn3, self.txn4) + # print ', '.join('%s(%d)[%s]' % (ok[0], ok[1], txn) + # for ok, txn in zip(ops, txns)) for i, ot in enumerate(zip(ops, txns)): self.session.begin_transaction() c = self.session.open_cursor(self.uri, None, 'overwrite') ok, txn = ot op, k = ok + # print '%s(%d)[%s]' % (ok[0], ok[1], txn) # We use the overwrite config so insert can update as needed. if op == 'insert' or op == 'update': c.set_key(k) c.set_value(i + 2) c.insert() + # A snapshot transaction should not see the changes + self.check(self.session2, "isolation=snapshot", expected) if txn == 'commit': expected[k] = i + 2 elif op == 'remove': c.set_key(k) c.remove() + # A snapshot transaction should not see the changes + self.check(self.session2, "isolation=snapshot", expected) if txn == 'commit' and k in expected: del expected[k] else: print "UNKNOWN op", op if txn == 'commit': # The transaction should see its own changes - self.check(expected) + self.check(self.session, None, expected) + # A read-uncommitted transaction should see the changes already + self.check(self.session2, "isolation=read-uncommitted", expected) self.session.commit_transaction() elif txn == 'rollback': self.session.rollback_transaction() else: print "UNKNOWN op", op - self.check(expected) + + # The change should be (in)visible in the same session + self.check(self.session, None, expected) + # The change should be (in)visible to snapshot transactions + self.check(self.session2, "isolation=snapshot", expected) self.session.drop(self.uri) if __name__ == '__main__': |