From dca01d4eaf32c8363ff14fb4f74a46deb73e11c3 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sat, 4 Apr 2026 14:15:37 +0000 Subject: [PATCH] Add I3/I4 message types for GTID range updates, disconnect on unknown message I1/I2 now strictly handle single trxid values (parsed via atoll). New I3/I4 messages handle range-based trxid updates (parsed as TrxId_Interval strings). This ensures backwards compatibility: an old ProxySQL receiving I3/I4 will safely ignore them via default:break, while a new ProxySQL correctly distinguishes single vs range messages. Also fixes events_read being incremented for unrecognized message types, and disconnects on unknown message types instead of silently ignoring them. --- lib/GTID_Server_Data.cpp | 41 +++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/GTID_Server_Data.cpp b/lib/GTID_Server_Data.cpp index 84220512f..cf42c7aed 100644 --- a/lib/GTID_Server_Data.cpp +++ b/lib/GTID_Server_Data.cpp @@ -81,6 +81,15 @@ void reader_cb(struct ev_loop *loop, struct ev_io *w, int revents) { sd->w = nullptr; } else { sd->dump(); + if (sd->active == false) { + // protocol error detected during parsing (e.g. unsupported message type) + MyHGM->gtid_missing_nodes = true; + proxy_warning("GTID: protocol error from ProxySQL binlog reader on port %d for server %s:%d , disconnecting\n", sd->port, sd->address, sd->mysql_port); + ev_io_stop(MyHGM->gtid_ev_loop, w); + close(w->fd); + free(w); + sd->w = nullptr; + } } } pthread_mutex_unlock(&ev_loop_mutex); @@ -300,11 +309,13 @@ bool GTID_Server_Data::writeout() { } /* - * The wire format for the binlogreader is three distinct messages, in plaintext: + * The wire format for the binlogreader is five distinct messages, in plaintext: * * ST=:[-][,:[-], ...] : Bootstrap message, providing individual transaction ID or trxid ranges for all seen UUID servers. - * I1=:[-] : Latest seen trxid or trxid ranges for a given UUID. - * I2=[-] : Latest seen trxid or trxid ranges. + * I1=: : Latest seen single trxid for a given UUID. + * I2= : Latest seen single trxid, reusing UUID from previous I1/I3 message. + * I3=:- : Latest seen trxid range for a given UUID. + * I4=- : Latest seen trxid range, reusing UUID from previous I1/I3 message. */ bool GTID_Server_Data::read_next_gtid() { if (len==0) { @@ -369,20 +380,36 @@ bool GTID_Server_Data::read_next_gtid() { char *a = NULL; int ul = 0; switch (rec_msg[1]) { - case '1': + case '1': // single trxid with UUID + a = strchr(rec_msg+3,':'); + ul = a-rec_msg-3; + strncpy(uuid_server,rec_msg+3,ul); + uuid_server[ul] = 0; + gtid_executed.add((std::string)uuid_server, (trxid_t)atoll(a+1)); + events_read++; + break; + case '2': // single trxid, reuse last UUID + gtid_executed.add((std::string)uuid_server, (trxid_t)atoll(rec_msg+3)); + events_read++; + break; + case '3': // trxid range with UUID a = strchr(rec_msg+3,':'); ul = a-rec_msg-3; strncpy(uuid_server,rec_msg+3,ul); uuid_server[ul] = 0; gtid_executed.add((std::string)uuid_server, a+1); + events_read++; break; - case '2': + case '4': // trxid range, reuse last UUID gtid_executed.add((std::string)uuid_server, rec_msg+3); + events_read++; break; default: - break; + proxy_warning("GTID: unsupported message type 'I%c' from binlog reader on port %d for server %s:%d , disconnecting\n", + rec_msg[1], port, address, mysql_port); + active = false; + return false; } - events_read++; } } return true;