Commit 04ae2fc0 authored by Julien Muchembled's avatar Julien Muchembled

client: fix possible corruption in case of network failure with a storage

In case of storage disconnection, one packet (VoteTransaction) was not handled
the same way as other writes, and the failure was not reported to the master
so that it arbitrates the vote. The transaction was therefore partially
committed.
parent 61e4ffa1
...@@ -562,7 +562,7 @@ class Application(ThreadedApplication): ...@@ -562,7 +562,7 @@ class Application(ThreadedApplication):
for uuid, status in involved_nodes.iteritems(): for uuid, status in involved_nodes.iteritems():
if status == 1 and uuid not in trans_nodes: if status == 1 and uuid not in trans_nodes:
self._askStorageForWrite(txn_context, uuid, packet) self._askStorageForWrite(txn_context, uuid, packet)
self.waitResponses(txn_context.queue) self.waitStoreResponses(txn_context)
# If there are failed nodes, ask the master whether they can be # If there are failed nodes, ask the master whether they can be
# disconnected while keeping the cluster operational. If possible, # disconnected while keeping the cluster operational. If possible,
# this will happen during tpc_finish. # this will happen during tpc_finish.
......
...@@ -1652,6 +1652,32 @@ class Test(NEOThreadedTest): ...@@ -1652,6 +1652,32 @@ class Test(NEOThreadedTest):
self.tic() self.tic()
self.assertPartitionTable(cluster, pt) self.assertPartitionTable(cluster, pt)
@with_cluster(partitions=2, storage_count=2)
def testMasterArbitratingVoteAfterFailedVoteTransaction(self, cluster):
"""
Check that the master node arbitrates the vote when a failure happens
at the end of the first phase (VoteTransaction).
"""
t, c = cluster.getTransaction()
tid = cluster.client.last_tid
r = c.root()
r[0] = ''
delayed = []
with cluster.moduloTID(1), ConnectionFilter() as f:
@f.delayAskVoteTransaction
def _(conn):
delayed.append(None)
s, = (s for s in cluster.storage_list if conn.uuid == s.uuid)
conn, = s.getConnectionList(cluster.client)
conn.em.wakeup(conn.close)
return False
self.assertRaises(NEOStorageError, t.commit)
self.tic()
self.assertEqual(len(delayed), 1)
self.assertEqual(tid, cluster.client.last_tid)
self.assertEqual(cluster.neoctl.getClusterState(),
ClusterStates.RUNNING)
@with_cluster() @with_cluster()
def testAbortTransaction(self, cluster): def testAbortTransaction(self, cluster):
t, c = cluster.getTransaction() t, c = cluster.getTransaction()
......
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