[Neo-report] r2535 vincent - in /trunk/neo: master/ master/handlers/ tests/master/
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Dec 14 16:57:05 CET 2010
Author: vincent
Date: Tue Dec 14 16:57:04 2010
New Revision: 2535
Log:
Release commit lock if client disconnects after acquiring it.
Modified:
trunk/neo/master/handlers/client.py
trunk/neo/master/transactions.py
trunk/neo/tests/master/testClientHandler.py
trunk/neo/tests/master/testStorageHandler.py
trunk/neo/tests/master/testTransactions.py
Modified: trunk/neo/master/handlers/client.py
==============================================================================
--- trunk/neo/master/handlers/client.py [iso-8859-1] (original)
+++ trunk/neo/master/handlers/client.py [iso-8859-1] Tue Dec 14 16:57:04 2010
@@ -52,7 +52,8 @@ class ClientServiceHandler(MasterHandler
A client request a TID, nothing is kept about it until the finish.
"""
try:
- conn.answer(Packets.AnswerBeginTransaction(self.app.tm.begin(tid)))
+ conn.answer(Packets.AnswerBeginTransaction(self.app.tm.begin(
+ conn.getUUID(), tid)))
except DelayedError:
self.app.queueEvent(self.askBeginTransaction, conn, tid)
Modified: trunk/neo/master/transactions.py
==============================================================================
--- trunk/neo/master/transactions.py [iso-8859-1] (original)
+++ trunk/neo/master/transactions.py [iso-8859-1] Tue Dec 14 16:57:04 2010
@@ -325,7 +325,7 @@ class TransactionManager(object):
"""
return self._tid_dict.keys()
- def begin(self, tid=None):
+ def begin(self, uuid, tid=None):
"""
Generate a new TID
"""
@@ -336,7 +336,7 @@ class TransactionManager(object):
# TID requested, take commit lock immediately
if self._locked is not None:
raise DelayedError()
- self._locked = tid
+ self._locked = (uuid, tid)
return tid
def prepare(self, node, ttid, divisor, oid_list, uuid_list, msg_id):
@@ -344,7 +344,9 @@ class TransactionManager(object):
Prepare a transaction to be finished
"""
locked = self._locked
- if locked == ttid:
+ uuid = node.getUUID()
+ if locked is not None and locked[1] == ttid:
+ assert locked[0] == uuid
# Transaction requested some TID upon begin, and it owns the commit
# lock since then.
tid = ttid
@@ -353,7 +355,7 @@ class TransactionManager(object):
if locked is not None:
raise DelayedError()
tid = self._nextTID(ttid, divisor)
- self._locked = tid
+ self._locked = (uuid, tid)
self.setLastTID(tid)
txn = Transaction(node, ttid, tid, oid_list, uuid_list, msg_id)
@@ -365,7 +367,8 @@ class TransactionManager(object):
"""
Remove a transaction, commited or aborted
"""
- if tid == self._locked:
+ locked = self._locked
+ if locked is not None and tid == locked[1]:
# If TID has the lock, release it.
# It might legitimately not have the lock (ex: a transaction
# aborting, which didn't request a TID upon begin)
@@ -389,6 +392,9 @@ class TransactionManager(object):
"""
Abort pending transactions initiated by a node
"""
+ locked = self._locked
+ if locked is not None and locked[0] == node.getUUID():
+ self._locked = None
# nothing to do
if node not in self._node_dict:
return
Modified: trunk/neo/tests/master/testClientHandler.py
==============================================================================
--- trunk/neo/tests/master/testClientHandler.py [iso-8859-1] (original)
+++ trunk/neo/tests/master/testClientHandler.py [iso-8859-1] Tue Dec 14 16:57:04 2010
@@ -78,7 +78,7 @@ class MasterClientHandlerTests(NeoUnitTe
service.askBeginTransaction(conn, None)
calls = tm.mockGetNamedCalls('begin')
self.assertEqual(len(calls), 1)
- calls[0].checkArgs(None)
+ calls[0].checkArgs(client_uuid, None)
# Client asks for a TID
self.app.tm = tm_org
service.askBeginTransaction(conn, tid1)
Modified: trunk/neo/tests/master/testStorageHandler.py
==============================================================================
--- trunk/neo/tests/master/testStorageHandler.py [iso-8859-1] (original)
+++ trunk/neo/tests/master/testStorageHandler.py [iso-8859-1] Tue Dec 14 16:57:04 2010
@@ -101,7 +101,7 @@ class MasterStorageHandlerTests(NeoUnitT
oid_list = self.getOID(), self.getOID()
msg_id = 1
# register a transaction
- ttid = self.app.tm.begin()
+ ttid = self.app.tm.begin(client_1.getUUID())
tid = self.app.tm.prepare(client_1, ttid, 1, oid_list, uuid_list,
msg_id)
self.assertTrue(tid in self.app.tm)
@@ -208,7 +208,7 @@ class MasterStorageHandlerTests(NeoUnitT
# Transaction 1: 2 storage nodes involved, one will die and the other
# already answered node lock
msg_id_1 = 1
- ttid1 = tm.begin()
+ ttid1 = tm.begin(node1.getUUID())
tid1 = tm.prepare(client1, ttid1, 1, oid_list,
[node1.getUUID(), node2.getUUID()], msg_id_1)
tm.lock(tid1, node2.getUUID())
@@ -226,7 +226,7 @@ class MasterStorageHandlerTests(NeoUnitT
# Transaction 2: 2 storage nodes involved, one will die
msg_id_2 = 2
- ttid2 = tm.begin()
+ ttid2 = tm.begin(node1.getUUID())
tid2 = tm.prepare(client2, ttid2, 1, oid_list,
[node1.getUUID(), node2.getUUID()], msg_id_2)
# T2: pending locking answer, client keeps waiting
@@ -235,7 +235,7 @@ class MasterStorageHandlerTests(NeoUnitT
# Transaction 3: 1 storage node involved, which won't die
msg_id_3 = 3
- ttid3 = tm.begin()
+ ttid3 = tm.begin(node1.getUUID())
tid3 = tm.prepare(client3, ttid3, 1, oid_list,
[node2.getUUID(), ], msg_id_3)
# T3: action not significant to this transacion, so no response
Modified: trunk/neo/tests/master/testTransactions.py
==============================================================================
--- trunk/neo/tests/master/testTransactions.py [iso-8859-1] (original)
+++ trunk/neo/tests/master/testTransactions.py [iso-8859-1] Tue Dec 14 16:57:04 2010
@@ -59,12 +59,13 @@ class testTransactionManager(NeoUnitTest
msg_id = 1
oid_list = (oid1, oid2) = self.makeOID(1), self.makeOID(2)
uuid_list = (uuid1, uuid2) = self.makeUUID(1), self.makeUUID(2)
+ client_uuid = self.makeUUID(3)
# create transaction manager
txnman = TransactionManager()
self.assertFalse(txnman.hasPending())
self.assertEqual(txnman.getPendingList(), [])
# begin the transaction
- ttid = txnman.begin()
+ ttid = txnman.begin(client_uuid)
self.assertTrue(ttid is not None)
self.assertFalse(txnman.hasPending())
self.assertEqual(len(txnman.getPendingList()), 0)
@@ -89,10 +90,11 @@ class testTransactionManager(NeoUnitTest
oid_list = [self.makeOID(1), ]
storage_1_uuid = self.makeUUID(1)
storage_2_uuid = self.makeUUID(2)
+ client_uuid = self.makeUUID(3)
txnman = TransactionManager()
# register 4 transactions made by two nodes
self.assertEqual(txnman.getPendingList(), [])
- ttid1 = txnman.begin()
+ ttid1 = txnman.begin(client_uuid)
tid1 = txnman.prepare(node1, ttid1, 1, oid_list, [storage_1_uuid], 1)
self.assertEqual(txnman.getPendingList(), [tid1])
# abort transactions of another node, transaction stays
@@ -103,7 +105,7 @@ class testTransactionManager(NeoUnitTest
self.assertEqual(txnman.getPendingList(), [])
self.assertFalse(txnman.hasPending())
# ...and the lock is available
- txnman.begin(self.getNextTID())
+ txnman.begin(client_uuid, self.getNextTID())
def test_getNextOIDList(self):
txnman = TransactionManager()
@@ -125,12 +127,13 @@ class testTransactionManager(NeoUnitTest
storage_1_uuid = self.makeUUID(1)
storage_2_uuid = self.makeUUID(2)
oid_list = [self.makeOID(1), ]
+ client_uuid = self.makeUUID(3)
tm = TransactionManager()
# Transaction 1: 2 storage nodes involved, one will die and the other
# already answered node lock
msg_id_1 = 1
- ttid1 = tm.begin()
+ ttid1 = tm.begin(client_uuid)
tid1 = tm.prepare(client1, ttid1, 1, oid_list,
[storage_1_uuid, storage_2_uuid], msg_id_1)
tm.lock(tid1, storage_2_uuid)
@@ -144,7 +147,7 @@ class testTransactionManager(NeoUnitTest
# Transaction 2: 2 storage nodes involved, one will die
msg_id_2 = 2
- ttid2 = tm.begin()
+ ttid2 = tm.begin(client_uuid)
tid2 = tm.prepare(client2, ttid2, 1, oid_list,
[storage_1_uuid, storage_2_uuid], msg_id_2)
t2 = tm[tid2]
@@ -158,7 +161,7 @@ class testTransactionManager(NeoUnitTest
# Transaction 3: 1 storage node involved, which won't die
msg_id_3 = 3
- ttid3 = tm.begin()
+ ttid3 = tm.begin(client_uuid)
tid3 = tm.prepare(client3, ttid3, 1, oid_list, [storage_2_uuid, ],
msg_id_3)
t3 = tm[tid3]
@@ -202,22 +205,36 @@ class testTransactionManager(NeoUnitTest
strictly increasing order.
Note: this implementation might change later, to allow more paralelism.
"""
+ client_uuid = self.makeUUID(3)
tm = TransactionManager()
# With a requested TID, lock spans from begin to remove
ttid1 = self.getNextTID()
ttid2 = self.getNextTID()
- tid1 = tm.begin(ttid1)
+ tid1 = tm.begin(client_uuid, ttid1)
self.assertEqual(tid1, ttid1)
- self.assertRaises(DelayedError, tm.begin, ttid2)
+ self.assertRaises(DelayedError, tm.begin, client_uuid, ttid2)
tm.remove(tid1)
- tm.remove(tm.begin(ttid2))
+ tm.remove(tm.begin(client_uuid, ttid2))
# Without a requested TID, lock spans from prepare to remove only
- ttid3 = tm.begin()
- ttid4 = tm.begin() # Doesn't raise
- tid4 = tm.prepare(None, ttid4, 1, [], [], 0)
- self.assertRaises(DelayedError, tm.prepare, None, ttid3, 1, [], [], 0)
+ ttid3 = tm.begin(client_uuid)
+ ttid4 = tm.begin(client_uuid) # Doesn't raise
+ node = Mock({'getUUID': client_uuid, '__hash__': 0})
+ tid4 = tm.prepare(node, ttid4, 1, [], [], 0)
+ self.assertRaises(DelayedError, tm.prepare, node, ttid3, 1, [], [], 0)
tm.remove(tid4)
- tm.prepare(None, ttid3, 1, [], [], 0)
+ tm.prepare(node, ttid3, 1, [], [], 0)
+
+ def testClientDisconectsAfterBegin(self):
+ client1_uuid = self.makeUUID(1)
+ client2_uuid = self.makeUUID(2)
+ tm = TransactionManager()
+ tid1 = self.getNextTID()
+ tid2 = self.getNextTID()
+ tm.begin(client1_uuid, tid1)
+ self.assertRaises(DelayedError, tm.begin, client2_uuid, tid2)
+ node1 = Mock({'getUUID': client1_uuid, '__hash__': 0})
+ tm.abortFor(node1)
+ tm.begin(client2_uuid, tid2)
if __name__ == '__main__':
unittest.main()
More information about the Neo-report
mailing list