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

VReplication VPlayer: set foreign_key_checks on initialization #14013

Merged
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
46 changes: 32 additions & 14 deletions go/vt/vttablet/tabletmanager/vreplication/vplayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,19 @@ type vplayer struct {

throttlerAppName string

foreignKeyCheck bool
// See updateFKCheck for more details on how the two fields below are used.

// foreignKeyChecksEnabled is the current state of the foreign key checks for the current session.
// It reflects what we have set the @@session.foreign_key_checks session variable to.
foreignKeyChecksEnabled bool

// foreignKeyChecksStateInitialized is set to true once we have initialized the foreignKeyChecksEnabled.
// The initialization is done on the first row event that this vplayer sees.
foreignKeyChecksStateInitialized bool
}

// NoForeignKeyCheckFlagBitmask is the bitmask for the 2nd bit (least significant) of the flags in a binlog row event.
// This bit is set if foreign key checks are disabled.
const NoForeignKeyCheckFlagBitmask uint32 = 1 << 1

// newVPlayer creates a new vplayer. Parameters:
Expand Down Expand Up @@ -105,7 +115,6 @@ func newVPlayer(vr *vreplicator, settings binlogplayer.VRSettings, copyState map
tablePlans: make(map[string]*TablePlan),
phase: phase,
throttlerAppName: throttlerapp.VCopierName.ConcatenateString(vr.throttlerAppName()),
foreignKeyCheck: false,
}
}

Expand Down Expand Up @@ -138,23 +147,32 @@ func (vp *vplayer) play(ctx context.Context) error {
return vp.fetchAndApply(ctx)
}

// updateFKCheck will check if the fk checks value has changed from what it is currently set to and update it if it has.
// This is done to avoid setting the fk checks value for every row event. vplayer starts with fk checks off.
// updateFKCheck updates the @@session.foreign_key_checks variable based on the binlog row event flags.
// The function only does it if it has changed to avoid redundant updates, using the cached vplayer.foreignKeyChecksEnabled
// The foreign_key_checks value for a transaction is determined by the 2nd bit (least significant) of the flags:
// - If set (1), foreign key checks are disabled.
// - If unset (0), foreign key checks are enabled.
// updateFKCheck also updates the state for the first row event that this vplayer and hence the connection sees.
func (vp *vplayer) updateFKCheck(ctx context.Context, flags2 uint32) error {
// The 2nd bit (least significant) of the flags attribute of the binlog row event
// is set to 1 if foreign key checks are disabled.
enableFK := true
dbForeignKeyChecksEnabled := true
if flags2&NoForeignKeyCheckFlagBitmask == NoForeignKeyCheckFlagBitmask {
enableFK = false
dbForeignKeyChecksEnabled = false
}
if vp.foreignKeyCheck == enableFK {
// if not changed, return

if vp.foreignKeyChecksStateInitialized /* already set earlier */ &&
dbForeignKeyChecksEnabled == vp.foreignKeyChecksEnabled /* no change in the state, no need to update */ {
return nil
}
vp.foreignKeyCheck = enableFK
log.Infof("Setting foreign_key_checks to %v", enableFK)
_, err := vp.vr.dbClient.ExecuteWithRetry(ctx, "set @@session.foreign_key_checks="+strconv.FormatBool(enableFK))
return err
log.Infof("Setting this session's foreign_key_checks to %s", strconv.FormatBool(dbForeignKeyChecksEnabled))
if _, err := vp.vr.dbClient.ExecuteWithRetry(ctx, "set @@session.foreign_key_checks="+strconv.FormatBool(dbForeignKeyChecksEnabled)); err != nil {
return fmt.Errorf("failed to set session foreign_key_checks: %w", err)
}
vp.foreignKeyChecksEnabled = dbForeignKeyChecksEnabled
if !vp.foreignKeyChecksStateInitialized {
log.Infof("First foreign_key_checks update to: %s", strconv.FormatBool(dbForeignKeyChecksEnabled))
vp.foreignKeyChecksStateInitialized = true
}
return nil
}

// fetchAndApply performs the fetching and application of the binlogs.
Expand Down
Loading