Skip to content

Improve fast forward replication CLIENT_DEPRECATE_EOF validation (closes #5062)#5240

Merged
renecannao merged 1 commit intov3.0from
v3.0-5062
Dec 6, 2025
Merged

Improve fast forward replication CLIENT_DEPRECATE_EOF validation (closes #5062)#5240
renecannao merged 1 commit intov3.0from
v3.0-5062

Conversation

@renecannao
Copy link
Contributor

Summary

Enhance fast forward replication CLIENT_DEPRECATE_EOF validation to improve compatibility and robustness.

Changes Made

  • Improved match_ff_req_options function in lib/mysql_connection.cpp
  • Enhanced CLIENT_DEPRECATE_EOF flag validation for fast forward replication scenarios
  • Added special handling for binlog-related commands that should be allowed even when CLIENT_DEPRECATE_EOF flags don't match
  • Implemented proper packet parsing to extract and validate MySQL command types

Technical Details

The function now performs a more robust check by examining the actual MySQL command type when the initial CLIENT_DEPRECATE_EOF flags don't match between frontend and backend connections. Special handling is provided for:

  • _MYSQL_COM_BINLOG_DUMP
  • _MYSQL_COM_BINLOG_DUMP_GTID
  • _MYSQL_COM_REGISTER_SLAVE

These commands are now allowed even when CLIENT_DEPRECATE_EOF flags don't match, improving compatibility for fast forward replication connections with mixed deprecate EOF configurations.

Test Coverage

This change is complemented by the new test fast_forward_switch_replication_deprecate_eof.cpp which validates all combinations of mysql-enable_client_deprecate_eof and mysql-enable_server_deprecate_eof settings.

Closes

#5062

Enhance the match_ff_req_options function to better handle CLIENT_DEPRECATE_EOF
flag validation in fast forward replication scenarios. The function now performs
a more robust check by examining the actual MySQL command type when the initial
CLIENT_DEPRECATE_EOF flags don't match between frontend and backend connections.

Key improvements:
- Special handling for binlog-related commands (_MYSQL_COM_BINLOG_DUMP,
  _MYSQL_COM_BINLOG_DUMP_GTID, _MYSQL_COM_REGISTER_SLAVE) that should be
  allowed even when CLIENT_DEPRECATE_EOF flags don't match
- Proper packet parsing to extract and validate MySQL command types
- Enhanced compatibility for fast forward replication connections with
  mixed deprecate EOF configurations

This change ensures that ProxySQL can handle more complex replication
scenarios while maintaining proper protocol validation.
@gemini-code-assist
Copy link

Summary of Changes

Hello @renecannao, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refines the fast forward replication mechanism by improving the validation of the CLIENT_DEPRECATE_EOF flag. It introduces more robust checks within the match_ff_req_options function, allowing critical binlog-related commands to bypass strict flag matching, thereby enhancing compatibility and stability for replication scenarios with differing EOF configurations.

Highlights

  • CLIENT_DEPRECATE_EOF Validation: The match_ff_req_options function in lib/mysql_connection.cpp has been enhanced to improve validation of the CLIENT_DEPRECATE_EOF flag during fast forward replication.
  • Special Command Handling: Specific binlog-related commands (_MYSQL_COM_BINLOG_DUMP, _MYSQL_COM_BINLOG_DUMP_GTID, _MYSQL_COM_REGISTER_SLAVE) are now explicitly allowed to proceed even if CLIENT_DEPRECATE_EOF flags do not match, improving compatibility.
  • Packet Parsing for Command Type: The validation logic now includes parsing the incoming packet to extract and identify the MySQL command type, enabling conditional handling based on the command.
  • Test Coverage: A new test, fast_forward_switch_replication_deprecate_eof.cpp, has been added to validate various combinations of mysql-enable_client_deprecate_eof and mysql-enable_server_deprecate_eof settings.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the fast forward replication logic by allowing specific binlog-related commands to bypass the CLIENT_DEPRECATE_EOF flag check. The change correctly identifies these commands by inspecting the packet payload. My review includes a suggestion to refactor the implementation in lib/mysql_connection.cpp to improve readability and maintainability by flattening nested conditions and simplifying pointer casting. Overall, the change is a good improvement for replication compatibility.

Comment on lines +741 to +763
bool ret = (frontend->options.client_flag & CLIENT_DEPRECATE_EOF) ==
(backend->mysql->server_capabilities & CLIENT_DEPRECATE_EOF);
if (ret == false) {
if (frontend->myds && frontend->myds->PSarrayIN) {
PtrSizeArray * PSarrayIN = frontend->myds->PSarrayIN;
if (PSarrayIN->len == 1) {
PtrSize_t pkt = PSarrayIN->pdata[0];
if (pkt.size >= 5) {
unsigned char c = *reinterpret_cast<unsigned char*>(static_cast<char*>(pkt.ptr) + 4);
switch ((enum_mysql_command)c) {
case _MYSQL_COM_BINLOG_DUMP:
case _MYSQL_COM_BINLOG_DUMP_GTID:
case _MYSQL_COM_REGISTER_SLAVE:
ret = true;
break;
default:
break;
};
}
}
}
}
return ret;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic here can be refactored to improve readability and maintainability.

  • The deeply nested if statements form an "arrowhead" structure which can be flattened using guard clauses (early returns). This makes the code easier to follow.
  • The extraction of the command byte can be simplified and made safer by avoiding reinterpret_cast. A static_cast to const unsigned char* followed by array indexing is cleaner.
  • The ret variable can be eliminated in favor of early returns, which simplifies control flow.

Here is a suggested refactoring:

                const bool flags_match = (frontend->options.client_flag & CLIENT_DEPRECATE_EOF) ==
				(backend->mysql->server_capabilities & CLIENT_DEPRECATE_EOF);
		if (flags_match) {
			return true;
		}

		if (!frontend->myds || !frontend->myds->PSarrayIN || frontend->myds->PSarrayIN->len != 1) {
			return false;
		}

		const PtrSize_t pkt = frontend->myds->PSarrayIN->pdata[0];
		if (pkt.size < 5) {
			return false;
		}

		const auto command = static_cast<enum_mysql_command>(static_cast<const unsigned char*>(pkt.ptr)[4]);

		switch (command) {
			case _MYSQL_COM_BINLOG_DUMP:
			case _MYSQL_COM_BINLOG_DUMP_GTID:
			case _MYSQL_COM_REGISTER_SLAVE:
				return true;
			default:
				return false;
		}

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 5, 2025

@renecannao renecannao merged commit 0f719d3 into v3.0 Dec 6, 2025
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant