Skip to content

Commit 15076ab

Browse files
replicators: Report server UUID when registering as a replica
MySQL 5.7 and some earlier versions of MySQL 8.0 have a bug where it will report a malformed packet when executing SHOW SLAVE HOSTS or SHOW REPLICAS. The issue is fixed in MySQL 8.0.28. In summary, the affected versions will attempt to report the server UUID, if this is not set when registering as a replica via SET @slave_uuid=<uuid> the command will fail. The fix is to add a server UUID parameter and use it or generate a random UUIDv4 when registering as a replica. Closes: REA-6238 Fixes: #1575 Release-Note-Core: Added the option `--replication-server-uuid` to set a server UUID in MySQL. This UUID will be reported in `SHOW REPLICAS`. Change-Id: I75df8080ab25691600b207b999ddb1f4062cd07c Reviewed-on: https://gerrit.readyset.name/c/readyset/+/11105 Reviewed-by: Michael Zink <michael.z@readyset.io> Tested-by: Buildkite CI
1 parent e277a2c commit 15076ab

File tree

5 files changed

+36
-2
lines changed

5 files changed

+36
-2
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

database-utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ deadpool-postgres = { workspace = true }
2525
num_cpus = { workspace = true }
2626
icu = { workspace = true }
2727
yore = { workspace = true }
28+
uuid = { workspace = true, features = ["v4", "serde"] }
2829

2930
[lints]
3031
workspace = true

database-utils/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use error::DatabaseTypeParseError;
1313
use mysql_async::OptsBuilder;
1414
use pem::Pem;
1515
use serde::{Deserialize, Serialize};
16+
use uuid::Uuid;
1617

1718
use readyset_errors::{ReadySetError, ReadySetResult};
1819
use readyset_sql::{Dialect, ast::SqlIdentifier};
@@ -97,6 +98,12 @@ pub struct UpstreamConfig {
9798
#[serde(default)]
9899
pub replication_server_id: Option<ReplicationServerId>,
99100

101+
/// UUID to report when registering as a replica with the upstream database (MySQL only).
102+
/// If not set, a random UUID will be reported.
103+
#[arg(long, env = "REPLICATION_SERVER_UUID", value_parser = parse_repl_uuid)]
104+
#[serde(default)]
105+
pub replication_server_uuid: Option<Uuid>,
106+
100107
/// Hostname to report when registering as a replica with the upstream database (MySQL only).
101108
/// If not set, no hostname will be reported.
102109
#[arg(long = "report-host", env = "REPORT_HOST")]
@@ -278,6 +285,10 @@ impl UpstreamConfig {
278285
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
279286
pub struct ReplicationServerId(pub String);
280287

288+
fn parse_repl_uuid(s: &str) -> Result<Uuid, String> {
289+
Uuid::parse_str(s).map_err(|e| e.to_string())
290+
}
291+
281292
impl Display for ReplicationServerId {
282293
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283294
f.write_str(&self.0[..])
@@ -341,6 +352,7 @@ impl Default for UpstreamConfig {
341352
disable_setup_ddl_replication: false,
342353
disable_create_publication: false,
343354
replication_server_id: Default::default(),
355+
replication_server_uuid: Default::default(),
344356
replica_report_host: Default::default(),
345357
replica_report_port: Default::default(),
346358
replica_report_user: Default::default(),

replicators/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ readyset-tracing = { path = "../readyset-tracing" }
5656
readyset-util = { path = "../readyset-util" }
5757
readyset-decimal = { path = "../readyset-decimal" }
5858
replication-offset = { path = "../replication-offset" }
59+
uuid = { workspace = true, features = ["v4", "serde"] }
5960

6061
[dev-dependencies]
6162
assert_matches = { workspace = true }

replicators/src/mysql_connector/connector.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use readyset_sql::ast::{
4242
};
4343
use replication_offset::mysql::MySqlPosition;
4444
use replication_offset::ReplicationOffset;
45+
use uuid::Uuid;
4546

4647
use crate::mysql_connector::utils::{mysql_pad_binary_column, mysql_pad_char_column};
4748
use crate::noria_adapter::{Connector, ReplicationAction};
@@ -132,6 +133,9 @@ pub(crate) struct MySqlBinlogConnector {
132133
/// The binlog "slave" must be assigned a unique `server_id` in the replica topology
133134
/// if one is not assigned we will use (u32::MAX - 55)
134135
server_id: Option<u32>,
136+
/// The binlog "slave" must be assigned a unique `server_uuid` in the replica topology
137+
/// if one is not assigned we will use a random UUID
138+
server_uuid: Option<Uuid>,
135139
/// If we just want to continue reading the binlog from a previous point
136140
next_position: MySqlPosition,
137141
/// The GTID of the current transaction. Table modification events will have
@@ -159,6 +163,12 @@ impl MySqlBinlogConnector {
159163
self.server_id.unwrap_or(DEFAULT_SERVER_ID)
160164
}
161165

166+
/// The binlog replica must be assigned a unique `server_uuid` in the replica topology
167+
/// if one is not assigned we will use a random UUID
168+
fn server_uuid(&self) -> Uuid {
169+
self.server_uuid.unwrap_or_else(Uuid::new_v4)
170+
}
171+
162172
async fn set_parameters(&mut self) -> mysql::Result<()> {
163173
// Enabling source to replica heartbeat packets requires manipulation of a knob that is
164174
// totally undocumented. Yes, this really is a user variable, not a session variable.
@@ -186,10 +196,16 @@ impl MySqlBinlogConnector {
186196
Ok(version) => {
187197
if version >= 80400 {
188198
// MySQL 8.4.0 and above
189-
"SET @source_binlog_checksum='CRC32'"
199+
format!(
200+
"SET @source_binlog_checksum='CRC32', @replica_uuid='{}'",
201+
self.server_uuid()
202+
)
190203
} else {
191204
// MySQL 8.3.0 and below
192-
"SET @master_binlog_checksum='CRC32'"
205+
format!(
206+
"SET @master_binlog_checksum='CRC32', @slave_uuid='{}'",
207+
self.server_uuid()
208+
)
193209
}
194210
}
195211
Err(err) => {
@@ -289,6 +305,7 @@ impl MySqlBinlogConnector {
289305
connection: mysql::Conn::new(mysql_opts).await?,
290306
reader: binlog::EventStreamReader::new(binlog::consts::BinlogVersion::Version4),
291307
server_id,
308+
server_uuid: config.replication_server_uuid,
292309
next_position,
293310
current_gtid: None,
294311
enable_statement_logging,

0 commit comments

Comments
 (0)