Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replication: check hostname length #1013

Merged
merged 2 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion canal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ type Config struct {
// Set Dialer
Dialer client.Dialer

// Set Localhost
// Set the hostname that is used when registering as replica. This is similar to `report_host` in MySQL.
// This will be truncated if it is longer than 255 characters.
Localhost string

// EventCacheCount is the capacity of the BinlogStreamer internal event channel.
Expand Down
12 changes: 8 additions & 4 deletions replication/binlogsyncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,13 +573,17 @@ func (b *BinlogSyncer) writeBinlogDumpMariadbGTIDCommand(gset mysql.GTIDSet) err
return b.writeBinlogDumpCommand(mysql.Position{Name: "", Pos: 0})
}

// localHostname returns the hostname that register slave would register as.
// localHostname returns the hostname that register replica would register as.
// this gets truncated to 255 bytes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

because in the old version the length limit is 60, it's better to truncate based on MySQL version

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that's correct.

To me it looks like MySQL 9.2.0 sends a up to 255 bytes hostname to the source when registering (see register_slave_on_master() in mysql-server) even when the source it is replicating from is (much) older.

So the limitation was mostly that older version would not send a longer hostname, not that the protocol or server couldn't handle it.

func (b *BinlogSyncer) localHostname() string {
if len(b.cfg.Localhost) == 0 {
h, _ := os.Hostname()
h := b.cfg.Localhost
if len(h) == 0 {
h, _ = os.Hostname()
}
if len(h) <= 255 {
return h
}
return b.cfg.Localhost
return h[:255]
}

func (b *BinlogSyncer) writeRegisterSlaveCommand() error {
Expand Down
50 changes: 50 additions & 0 deletions replication/binlogsyncer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package replication

import (
"os"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestLocalHostname(t *testing.T) {
b := BinlogSyncer{
cfg: BinlogSyncerConfig{
Localhost: "foobar",
},
}

require.Equal(t, "foobar", b.localHostname())
}

func TestLocalHostname_long(t *testing.T) {
b := BinlogSyncer{
cfg: BinlogSyncerConfig{
Localhost: strings.Repeat("x", 255),
},
}

require.Equal(t, 255, len(b.localHostname()))
}

func TestLocalHostname_toolong(t *testing.T) {
b := BinlogSyncer{
cfg: BinlogSyncerConfig{
Localhost: strings.Repeat("x", 300),
},
}

require.Equal(t, 255, len(b.localHostname()))
}

func TestLocalHostname_os(t *testing.T) {
b := BinlogSyncer{
cfg: BinlogSyncerConfig{
Localhost: "",
},
}

h, _ := os.Hostname()
require.Equal(t, h, b.localHostname())
}
Loading