Commit 15472c62 authored by Julien Muchembled's avatar Julien Muchembled

storage: fix crash when a client loses connection to the master just before voting

This is similar to commit 7aecdada
and for completeness, we also protect unlock the same way.
parent 298cb6c4
Pipeline #3856 skipped
......@@ -647,6 +647,10 @@ class Application(ThreadedApplication):
txn_context['voted'] = None
# We must not go further if connection to master was lost since
# tpc_begin, to lower the probability of failing during tpc_finish.
# IDEA: We can improve in 2 opposite directions:
# - In the case of big transactions, it would be useful to
# also detect failures earlier.
# - If possible, recover from master failure.
if 'error' in txn_context:
raise NEOStorageError(txn_context['error'])
return result
......
......@@ -162,7 +162,10 @@ class TransactionManager(object):
Store transaction information received from client node
"""
logging.debug('Vote TXN %s', dump(ttid))
transaction = self._transaction_dict[ttid]
try:
transaction = self._transaction_dict[ttid]
except KeyError:
raise ProtocolError("unknown ttid %s" % dump(ttid))
object_list = transaction.getObjectList()
if txn_info:
user, desc, ext, oid_list = txn_info
......@@ -195,7 +198,10 @@ class TransactionManager(object):
"""
Unlock transaction
"""
tid = self._transaction_dict[ttid].getTID()
try:
tid = self._transaction_dict[ttid].getTID()
except KeyError:
raise ProtocolError("unknown ttid %s" % dump(ttid))
logging.debug('Unlock TXN %s (ttid=%s)', dump(tid), dump(ttid))
dm = self._app.dm
dm.unlockTransaction(tid, ttid)
......
......@@ -1135,6 +1135,25 @@ class Test(NEOThreadedTest):
finally:
cluster.stop()
def testMasterFailureBeforeVote(self):
def waitStoreResponses(orig, *args):
result = orig(*args)
m2c, = cluster.master.getConnectionList(orig.__self__)
m2c.close()
self.tic()
return result
cluster = NEOCluster(storage_count=2, partitions=2)
try:
cluster.start()
t, c = cluster.getTransaction()
c.root()['x'] = PCounter() # 1 store() to each storage
with Patch(cluster.client, waitStoreResponses=waitStoreResponses):
self.assertRaises(POSException.StorageError, t.commit)
self.assertEqual(cluster.neoctl.getClusterState(),
ClusterStates.RUNNING)
finally:
cluster.stop()
def testEmptyTransaction(self):
cluster = NEOCluster()
try:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment