-
Notifications
You must be signed in to change notification settings - Fork 936
Add basic support for group replication #1180
Changes from all commits
cf2b55e
d98af1b
bd4f4db
03264a5
30f5b1a
b1c57f4
dd2716a
62e554f
a44205d
87fba96
cf67e24
04b759f
51e6bc0
10e3ab2
cd5c79f
f63f7a6
105cdc6
bd6be2f
2af7934
03b088a
6d643ec
c31d71a
2d4817f
9d582de
80274ac
ea180cf
950e500
7fcf1c9
3188102
7053a44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -580,5 +580,41 @@ var generateSQLPatches = []string{ | |
ALTER TABLE /* sqlite3-skip */ | ||
database_instance | ||
MODIFY semi_sync_master_timeout BIGINT UNSIGNED NOT NULL DEFAULT 0 | ||
`, | ||
// Fields related to Replication Group the instance belongs to | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_name VARCHAR(64) CHARACTER SET ascii NOT NULL DEFAULT '' AFTER gtid_mode | ||
ejortegau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_is_single_primary_mode TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER replication_group_name | ||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_member_state VARCHAR(16) CHARACTER SET ascii NOT NULL DEFAULT '' AFTER replication_group_is_single_primary_mode | ||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_member_role VARCHAR(16) CHARACTER SET ascii NOT NULL DEFAULT '' AFTER replication_group_member_state | ||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_members text CHARACTER SET ascii NOT NULL AFTER replication_group_member_role | ||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_primary_host varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' AFTER replication_group_members | ||
`, | ||
` | ||
ALTER TABLE | ||
database_instance | ||
ADD COLUMN replication_group_primary_port smallint(5) unsigned NOT NULL DEFAULT 0 AFTER replication_group_primary_host | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
`, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -160,11 +160,19 @@ func GetReplicationAnalysis(clusterName string, hints *ReplicationAnalysisHints) | |
master_instance.last_checked <= master_instance.last_seen | ||
and master_instance.last_attempted_check <= master_instance.last_seen + interval ? second | ||
) = 1 AS is_last_check_valid, | ||
/* To be considered a master, traditional async replication must not be present/valid AND the host should either */ | ||
/* not be a replication group member OR be the primary of the replication group */ | ||
MIN(master_instance.last_check_partial_success) as last_check_partial_success, | ||
MIN( | ||
master_instance.master_host IN ('', '_') | ||
OR master_instance.master_port = 0 | ||
OR substr(master_instance.master_host, 1, 2) = '//' | ||
( | ||
master_instance.master_host IN ('', '_') | ||
OR master_instance.master_port = 0 | ||
OR substr(master_instance.master_host, 1, 2) = '//' | ||
) | ||
AND ( | ||
master_instance.replication_group_name = '' | ||
OR master_instance.replication_group_member_role = 'PRIMARY' | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
) AS is_master, | ||
MIN(master_instance.is_co_master) AS is_co_master, | ||
MIN( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,13 +129,32 @@ type Instance struct { | |
LastDiscoveryLatency time.Duration | ||
|
||
seed bool // Means we force this instance to be written to backend, even if it's invalid, empty or forgotten | ||
|
||
/* All things Group Replication below */ | ||
|
||
// Group replication global variables | ||
ReplicationGroupName string | ||
ReplicationGroupIsSinglePrimary bool | ||
|
||
// Replication group members information. See | ||
// https://dev.mysql.com/doc/refman/8.0/en/replication-group-members-table.html for details. | ||
ReplicationGroupMemberState string | ||
ReplicationGroupMemberRole string | ||
|
||
// List of all known members of the same group | ||
ReplicationGroupMembers InstanceKeyMap | ||
|
||
// Primary of the replication group | ||
ReplicationGroupPrimaryInstanceKey InstanceKey | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
|
||
// NewInstance creates a new, empty instance | ||
|
||
func NewInstance() *Instance { | ||
return &Instance{ | ||
Replicas: make(map[InstanceKey]bool), | ||
Problems: []string{}, | ||
Replicas: make(map[InstanceKey]bool), | ||
ReplicationGroupMembers: make(map[InstanceKey]bool), | ||
Problems: []string{}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
} | ||
|
||
|
@@ -228,6 +247,21 @@ func (this *Instance) IsNDB() bool { | |
return strings.Contains(this.Version, "-ndb-") | ||
} | ||
|
||
// IsReplicationGroup checks whether the host thinks it is part of a known replication group. Notice that this might | ||
// return True even if the group has decided to expel the member represented by this instance, as the instance might not | ||
// know that under certain circumstances | ||
func (this *Instance) IsReplicationGroupMember() bool { | ||
return this.ReplicationGroupName != "" | ||
} | ||
|
||
func (this *Instance) IsReplicationGroupPrimary() bool { | ||
return this.IsReplicationGroupMember() && this.ReplicationGroupPrimaryInstanceKey.Equals(&this.Key) | ||
} | ||
|
||
func (this *Instance) IsReplicationGroupSecondary() bool { | ||
return this.IsReplicationGroupMember() && !this.ReplicationGroupPrimaryInstanceKey.Equals(&this.Key) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
// IsBinlogServer checks whether this is any type of a binlog server (currently only maxscale) | ||
func (this *Instance) IsBinlogServer() bool { | ||
if this.isMaxScale() { | ||
|
@@ -293,9 +327,24 @@ func (this *Instance) IsReplica() bool { | |
return this.MasterKey.Hostname != "" && this.MasterKey.Hostname != "_" && this.MasterKey.Port != 0 && (this.ReadBinlogCoordinates.LogFile != "" || this.UsingGTID()) | ||
} | ||
|
||
// IsMaster makes simple heuristics to decide whether this instance is a master (not replicating from any other server) | ||
// IsMaster makes simple heuristics to decide whether this instance is a master (not replicating from any other server), | ||
// either via traditional async/semisync replication or group replication | ||
func (this *Instance) IsMaster() bool { | ||
return !this.IsReplica() | ||
// If traditional replication is configured, it is for sure not a master | ||
if this.IsReplica() { | ||
return false | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm replacing this code: func (this *Instance) IsMaster() bool {
// If traditional replication is configured, it is for sure not a master
if this.IsReplica() {
return false
} else {
// If traditional replication is not configured, and it is also not part of a replication group, this host is
// a master
if !this.IsReplicationGroupMember() {
return true
} else {
// If traditional replication is not configured, and this host is part of a group, it is only considered a
// master if it has the role of group Primary. Otherwise it is not a master.
if this.ReplicationGroupMemberRole == GroupReplicationMemberRolePrimary {
return true
} else {
return false
}
}
}
} with simplified nesting: func (this *Instance) IsMaster() bool {
// If traditional replication is configured, it is for sure not a master
if this.IsReplica() {
return false
}
// If traditional replication is not configured, and it is also not part of a replication group, this host is
// a master
if !this.IsReplicationGroupMember() {
return true
}
// If traditional replication is not configured, and this host is part of a group, it is only considered a
// master if it has the role of group Primary. Otherwise it is not a master.
if this.ReplicationGroupMemberRole == GroupReplicationMemberRolePrimary {
return true
}
return false
} |
||
// If traditional replication is not configured, and it is also not part of a replication group, this host is | ||
// a master | ||
if !this.IsReplicationGroupMember() { | ||
return true | ||
} | ||
// If traditional replication is not configured, and this host is part of a group, it is only considered a | ||
// master if it has the role of group Primary. Otherwise it is not a master. | ||
if this.ReplicationGroupMemberRole == GroupReplicationMemberRolePrimary { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// ReplicaRunning returns true when this instance's status is of a replicating replica. | ||
|
@@ -358,6 +407,11 @@ func (this *Instance) AddReplicaKey(replicaKey *InstanceKey) { | |
this.Replicas.AddKey(*replicaKey) | ||
} | ||
|
||
// AddGroupMemberKey adds a group member to the list of this instance's group members. | ||
func (this *Instance) AddGroupMemberKey(groupMemberKey *InstanceKey) { | ||
this.ReplicationGroupMembers.AddKey(*groupMemberKey) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
// GetNextBinaryLog returns the successive, if any, binary log file to the one given | ||
func (this *Instance) GetNextBinaryLog(binlogCoordinates BinlogCoordinates) (BinlogCoordinates, error) { | ||
if binlogCoordinates.LogFile == this.SelfBinlogCoordinates.LogFile { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