summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@wiredtiger.com>2012-06-20 12:40:17 +1000
committerMichael Cahill <michael.cahill@wiredtiger.com>2012-06-20 15:32:48 +1000
commit3c4adbdbb247106841132bf903eccf8fef43f563 (patch)
tree323bbddecd0e27e651528be2ac15ccdfa460c157
parent41dce09ac64bc8f0d4849699c2e7bb4a4213cedc (diff)
downloadmongo-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.i4
-rw-r--r--src/txn/txn.c4
-rw-r--r--test/suite/test_txn02.py29
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__':