Skip to content

Commit be84db2

Browse files
committed
refactor: decide replication syntax by flavor capabilities
The replication syntax (SHOW REPLICA STATUS, CHANGE REPLICATION SOURCE, SHOW BINARY LOG STATUS, RESET BINARY LOGS AND GTIDS, semisync source plugins, 8.4 group replication options) was chosen with the flavor-blind GreaterOrEqualVersion, which guesses MariaDB from the major version. That guess broke with MySQL 26.x calendar versions. Add these features to the MySQL-family capabilities (MySQL, Percona Server, PXC, NDB, VillageSQL) and use HasCapability(flavor, ...) at every call site; MariaDB has none of them, at any version. Plain version comparisons (registry newest, client compatibility, self-update, ts manifests) use GreaterOrEqualVersionList. The registry lookup keeps resolving MariaDB through the MariaDB Foundation API, as before (the old check made registry entries never match for MariaDB majors). GreaterOrEqualVersion is kept, deprecated, for library users.
1 parent 07e3ff0 commit be84db2

16 files changed

Lines changed: 197 additions & 46 deletions

‎CHANGELOG.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
Flavor-blind version checks treated every major from 10 as MariaDB, so
1818
26.x got pre-8.0 behaviour: `downloads get-by-version 26.7` failed, and the
1919
generated `test_replication` checked the old replication status columns.
20-
Majors from 10 to 25 are still treated as MariaDB.
20+
The replication syntax (SHOW REPLICA STATUS, CHANGE REPLICATION SOURCE,
21+
SHOW BINARY LOG STATUS, RESET BINARY LOGS AND GTIDS, semisync source
22+
plugins, 8.4 group replication options) is now decided by flavor
23+
capabilities: the MySQL family (MySQL, Percona Server, PXC, NDB,
24+
VillageSQL) gets it from the respective version, MariaDB never does.
25+
`common.GreaterOrEqualVersion` is no longer used by dbdeployer.
2126
* Group replication sandboxes set `group_replication_communication_stack=XCOM`
2227
(8.4+). Each node uses a dedicated group communication port, which the
2328
MYSQL stack, the default from MySQL 26.x, does not support: nodes stayed

