From 3f0281651e1a80572b2a97b05604e030e8a1c141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Sun, 22 Mar 2026 11:03:53 +0100 Subject: [PATCH] Extract transaction state tracking logic (Phase 3.8, #5496) New files: - include/TransactionState.h: 2 pure function declarations - lib/TransactionState.cpp: implementations Functions: - update_transaction_persistent_hostgroup(): mirrors session logic for locking/unlocking HG on transaction start/end - is_transaction_timed_out(): checks if transaction exceeded max time Logic identical for MySQL and PgSQL (shared via Base_Session). --- include/TransactionState.h | 48 +++++++++++++++++++++++++++++++++ lib/Makefile | 1 + lib/TransactionState.cpp | 55 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 include/TransactionState.h create mode 100644 lib/TransactionState.cpp diff --git a/include/TransactionState.h b/include/TransactionState.h new file mode 100644 index 000000000..e6456008a --- /dev/null +++ b/include/TransactionState.h @@ -0,0 +1,48 @@ +/** + * @file TransactionState.h + * @brief Pure transaction state tracking logic for unit testability. + * + * Extracted from MySQL_Session/PgSQL_Session transaction persistence + * logic. The decision is identical for both protocols. + * + * @see Phase 3.8 (GitHub issue #5496) + */ + +#ifndef TRANSACTION_STATE_H +#define TRANSACTION_STATE_H + +/** + * @brief Update transaction_persistent_hostgroup based on backend state. + * + * Mirrors the logic in MySQL_Session/PgSQL_Session (~lines 9276-9293): + * - When a transaction starts on a backend, lock to the current HG + * - When a transaction ends, unlock (-1) + * + * @param transaction_persistent Whether transaction persistence is enabled. + * @param transaction_persistent_hostgroup Current persistent HG (-1 = none). + * @param current_hostgroup HG where the query executed. + * @param backend_in_transaction Whether the backend has an active transaction. + * @return Updated transaction_persistent_hostgroup value. + */ +int update_transaction_persistent_hostgroup( + bool transaction_persistent, + int transaction_persistent_hostgroup, + int current_hostgroup, + bool backend_in_transaction +); + +/** + * @brief Check if a transaction has exceeded the maximum allowed time. + * + * @param transaction_started_at Timestamp when transaction started (0 = none). + * @param current_time Current timestamp. + * @param max_transaction_time_ms Maximum transaction time in milliseconds (0 = no limit). + * @return true if the transaction has exceeded the time limit. + */ +bool is_transaction_timed_out( + unsigned long long transaction_started_at, + unsigned long long current_time, + int max_transaction_time_ms +); + +#endif // TRANSACTION_STATE_H diff --git a/lib/Makefile b/lib/Makefile index f7f24075c..c91a22854 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -106,6 +106,7 @@ _OBJ_CXX := ProxySQL_GloVars.oo network.oo debug.oo configfile.oo Query_Cache.oo PgSQL_PreparedStatement.oo PgSQL_Extended_Query_Message.oo \ pgsql_tokenizer.oo \ MonitorHealthDecision.oo \ + TransactionState.oo \ proxy_sqlite3_symbols.oo # TSDB object files diff --git a/lib/TransactionState.cpp b/lib/TransactionState.cpp new file mode 100644 index 000000000..e68bf509c --- /dev/null +++ b/lib/TransactionState.cpp @@ -0,0 +1,55 @@ +/** + * @file TransactionState.cpp + * @brief Implementation of pure transaction state tracking. + * + * @see TransactionState.h + * @see Phase 3.8 (GitHub issue #5496) + */ + +#include "TransactionState.h" + +int update_transaction_persistent_hostgroup( + bool transaction_persistent, + int transaction_persistent_hostgroup, + int current_hostgroup, + bool backend_in_transaction) +{ + if (!transaction_persistent) { + return -1; // persistence disabled + } + + if (transaction_persistent_hostgroup == -1) { + // Not currently locked — lock if transaction just started + if (backend_in_transaction) { + return current_hostgroup; + } + } else { + // Currently locked — unlock if transaction just ended + if (!backend_in_transaction) { + return -1; + } + } + + return transaction_persistent_hostgroup; // no change +} + +bool is_transaction_timed_out( + unsigned long long transaction_started_at, + unsigned long long current_time, + int max_transaction_time_ms) +{ + if (transaction_started_at == 0) { + return false; // no active transaction + } + if (max_transaction_time_ms <= 0) { + return false; // no time limit + } + + unsigned long long elapsed_ms = 0; + if (current_time > transaction_started_at) { + elapsed_ms = (current_time - transaction_started_at) / 1000; + // transaction_started_at and current_time are in microseconds + } + + return (elapsed_ms > (unsigned long long)max_transaction_time_ms); +}