From 4d379127cb3356a843cc6a615c478644abf3204c Mon Sep 17 00:00:00 2001
From: Nikolay Shirokovskiy <nshirokovskiy@tarantool.org>
Date: Tue, 5 Dec 2023 13:31:28 +0300
Subject: [PATCH] iproto: don't account message twice in case of override
 fallback

We need to call `tx_accept_msg` in `tx_process_override` before we pass
message to the override handler. Unfortunately if handler response with
IPROTO_HANDLER_FALLBACK we call the builtin handler for message that
calls `tx_accept_msg` again which is not expected. Some actions of
this function are idempotent and some are not.

Let's make the function NOP if it called once again.

Closes #9345

NO_DOC=bugfix

(cherry picked from commit 21112b066902338724f4f3671359f3e624b45938)
---
 ...-fix-iproto-override-double-request-account.md |  4 ++++
 src/box/iproto.cc                                 | 10 ++++++++++
 .../iproto_request_handlers_overriding_test.lua   | 15 +++++++++++++++
 3 files changed, 29 insertions(+)
 create mode 100644 changelogs/unreleased/gh-9345-fix-iproto-override-double-request-account.md

diff --git a/changelogs/unreleased/gh-9345-fix-iproto-override-double-request-account.md b/changelogs/unreleased/gh-9345-fix-iproto-override-double-request-account.md
new file mode 100644
index 0000000000..5198b47b5b
--- /dev/null
+++ b/changelogs/unreleased/gh-9345-fix-iproto-override-double-request-account.md
@@ -0,0 +1,4 @@
+## bugfix/core
+
+* Fixed incorrect calculation of requests in progress in case of iproto
+  override fallback (gh-9345).
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index d963dfbbc1..4c37a869da 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -420,6 +420,12 @@ struct iproto_msg
 	struct stailq_entry in_stream;
 	/** Stream that owns this message, or NULL. */
 	struct iproto_stream *stream;
+	/**
+	 * True if message processing in tx thread is started. The flag is
+	 * used to prevent double accounting of message in case of iproto
+	 * override fallback to original handler.
+	 */
+	bool accepted;
 };
 
 static struct iproto_msg *
@@ -812,6 +818,7 @@ iproto_msg_new(struct iproto_connection *con)
 	msg->close_connection = false;
 	msg->connection = con;
 	msg->stream = NULL;
+	msg->accepted = false;
 	rmean_collect(con->iproto_thread->rmean, IPROTO_REQUESTS, 1);
 	return msg;
 }
@@ -1978,6 +1985,9 @@ static inline struct iproto_msg *
 tx_accept_msg(struct cmsg *m)
 {
 	struct iproto_msg *msg = (struct iproto_msg *) m;
+	if (msg->accepted)
+		return msg;
+	msg->accepted = true;
 	tx_accept_wpos(msg->connection, &msg->wpos);
 	tx_fiber_init(msg->connection->session, msg->header.sync);
 	tx_prepare_transaction_for_request(msg);
diff --git a/test/box-luatest/iproto_request_handlers_overriding_test.lua b/test/box-luatest/iproto_request_handlers_overriding_test.lua
index 18731e06aa..4c7fdd6783 100644
--- a/test/box-luatest/iproto_request_handlers_overriding_test.lua
+++ b/test/box-luatest/iproto_request_handlers_overriding_test.lua
@@ -417,3 +417,18 @@ g.test_box_iproto_override_cb_lua_invalid_return_type = function(cg)
         box.iproto.override(box.iproto.type.PING, nil)
     end)
 end
+
+-- gh-9345: Checks that we don't account message twice in case of fallback.
+g.test_box_iproto_override_fallback_double_accounting = function(cg)
+    cg.server:exec(function()
+        local cb_fallback = function()
+            return false
+        end
+        local before = box.stat.net().REQUESTS_IN_PROGRESS.current
+        box.iproto.override(box.iproto.type.PING, cb_fallback)
+        _G.test_ping()
+        box.iproto.override(box.iproto.type.PING, nil)
+        local after = box.stat.net().REQUESTS_IN_PROGRESS.current
+        t.assert_equals(after - before, 0)
+    end)
+end
-- 
GitLab