Skip to content

Conversation

@ParadoxV5
Copy link
Contributor

  • The Jira issue number for this PR is: MDEV-35879

Description

Master_info::heartbeat_period was previously a float, which only has 7 decimal digits of precision on most platforms, which is less than the maximum of 10 its range allows, let alone superfluous user inputs.

This commit solves this issue by changing this
field to a DECIMAL(10, 3); specifically:

  • A uint32_t of milliseconds internally,
  • A my_decimal of seconds when parsing CHANGE MASTER,
  • A double of seconds when showing to the user, as reads are not affected by external precision issues

While here, this commit also corrects the rounding method from “round down” to “nearest millisecond”.

Release Notes

Fix CHANGE MASTER TO master_heartbeat_period imprecision for large values

How can this PR be tested?

This commit adds another test value and additional queries to rpl.rpl_heartbeat_basic.

PR quality check

  • This is a new feature or a refactoring, and the PR is based against the main branch.
    • This commit does not move code.
  • This is a bug fix, and the PR is based against the earliest maintained branch in which the bug can be reproduced.
  • I checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am ok with the reviewer making the changes themselves.

`Master_info::heartbeat_period` was previously a `float`, which only has
7 decimal digits of precision on most platforms, which is less than the
maximum of 10 its range allows, let alone superfluous user inputs.

This commit solves this issue by changing this
field to a `DECIMAL(10, 3)`; specifically:
* A `uint32_t` of milliseconds internally,
* A `my_decimal` of seconds when parsing CHANGE MASTER,
* A `double` of seconds when showing to the user,
  as reads are not affected by external precision issues

While here, this commit also corrects the rounding
method from “round down” to “nearest millisecond”.
@ParadoxV5 ParadoxV5 added MariaDB Corporation Replication Patches involved in replication labels Nov 17, 2025
Value 5.000
connection slave;
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.0009999;
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.0004999;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I keep the rounding method change out of 10.11?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Range testing of master_heartbeat_period is duplicated between rpl_heartbeat_basic (runs with mix only) and rpl_heartbeat (tests all three binlog formats).

Copy link
Contributor Author

@ParadoxV5 ParadoxV5 left a comment

Choose a reason for hiding this comment

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

Huge nit:
The double interfaces of decimal_t are implemented by printing into a string and parsing that char array.
Even without benchmarks, this already sounds impractical.

Comment on lines +2272 to +2278
Decimal_from_double(double value): my_decimal()
{
int unexpected_error __attribute__((unused))=
double2my_decimal(E_DEC_ERROR, value, this);
DBUG_ASSERT(!unexpected_error);
}
} MAX_PERIOD= SLAVE_MAX_HEARTBEAT_PERIOD/1000.0, THOUSAND= 1000;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
Decimal_from_double(double value): my_decimal()
{
int unexpected_error __attribute__((unused))=
double2my_decimal(E_DEC_ERROR, value, this);
DBUG_ASSERT(!unexpected_error);
}
} MAX_PERIOD= SLAVE_MAX_HEARTBEAT_PERIOD/1000.0, THOUSAND= 1000;
Decimal_from_ll(longlong value): my_decimal()
{
int unexpected_error __attribute__((unused))=
int2my_decimal(E_DEC_ERROR, value, false, this);
DBUG_ASSERT(!unexpected_error);
}
} MAX_PERIOD= SLAVE_MAX_HEARTBEAT_PERIOD/1000, THOUSAND= 1000;

Comment on lines +2290 to +2291
decimal_mul(&rounded, &THOUSAND, &decimal_buffer) |
decimal2ulonglong(&decimal_buffer, &(Lex->mi.heartbeat_period));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
decimal_mul(&rounded, &THOUSAND, &decimal_buffer) |
decimal2ulonglong(&decimal_buffer, &(Lex->mi.heartbeat_period));
/*
(The ideal order would export to a `double` and *then* multiply,
but disappointingly, decimal2double() is implemented
by printing into a string and parsing that char array.)
*/
decimal_mul(&rounded, &THOUSAND, &decimal_buffer) |
decimal2ulonglong(&decimal_buffer, &(Lex->mi.heartbeat_period));

ParadoxV5 added a commit that referenced this pull request Nov 19, 2025
MDEV-35879 Slave_heartbeat_period is imprecise
* Increase maximum to `std::numeric_limits<uint32_t>::max() ÷ 1000`,
  i.e., `4294967.295` *exactly*
* Excludes its additional tests as they are exclusive to that issue fix.
  * But not the `0.00049` case, which was *changed*, not *added*.
* Some changes are refactors and so are exclusive to the `main` branch.
  * Delete tests in `rpl.rpl_heartbeat`
    that duplicates `rpl.rpl_heartbeat_basic`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MariaDB Corporation Replication Patches involved in replication

Development

Successfully merging this pull request may close these issues.

2 participants