‎cmd/replication.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ func replicationSandbox(cmd *cobra.Command, args []string) {
288288
if isMinimumSync {
289289
// MySQL 9.2+ removed semisync_master.so/semisync_slave.so;
290290
// use semisync_source.so/semisync_replica.so instead.
291-
useSourcePlugin, _ := common.GreaterOrEqualVersion(sd.Version, globals.MinimumSemisyncSourcePluginVersion)
291+
useSourcePlugin, _ := common.HasCapability(sd.Flavor, common.SemisyncSourcePlugin, sd.Version)
292292
if useSourcePlugin {
293293
sd.SemiSyncOptions = sandbox.SingleTemplates[globals.TmplSemisyncSourceOptions].Contents
294294
} else {

‎cmd/single.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ func fillSandboxDefinition(cmd *cobra.Command, args []string, usingImport bool)
402402
sd.GtidOptions = sandbox.SingleTemplates[templateName].Contents
403403
// Use 8.4+ crash-safe options template (no deprecated master-info-repository)
404404
crashSafeTmpl := globals.TmplReplCrashSafeOptions
405-
isMySQL84, _ := common.GreaterOrEqualVersion(sd.Version, globals.MinimumResetBinaryLogsVersion)
405+
isMySQL84, _ := common.HasCapability(sd.Flavor, common.ResetBinaryLogs, sd.Version)
406406
if isMySQL84 {
407407
crashSafeTmpl = globals.TmplReplCrashSafeOptions84
408408
}
@@ -426,7 +426,7 @@ func fillSandboxDefinition(cmd *cobra.Command, args []string, usingImport bool)
426426
if isMinimumCrashSafe {
427427
// Use 8.4+ crash-safe options template (no deprecated master-info-repository)
428428
crashSafeTmpl := globals.TmplReplCrashSafeOptions
429-
isMySQL84, _ := common.GreaterOrEqualVersion(sd.Version, globals.MinimumResetBinaryLogsVersion)
429+
isMySQL84, _ := common.HasCapability(sd.Flavor, common.ResetBinaryLogs, sd.Version)
430430
if isMySQL84 {
431431
crashSafeTmpl = globals.TmplReplCrashSafeOptions84
432432
}

‎cmd/update.go‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ func updateDbDeployer(cmd *cobra.Command, args []string) {
9292
"Download canceled",
9393
)
9494
}
95-
foundOldVersion, err := common.GreaterOrEqualVersion(common.VersionDef, tagList)
95+
currentList, err := common.VersionToList(common.VersionDef)
96+
common.ErrCheckExitf(err, 1, "error comparing remote tag %s to dbdeployer version %s", tag, common.VersionDef)
97+
foundOldVersion, err := common.GreaterOrEqualVersionList(currentList, tagList)
9698
common.ErrCheckExitf(err, 1, "error comparing remote tag %s to dbdeployer version %s", tag, common.VersionDef)
9799
if foundOldVersion && !forceOldVersion {
98100
common.Exit(0,

‎common/capabilities.go‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ const (
8686
EmbedMySQLShell = "embed-mysql-shell"
8787
CloneServer = "clone-server"
8888
CircularReplication = "circular-replication"
89+
ShowReplicaStatus = "show-replica-status"
90+
ChangeReplicationSource = "change-replication-source"
91+
ShowBinaryLogStatus = "show-binary-log-status"
92+
NoWriteSetExtraction = "no-write-set-extraction"
93+
ResetBinaryLogs = "reset-binary-logs"
94+
SemisyncSourcePlugin = "semisync-source-plugin"
8995
)
9096

9197
var MySQLCapabilities = Capabilities{
@@ -182,6 +188,33 @@ var MySQLCapabilities = Capabilities{
182188
Description: "Allow circular replication",
183189
Since: globals.MinimumMySQLAutoIncrementIncrement,
184190
},
191+
// The replication syntax features below exist only in the MySQL family
192+
// (MySQL, Percona Server, PXC, NDB, VillageSQL). MariaDB keeps the
193+
// historical syntax (CHANGE MASTER TO, SHOW SLAVE STATUS, ...).
194+
ShowReplicaStatus: {
195+
Description: "SHOW REPLICA STATUS, START/STOP/RESET REPLICA",
196+
Since: globals.MinimumShowReplicaStatusVersion,
197+
},
198+
ChangeReplicationSource: {
199+
Description: "CHANGE REPLICATION SOURCE TO",
200+
Since: globals.MinimumChangeReplicationSourceVersion,
201+
},
202+
ShowBinaryLogStatus: {
203+
Description: "SHOW BINARY LOG STATUS",
204+
Since: globals.MinimumShowBinaryLogStatusVersion,
205+
},
206+
NoWriteSetExtraction: {
207+
Description: "transaction_write_set_extraction removed",
208+
Since: globals.MinimumNoWriteSetExtractionVersion,
209+
},
210+
ResetBinaryLogs: {
211+
Description: "RESET BINARY LOGS AND GTIDS, 8.4 replication options",
212+
Since: globals.MinimumResetBinaryLogsVersion,
213+
},
214+
SemisyncSourcePlugin: {
215+
Description: "semisync_source / semisync_replica plugins",
216+
Since: globals.MinimumSemisyncSourcePluginVersion,
217+
},
185218
},
186219
}
187220

@@ -332,6 +365,12 @@ var NdbCapabilities = Capabilities{
332365
Description: "MySQL NDB Cluster",
333366
Since: globals.MinimumNdbClusterVersion,
334367
},
368+
ShowReplicaStatus: MySQLCapabilities.Features[ShowReplicaStatus],
369+
ChangeReplicationSource: MySQLCapabilities.Features[ChangeReplicationSource],
370+
ShowBinaryLogStatus: MySQLCapabilities.Features[ShowBinaryLogStatus],
371+
NoWriteSetExtraction: MySQLCapabilities.Features[NoWriteSetExtraction],
372+
ResetBinaryLogs: MySQLCapabilities.Features[ResetBinaryLogs],
373+
SemisyncSourcePlugin: MySQLCapabilities.Features[SemisyncSourcePlugin],
335374
},
336375
}
337376

‎common/capabilities_test.go‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,60 @@ func TestCopyCapabilities(t *testing.T) {
130130
}
131131
testHasCapability(capabilitiesList, t)
132132
}
133+
134+
// The replication syntax is decided by flavor, not by version number: MySQL
135+
// 26.x (calendar versions) uses the new syntax, while MariaDB keeps the
136+
// historical one at any version.
137+
func TestReplicationSyntaxCapabilities(t *testing.T) {
138+
features := []string{
139+
ShowReplicaStatus,
140+
ChangeReplicationSource,
141+
ShowBinaryLogStatus,
142+
NoWriteSetExtraction,
143+
ResetBinaryLogs,
144+
SemisyncSourcePlugin,
145+
}
146+
mysqlFamily := []string{MySQLFlavor, PerconaServerFlavor, PxcFlavor, NdbFlavor, VillageSQLFlavor}
147+
for _, flavor := range mysqlFamily {
148+
for _, feature := range features {
149+
for _, version := range []string{"9.7.2", "26.7.0", "27.1.0"} {
150+
has, err := HasCapability(flavor, feature, version)
151+
if err != nil || !has {
152+
t.Errorf("%s %s should have %s (err: %v)", flavor, version, feature, err)
153+
}
154+
}
155+
has, _ := HasCapability(flavor, feature, "5.7.44")
156+
if has {
157+
t.Errorf("%s 5.7.44 should not have %s", flavor, feature)
158+
}
159+
}
160+
}
161+
for _, feature := range features {
162+
for _, version := range []string{"10.11.9", "11.4.13", "12.3.3", "13.0.2", "26.7.0"} {
163+
has, _ := HasCapability(MariaDbFlavor, feature, version)
164+
if has {
165+
t.Errorf("mariadb %s should not have %s", version, feature)
166+
}
167+
}
168+
}
169+
170+
thresholds := []struct {
171+
feature string
172+
below string
173+
since string
174+
}{
175+
{ShowReplicaStatus, "8.0.21", "8.0.22"},
176+
{ChangeReplicationSource, "8.0.22", "8.0.23"},
177+
{ShowBinaryLogStatus, "8.1.0", "8.2.0"},
178+
{NoWriteSetExtraction, "8.2.0", "8.3.0"},
179+
{ResetBinaryLogs, "8.3.0", "8.4.0"},
180+
{SemisyncSourcePlugin, "9.1.0", "9.2.0"},
181+
}
182+
for _, th := range thresholds {
183+
before, _ := HasCapability(MySQLFlavor, th.feature, th.below)
184+
after, _ := HasCapability(MySQLFlavor, th.feature, th.since)
185+
if before || !after {
186+
t.Errorf("%s: expected false at %s and true at %s, got %v and %v", th.feature, th.below, th.since, before, after)
187+
}
188+
}
189+
}

‎common/checks.go‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,11 @@ func GetCompatibleClientVersion(basedir, serverVersion string) (string, error) {
172172
if v == serverVersion {
173173
return v, nil
174174
}
175-
isCompatible, err := GreaterOrEqualVersion(v, serverVersionList)
175+
clientVersionList, err := VersionToList(v)
176+
if err != nil {
177+
return globals.EmptyString, err
178+
}
179+
isCompatible, err := GreaterOrEqualVersionList(clientVersionList, serverVersionList)
176180
if err != nil {
177181
return globals.EmptyString, err
178182
}
@@ -653,8 +657,9 @@ func VersionToPort(version string) (int, error) {
653657
// So far (2018-02-19) this comparison holds, because MariaDB behaves like 5.5+ for
654658
// the purposes of sandbox deployment
655659
//
656-
// DEPRECATED as of 1.18.0
657-
// Use GreaterOrEqualVersionList and flavors instead
660+
// Deprecated: since 1.18.0. dbdeployer no longer uses it: use
661+
// HasCapability(flavor, feature, version) for features, and
662+
// GreaterOrEqualVersionList for plain version comparisons.
658663
func GreaterOrEqualVersion(version string, comparedTo []int) (bool, error) {
659664
if len(comparedTo) != 3 {
660665
return false, errors.Wrapf(fmt.Errorf("invalid slice size: %v", comparedTo), "GreaterOrEqualVersion:")

‎downloads/remote_registry.go‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,13 @@ func FindOrGuessTarballByVersionFlavorOS(version, flavor, OS, arch string, minim
238238
}
239239
var tbd []TarballDescription
240240
newestVersionList := []int{0, 0, 0}
241+
// MariaDB tarballs are resolved through the MariaDB Foundation API
242+
// (below), which knows the newest releases: registry entries are not
243+
// used for them.
241244
for _, tb := range DefaultTarballRegistry.Tarballs {
245+
if flavor == common.MariaDbFlavor {
246+
break
247+
}
242248
archMatch := true
243249
if tb.Arch != "" {
244250
archMatch = strings.ToLower(tb.Arch) == arch
@@ -255,10 +261,10 @@ func FindOrGuessTarballByVersionFlavorOS(version, flavor, OS, arch string, minim
255261
}
256262
}
257263
tbd = append(tbd, tb)
258-
greatest, err := common.GreaterOrEqualVersion(tb.Version, newestVersionList)
259-
if err == nil && greatest {
260-
versionList, err := common.VersionToList(tb.Version)
261-
if err == nil {
264+
versionList, err := common.VersionToList(tb.Version)
265+
if err == nil {
266+
greatest, err := common.GreaterOrEqualVersionList(versionList, newestVersionList)
267+
if err == nil && greatest {
262268
newestVersionList = versionList
263269
}
264270
}
@@ -293,7 +299,8 @@ func FindOrGuessTarballByVersionFlavorOS(version, flavor, OS, arch string, minim
293299
newest = true
294300
newestEntry := tbd[0]
295301
for _, tb := range tbd {
296-
isGreater, _ := common.GreaterOrEqualVersion(tb.Version, newestVersionList)
302+
versionList, _ := common.VersionToList(tb.Version)
303+
isGreater, _ := common.GreaterOrEqualVersionList(versionList, newestVersionList)
297304
if isGreater || tb.Version == fmt.Sprintf("%d.%d.%d", newestVersionList[0], newestVersionList[1], newestVersionList[2]) {
298305
newestEntry = tb
299306
}

‎sandbox/group_replication.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas
238238
"StopNodeList": stopNodeList,
239239
"Nodes": []common.StringMap{},
240240
}
241-
replCmds := replicationCommands(sandboxDef.Version)
241+
replCmds := replicationCommands(sandboxDef.Flavor, sandboxDef.Version)
242242
data["ChangeMasterTo"] = replCmds["ChangeMasterTo"]
243243
data["MasterUserParam"] = replCmds["MasterUserParam"]
244244
data["MasterPasswordParam"] = replCmds["MasterPasswordParam"]
@@ -290,7 +290,7 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas
290290

291291
// Select version-appropriate templates for group replication init
292292
initNodesTmpl := globals.TmplInitNodes
293-
isMySQL84, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion)
293+
isMySQL84 := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ResetBinaryLogs)
294294
if isMySQL84 {
295295
initNodesTmpl = globals.TmplInitNodes84
296296
}
@@ -343,10 +343,10 @@ func CreateGroupReplication(sandboxDef SandboxDef, origin string, nodes int, mas
343343
basePortText := fmt.Sprintf("%08d", basePort)
344344

345345
// Version-aware options for group replication
346-
useReplicaUpdates, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumShowReplicaStatusVersion)
347-
useNoWriteSetExtraction, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumNoWriteSetExtractionVersion)
346+
useReplicaUpdates := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ShowReplicaStatus)
347+
useNoWriteSetExtraction := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.NoWriteSetExtraction)
348348
// Use 8.4+ group replication options template when applicable
349-
useMySQL84GroupOptions, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion)
349+
useMySQL84GroupOptions := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ResetBinaryLogs)
350350

351351
replicationData := common.StringMap{
352352
"BasePort": basePortText,

‎sandbox/innodb_cluster.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ func CreateInnoDBCluster(sandboxDef SandboxDef, origin string, nodes int, master
277277
stopNodeList += fmt.Sprintf(" %d", i)
278278
}
279279

280-
replCmds := replicationCommands(sandboxDef.Version)
280+
replCmds := replicationCommands(sandboxDef.Flavor, sandboxDef.Version)
281281

282282
// Build the connection string for GR seeds
283283
connectionString := ""
@@ -357,7 +357,7 @@ func CreateInnoDBCluster(sandboxDef SandboxDef, origin string, nodes int, master
357357

358358
// Version-aware group replication init template
359359
initNodesTmpl := globals.TmplInitNodes
360-
isMySQL84, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion)
360+
isMySQL84 := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ResetBinaryLogs)
361361
if isMySQL84 {
362362
initNodesTmpl = globals.TmplInitNodes84
363363
}
@@ -417,9 +417,9 @@ func CreateInnoDBCluster(sandboxDef SandboxDef, origin string, nodes int, master
417417
basePortText := fmt.Sprintf("%08d", basePort)
418418

419419
// Version-aware options for group replication
420-
useReplicaUpdates, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumShowReplicaStatusVersion)
421-
useNoWriteSetExtraction, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumNoWriteSetExtractionVersion)
422-
useMySQL84GroupOptions, _ := common.GreaterOrEqualVersion(sandboxDef.Version, globals.MinimumResetBinaryLogsVersion)
420+
useReplicaUpdates := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ShowReplicaStatus)
421+
useNoWriteSetExtraction := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.NoWriteSetExtraction)
422+
useMySQL84GroupOptions := hasFeature(sandboxDef.Flavor, sandboxDef.Version, common.ResetBinaryLogs)
423423

424424
replicationData := common.StringMap{
425425
"BasePort": basePortText,

0 commit comments

Comments
 (0)