Skip to content

Support MySQL replication named channels (phases 1-3)#78

Merged
renecannao merged 3 commits intomasterfrom
issue77-named-channels
Apr 8, 2026
Merged

Support MySQL replication named channels (phases 1-3)#78
renecannao merged 3 commits intomasterfrom
issue77-named-channels

Conversation

@renecannao
Copy link
Copy Markdown

@renecannao renecannao commented Apr 8, 2026

Summary

Implements phases 1-3 of #77: Support MySQL replication named channels (multi-source replication).

  • Phase 1 (Data Model): Add ChannelStatus struct for per-channel replication state, extend Instance with ReplicationChannels and ManagedChannelName fields, add database_instance_channels table migration.
  • Phase 2 (Discovery): Parse all SHOW REPLICA STATUS rows into ChannelStatus structs, select a canonical channel for backward-compatible Instance fields, persist and read channel data to/from the backend database.
  • Phase 3 (Channel-Aware Operations): Add FOR CHANNEL clause support to all replication SQL commands, add StopReplicationForChannel/StartReplicationForChannel/ChangeMasterToForChannel functions that target specific channels.

All changes are backward compatible: single-source replication (the common case) behaves identically to before. Group Replication internal channels (group_replication_applier, group_replication_recovery) are skipped when selecting the canonical channel.

Phases 4-6 (visualization, failover, testing) will follow in subsequent PRs.

Closes #77

Test plan

  • go build succeeds
  • go test ./go/inst/... passes
  • go test ./go/... passes (all packages)
  • Manual testing with single-source MySQL replication (no behavioral change)
  • Manual testing with multi-source MySQL 5.7+/8.0 replication
  • Verify database_instance_channels table is created on schema migration

Summary by CodeRabbit

  • New Features
    • Support for multi-source replication via named channels
    • Per-channel replication status persisted and surfaced for monitoring
    • Channel-specific operations for managing replication: start, stop, change-master
    • Channel-aware SQL generation to target specific replication channels

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ced3b1bf-6590-42f6-a9af-df95580b1622

📥 Commits

Reviewing files that changed from the base of the PR and between e5e833c and 8f0d92c.

📒 Files selected for processing (5)
  • go/db/generate_patches.go
  • go/inst/instance.go
  • go/inst/instance_dao.go
  • go/inst/instance_topology_dao.go
  • go/inst/query_string_provider.go

📝 Walkthrough

Walkthrough

Adds multi-source replication support Phase 1–3: new DB table for per-channel metadata, ChannelStatus and Instance fields for channels, discovery parsing of all replication-channel rows, persistence of channel rows, and channel-aware replication control APIs with backward-compatible wrappers.

Changes

Cohort / File(s) Summary
Schema
go/db/generate_patches.go
Add CREATE TABLE IF NOT EXISTS database_instance_channels DDL to store per-(hostname,port,channel_name) replication channel metadata.
Data model
go/inst/instance.go
Introduce ChannelStatus type, IsGRInternalChannel() method, and extend Instance with ReplicationChannels []ChannelStatus and ManagedChannelName string.
Discovery & persistence
go/inst/instance_dao.go
Parse all SHOW SLAVE STATUS rows into per-channel ChannelStatus entries, select a canonical channel, set instance replication fields from that channel, and add writeInstanceChannels / readInstanceChannels to persist/load channels to/from database_instance_channels.
Topology & control flow
go/inst/instance_topology_dao.go
Add channel-aware APIs StopReplicationForChannel, StartReplicationForChannel, ChangeMasterToForChannel; legacy functions delegate to channel variants; use effective channel (managed when multi-source); include channel in logs; append channel clause to CHANGE MASTER TO statements.
Query string provider
go/inst/query_string_provider.go
Add forChannelClause(channelName) helper and eight QueryStringProvider methods producing channel-specific SQL (e.g., StopReplicaForChannel, StartReplicaForChannel, StopReplicaIOThreadForChannel, etc.).
Manifest
go.mod
Module manifest updated (touched in this diff).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant DiscoveryEngine as Discovery Engine
    participant Instance
    participant Database as DB

    Client->>DiscoveryEngine: Discover instance
    DiscoveryEngine->>Instance: Execute SHOW SLAVE STATUS
    Instance-->>DiscoveryEngine: Multi-row result (channels)
    DiscoveryEngine->>DiscoveryEngine: Parse rows → ReplicationChannels[]
    DiscoveryEngine->>DiscoveryEngine: selectCanonicalChannelIndex()
    DiscoveryEngine->>Instance: Set ReplicationChannels, ManagedChannelName
    DiscoveryEngine->>Database: writeInstanceChannels()
    Database-->>DiscoveryEngine: persisted rows

    Note over Client: Later: channel-aware operations
    Client->>DiscoveryEngine: Stop/Start/ChangeMaster (may include channel)
    DiscoveryEngine->>DiscoveryEngine: determine effectiveChannel
    DiscoveryEngine->>Instance: Execute channel-specific SQL (e.g., STOP REPLICA FOR CHANNEL)
    Instance-->>DiscoveryEngine: Result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibbled logs and found each thread,

