From afa5586beabbb57226c348496953aee9bd22ebe3 Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Wed, 23 Jul 2014 17:55:41 +0400
Subject: [PATCH] Allocate transaction on_stop trigger with struct txn

Fix potential bug multiple parallel transactions
---
 src/box/txn.cc | 20 +++++++++++---------
 src/box/txn.h  |  2 ++
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/box/txn.cc b/src/box/txn.cc
index 16c633591f..86c126809b 100644
--- a/src/box/txn.cc
+++ b/src/box/txn.cc
@@ -54,16 +54,12 @@ txn_add_redo(struct txn_stmt *stmt, struct request *request)
 	stmt->row = row;
 }
 
-extern "C" void
+static void
 txn_on_yield(struct trigger * /* trigger */, void * /* event */)
 {
 	txn_rollback(); /* doesn't throw */
 }
 
-struct trigger on_yield = {
-	rlist_nil, txn_on_yield, NULL, NULL
-};
-
 void
 txn_replace(struct txn *txn, struct space *space,
 	    struct tuple *old_tuple, struct tuple *new_tuple,
@@ -95,8 +91,10 @@ txn_replace(struct txn *txn, struct space *space,
 	if (txn->autocommit == false) {
 		if (txn->n_stmts == 1) {
 			txn->engine = engine_id(space->engine);
-			if (engine_no_yield(txn->engine))
-				trigger_add(&fiber()->on_yield, &on_yield);
+			if (engine_no_yield(txn->engine)) {
+				trigger_add(&fiber()->on_yield,
+					    &txn->fiber_on_yield);
+			}
 		} else if (txn->engine != engine_id(space->engine))
 			tnt_raise(ClientError, ER_CROSS_ENGINE_TRANSACTION);
 		if (! engine_transactional(txn->engine)) {
@@ -137,6 +135,10 @@ txn_begin(bool autocommit)
 	rlist_create(&txn->stmts);
 	rlist_create(&txn->on_commit);
 	rlist_create(&txn->on_rollback);
+	txn->fiber_on_yield = {
+		rlist_nil, txn_on_yield, NULL, NULL
+	};
+
 	txn->autocommit = autocommit;
 	in_txn() = txn;
 	return txn;
@@ -171,7 +173,7 @@ txn_commit(struct txn *txn)
 	assert(txn == in_txn());
 	struct txn_stmt *stmt;
 	/* if (!txn->autocommit && txn->n_stmts && engine_no_yield(txn->engine)) */
-		trigger_clear(&on_yield);
+		trigger_clear(&txn->fiber_on_yield);
 	rlist_foreach_entry(stmt, &txn->stmts, next) {
 		if ((!stmt->old_tuple && !stmt->new_tuple) ||
 		    space_is_temporary(stmt->space))
@@ -252,7 +254,7 @@ txn_rollback()
 			tuple_ref(stmt->new_tuple, -1);
 	}
 	/* if (!txn->autocommit && txn->n_stmts && engine_no_yield(txn->engine)) */
-		trigger_clear(&on_yield);
+		trigger_clear(&txn->fiber_on_yield);
 	TRASH(txn);
 	/** Free volatile txn memory. */
 	fiber_gc();
diff --git a/src/box/txn.h b/src/box/txn.h
index aebe1259a0..aa25e53a0a 100644
--- a/src/box/txn.h
+++ b/src/box/txn.h
@@ -69,6 +69,8 @@ struct txn {
 	bool autocommit;
 	/** Id of the engine involved in multi-statement transaction. */
 	uint8_t engine;
+	/** Trigger on fiber yield to abort transaction for in-memory engine */
+	struct trigger fiber_on_yield;
 };
 
 /* Pointer to the current transaction (if any) */
-- 
GitLab