[PATCH 1.7 4/4] txn: fix on_replace trigger chaining

Vladimir Davydov vdavydov.dev at gmail.com
Tue Jan 23 13:06:14 MSK 2018


If there are multiple on_replace triggers installed for the same space
and one of them creates a new statement (by issuing a DML request), then
the trigger that is called next will get the statement created by the
previous trigger instead of the original statement. To fix that, let's
patch txn_current_stmt() so as to return the first statement at the
current transaction level instead of the last statement and use it in
txn_commit_stmt(). This will also allow us to issue DML requests from a
before_replace trigger without disrupting the current statement.

Needed for #2993
Follow-up #3020
---
 src/box/txn.c                |  3 +--
 src/box/txn.h                |  8 +++---
 test/box/on_replace.result   | 60 ++++++++++++++++++++++++++++++++++++++++++++
 test/box/on_replace.test.lua | 25 ++++++++++++++++++
 4 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/src/box/txn.c b/src/box/txn.c
index d017b967..1af8243e 100644
--- a/src/box/txn.c
+++ b/src/box/txn.c
@@ -205,8 +205,7 @@ txn_commit_stmt(struct txn *txn, struct request *request)
 	 * Run on_replace triggers. For now, disallow mutation
 	 * of tuples in the trigger.
 	 */
-	struct txn_stmt *stmt = stailq_last_entry(&txn->stmts,
-						  struct txn_stmt, next);
+	struct txn_stmt *stmt = txn_current_stmt(txn);
 
 	/* Create WAL record for the write requests in non-temporary spaces */
 	if (!space_is_temporary(stmt->space)) {
diff --git a/src/box/txn.h b/src/box/txn.h
index f8d3487f..4db74dfc 100644
--- a/src/box/txn.h
+++ b/src/box/txn.h
@@ -264,9 +264,11 @@ txn_check_singlestatement(struct txn *txn, const char *where);
 static inline struct txn_stmt *
 txn_current_stmt(struct txn *txn)
 {
-	return (txn->in_sub_stmt > 0 ?
-		stailq_last_entry(&txn->stmts, struct txn_stmt, next) :
-		NULL);
+	if (txn->in_sub_stmt == 0)
+		return NULL;
+	struct stailq_entry *stmt = txn->sub_stmt_begin[txn->in_sub_stmt - 1];
+	stmt = stmt != NULL ? stailq_next(stmt) : stailq_first(&txn->stmts);
+	return stailq_entry(stmt, struct txn_stmt, next);
 }
 
 /** The last statement of the transaction. */
diff --git a/test/box/on_replace.result b/test/box/on_replace.result
index e05791ff..d6158dc5 100644
--- a/test/box/on_replace.result
+++ b/test/box/on_replace.result
@@ -624,3 +624,63 @@ s2:drop()
 s3:drop()
 ---
 ...
+--
+-- gh-3020: trigger chaining
+--
+s1 = box.schema.space.create('test1')
+---
+...
+_ = s1:create_index('pk')
+---
+...
+s2 = box.schema.space.create('test2')
+---
+...
+_ = s2:create_index('pk')
+---
+...
+s3 = box.schema.space.create('test3')
+---
+...
+_ = s3:create_index('pk')
+---
+...
+x = 1
+---
+...
+_ = s1:on_replace(function(old, new) s2:insert(new:update{{'!', 2, x}}) x = x + 1 end)
+---
+...
+_ = s1:on_replace(function(old, new) s3:insert(new:update{{'!', 2, x}}) x = x + 1 end)
+---
+...
+box.begin() s1:insert{1} s1:insert{2} s1:insert{3} box.commit()
+---
+...
+s1:select()
+---
+- - [1]
+  - [2]
+  - [3]
+...
+s2:select()
+---
+- - [1, 2]
+  - [2, 4]
+  - [3, 6]
+...
+s3:select()
+---
+- - [1, 1]
+  - [2, 3]
+  - [3, 5]
+...
+s1:drop()
+---
+...
+s2:drop()
+---
+...
+s3:drop()
+---
+...
diff --git a/test/box/on_replace.test.lua b/test/box/on_replace.test.lua
index 906fd99b..190c6f18 100644
--- a/test/box/on_replace.test.lua
+++ b/test/box/on_replace.test.lua
@@ -250,3 +250,28 @@ s3:select()
 s1:drop()
 s2:drop()
 s3:drop()
+
+--
+-- gh-3020: trigger chaining
+--
+s1 = box.schema.space.create('test1')
+_ = s1:create_index('pk')
+s2 = box.schema.space.create('test2')
+_ = s2:create_index('pk')
+s3 = box.schema.space.create('test3')
+_ = s3:create_index('pk')
+
+x = 1
+
+_ = s1:on_replace(function(old, new) s2:insert(new:update{{'!', 2, x}}) x = x + 1 end)
+_ = s1:on_replace(function(old, new) s3:insert(new:update{{'!', 2, x}}) x = x + 1 end)
+
+box.begin() s1:insert{1} s1:insert{2} s1:insert{3} box.commit()
+
+s1:select()
+s2:select()
+s3:select()
+
+s1:drop()
+s2:drop()
+s3:drop()
-- 
2.11.0




More information about the Tarantool-patches mailing list