Channels sprouted where there was one instead,
I map them, store them, pick the one to steer,
Hop-keeping replication now holds each ear,
A carrot for every channel, bright and clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding MySQL named channels support across phases 1-3, matching the PR's primary objectives.
Linked Issues check ✅ Passed All phase 1-3 objectives from issue #77 are met: ChannelStatus struct and database table added [Phase 1], discovery and persistence of channels implemented [Phase 2], and channel-aware replication operations provided [Phase 3].
Out of Scope Changes check ✅ Passed All changes are directly aligned with phases 1-3 of issue #77; no unrelated modifications or scope creep detected beyond named channel support infrastructure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue77-named-channels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Phase 1 of issue #77: Support MySQL replication named channels.

- Add ChannelStatus struct to represent per-channel replication state
  (IO/SQL thread status, coordinates, lag, errors, GTID usage)
- Add ReplicationChannels and ManagedChannelName fields to Instance struct
- Add database_instance_channels table migration for persisting channel data
Phase 2 of issue #77: Parse all SHOW REPLICA STATUS rows into
ChannelStatus structs, select a canonical channel for backward
compatibility, and persist/read channel data to/from the backend DB.

- Parse Channel_Name column from each SHOW SLAVE STATUS row
- Build ChannelStatus per row and store in instance.ReplicationChannels
- selectCanonicalChannelIndex picks default/non-GR channel for Instance fields
- writeInstanceChannels persists channel data after discovery
- readInstanceChannels loads channels when reading from backend
- Single-source replication behavior is unchanged
Phase 3 of issue #77: Make stop/start replication and change master
operations channel-aware for named replication channels.

- Add FOR CHANNEL clause helpers to QueryStringProvider for all
  replication commands (stop, start, reset, IO/SQL thread control)
- Add StopReplicationForChannel and StartReplicationForChannel that
  target a specific channel or fall back to the managed channel
- Add ChangeMasterToForChannel with FOR CHANNEL clause on all
  CHANGE MASTER TO variants (GTID, binlog pos, MariaDB, Oracle)
- Original StopReplication/StartReplication/ChangeMasterTo delegate
  to the new functions with empty channel for backward compatibility
@renecannao renecannao force-pushed the issue77-named-channels branch from e5e833c to 8f0d92c Compare April 8, 2026 03:41
@renecannao renecannao merged commit 56293ce into master Apr 8, 2026
3 of 5 checks passed
Copy link
Copy Markdown

@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 implements multi-source replication support by introducing a new database table for channel status, updating the Instance model, and adding channel-aware replication control functions. The review feedback highlights a potential SQL syntax error due to unescaped channel names, an N+1 query performance issue when loading instances, and the need for consistent logic and refactoring when determining the effective replication channel across different operations.

I am having trouble creating individual review comments. Click here to see my feedback.

go/inst/query_string_provider.go (402)

high

The channel name is concatenated directly into the SQL string using single quotes. If a channel name contains a single quote (which is technically possible in MySQL), this will result in a SQL syntax error. It is safer to escape the channel name using strings.ReplaceAll(channelName, "'", "''") (note: this requires importing the strings package).

go/inst/instance_topology_dao.go (1008)

high

Unlike StopReplicationForChannel and StartReplicationForChannel, this function does not automatically target the ManagedChannelName when channelName is empty on a multi-source instance. This inconsistency may cause ChangeMasterTo (which calls this with an empty channel) to target the wrong channel (the default one) instead of the one orchestrator is supposed to manage.

	// For multi-source instances with no explicit channel, use the managed channel
	effectiveChannel := channelName
	if effectiveChannel == "" && len(instance.ReplicationChannels) > 1 {
		effectiveChannel = instance.ManagedChannelName
	}
	// Build the FOR CHANNEL suffix for multi-source replication
	channelClause := forChannelClause(effectiveChannel)

go/inst/instance_dao.go (1560)

medium

Executing a separate query for replication channels for every instance row read will lead to an N+1 query problem, significantly impacting performance when reading large clusters or many instances (e.g., for the dashboard or API). Consider fetching all channels for the set of instances in a single query and distributing them to the instances in bulk.

go/inst/instance_topology_dao.go (418-421)

medium

This logic for determining the effective channel name is duplicated in StartReplicationForChannel and should also be applied to ChangeMasterToForChannel. Consider refactoring this into a helper method on the Instance struct (e.g., func (this *Instance) GetEffectiveChannel(channelName string) string).

go/inst/instance_topology_dao.go (1088)

medium

Update the log message to use the effective channel name determined at the beginning of the function.

	log.Infof("ChangeMasterTo: Changed master on %+v to: %+v, %+v. GTID: %+v, Channel: %q", *instanceKey, masterKey, masterBinlogCoordinates, changedViaGTID, effectiveChannel)

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.

Support MySQL replication named channels (multi-source replication)

1 participant