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

restore: Run PITR through mysqlctl #13123

Merged

Conversation

dbussink
Copy link
Contributor

@dbussink dbussink commented May 22, 2023

When we run a restore remotely on the vttablet, we need to run the PITR logic through mysqlctl to ensure we run it with the correct MySQL binaries.

It adds additional safety checks for using the Mysqld type because it's reused between both the local MySQL interaction and mysqlctl but also as a remote interface used from vttablet.

This safety check means that we should never run certain things when running remotely inside vttablet, which is identified by the socketFile being set or not. When it is set, we now panic on certain actions we know are not going to work.

By adding this panic we can ensure we catch uses like the restore usage earlier since it would break if we do anything unsupported.

Related Issue(s)

Fixes #13124

Checklist

  • "Backport to:" labels have been added if this change should be back-ported
  • Tests were added or are not required
  • Did the new or modified tests pass consistently locally and on the CI
  • Documentation was added or is not required

@vitess-bot vitess-bot bot added the NeedsDescriptionUpdate The description is not clear or comprehensive enough, and needs work label May 22, 2023
@vitess-bot
Copy link
Contributor

vitess-bot bot commented May 22, 2023

Review Checklist

Hello reviewers! 👋 Please follow this checklist when reviewing this Pull Request.

General

  • Ensure that the Pull Request has a descriptive title.
  • If this is a change that users need to know about, please apply the release notes (needs details) label so that merging is blocked unless the summary release notes document is included.
  • If a test is added or modified, there should be a documentation on top of the test to explain what the expected behavior is what the test does.

If a new flag is being introduced:

  • Is it really necessary to add this flag?
  • Flag names should be clear and intuitive (as far as possible)
  • Help text should be descriptive.
  • Flag names should use dashes (-) as word separators rather than underscores (_).

If a workflow is added or modified:

  • Each item in Jobs should be named in order to mark it as required.
  • If the workflow should be required, the maintainer team should be notified.

Bug fixes

  • There should be at least one unit or end-to-end test.
  • The Pull Request description should include a link to an issue that describes the bug.

Non-trivial changes

  • There should be some code comments as to why things are implemented the way they are.

New/Existing features

  • Should be documented, either by modifying the existing documentation or creating new documentation.
  • New features should have a link to a feature request issue or an RFC that documents the use cases, corner cases and test cases.

Backward compatibility

  • Protobuf changes should be wire-compatible.
  • Changes to _vt tables and RPCs need to be backward compatible.
  • vtctl command output order should be stable and awk-able.
  • RPC changes should be compatible with vitess-operator
  • If a flag is removed, then it should also be removed from VTop, if used there.

@vitess-bot vitess-bot bot added NeedsIssue A linked issue is missing for this Pull Request NeedsWebsiteDocsUpdate What it says labels May 22, 2023
@github-actions github-actions bot added this to the v17.0.0 milestone May 22, 2023
@dbussink dbussink force-pushed the dbussink/remote-binlog-restore branch 2 times, most recently from a51a422 to 2f03810 Compare May 22, 2023 13:29
When we run a retore remotely on the vttablet, we need to run the
partial restore logic through mysqlctl to ensure we run it with the
correct MySQL binaries.

It adds additional safety checks for using `Mysqld` because it's reused
between both the local MySQL interaction and `mysqlctl` but also as a
remote interface used from `vttablet`.

This safety check means that we should never run certain things when
running remotely inside `vttablet`, which is identified by the
`socketFile` being set or not. When it is set, we now panic on certain
actions we know are not going to work.

By adding this panic we can ensure we catch uses like the restore usage
earlier since it would break if we do anything unsupported.

Signed-off-by: Dirkjan Bussink <[email protected]>
@dbussink dbussink force-pushed the dbussink/remote-binlog-restore branch from 2f03810 to 8061c55 Compare May 22, 2023 14:01
func (c *capabilitySet) hasDisableRedoLog() bool {
return c.isMySQLLike() && c.version.atLeast(ServerVersion{Major: 8, Minor: 0, Patch: 21})
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have removed this function since nothing is using atm. I'd like to reduce anything that checks capabilities to as little as possible, since this PR also further restricts that these capabilities can only be used properly inside mysqlctl and with less surface, we have less potential issues where it can be used wrong.

if socketFile != "" {
log.Info("mysqld is remote. Skipping flavor detection")
return result
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This ensures we don't set up capabilities when we can't correctly detect them.

@@ -286,7 +293,7 @@ func (mysqld *Mysqld) RunMysqlUpgrade() error {
return fmt.Errorf("can't dial mysqlctld: %v", err)
}
defer client.Close()
return client.RunMysqlUpgrade(context.TODO())
return client.RunMysqlUpgrade(ctx)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems simplest to pass in the context we already have in all the callers further up in the call chain.

@@ -635,6 +642,7 @@ func execCmd(name string, args, env []string, dir string, input io.Reader) (cmd
// binaryPath does a limited path lookup for a command,
// searching only within sbin and bin in the given root.
func binaryPath(root, binary string) (string, error) {
noSocketFile()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Anywhere we're going to check if a certain binary is available, implies we need to be running inside mysqlctl. This ensures we error out hard when we try to end up calling this somewhere else.

Everything is correct here today, this is a safety mechanism so that we don't accidentally add broken usage in the future.

}
res := qr.Named().Row()
version, _ := res.ToString("@@global.version")
return version
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar to GetVersionComment, we get the version number here at runtime from the actual running MySQL instance. This ensures we get the right version and not the local binary.

}
defer client.Close()
return client.ApplyBinlogFile(ctx, binlogFile, mysql.EncodePosition(restorePos))
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is now part of the interface and also has a remote version so we can run this correctly for restores through mysqlctl.

// $ mysqlbinlog --include-gtids binlog.file | mysql
func (mysqld *Mysqld) applyBinlogFile(binlogFile string, includeGTIDs mysql.GTIDSet) error {
func (mysqld *Mysqld) ApplyBinlogFile(ctx context.Context, binlogFile string, restorePos mysql.Position) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changing this to mysql.Position makes it easier to serialize / deserialize and better matches how we use a GTID position in other places here.

@dbussink dbussink added Type: Bug Component: TabletManager Component: Backup and Restore and removed NeedsDescriptionUpdate The description is not clear or comprehensive enough, and needs work NeedsWebsiteDocsUpdate What it says NeedsIssue A linked issue is missing for this Pull Request labels May 22, 2023
@dbussink dbussink marked this pull request as ready for review May 22, 2023 14:40
@dbussink dbussink changed the title restore: Run partial restore through mysqlctl restore: Run PITR restore through mysqlctl May 22, 2023
@dbussink dbussink changed the title restore: Run PITR restore through mysqlctl restore: Run PITR through mysqlctl May 22, 2023
BinlogRestorePosition: binlogRestorePosition,
}
return c.withRetry(ctx, func() error {
_, err := c.c.ApplyBinlogFile(ctx, req)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a fan of c.c. but unrelated to this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copied this basically from the other things we have to be consistent.

log.Errorf("Unexpected number of rows: %v", qr.Rows)
return ""
}
res := qr.Named().Row()
Copy link
Contributor

Choose a reason for hiding this comment

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

BTW the function Row() returns nil if the number of rows != 1. So if you wanted, you could rewrite the integrity check above from if len(qr.Rows) != 1 { to (down in this line) if res == nil. Whichever you feel more comfortable with, seeing that the former is more explicit and the latter is implied.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here, this is basically a copy paste of how the comment version works and mostly the same to stay consistent with that.

@harshit-gangal harshit-gangal merged commit 04c4862 into vitessio:main May 23, 2023
@harshit-gangal harshit-gangal deleted the dbussink/remote-binlog-restore branch May 23, 2023 06:54
dbussink added a commit to planetscale/vitess that referenced this pull request May 23, 2023
After the changes in vitessio#13123, I
realized that there's no cases left where we actually use or depend on
`MYSQL_FLAVOR`.

This means we can actually remove usages of `MYSQL_FLAVOR`. It doesn't
yet remove it from the artifacts we build, because we shouldn't clean
that up until v18 then because users might mix versions during the
upgrade and we don't want to have old code that still depends on this
fail then.

Signed-off-by: Dirkjan Bussink <[email protected]>
deepthi pushed a commit that referenced this pull request May 23, 2023
* mysqlctl: Remove usage of MYSQL_FLAVOR

After the changes in #13123, I
realized that there's no cases left where we actually use or depend on
`MYSQL_FLAVOR`.

This means we can actually remove usages of `MYSQL_FLAVOR`. It doesn't
yet remove it from the artifacts we build, because we shouldn't clean
that up until v18 then because users might mix versions during the
upgrade and we don't want to have old code that still depends on this
fail then.

Signed-off-by: Dirkjan Bussink <[email protected]>

* Add release note item for removed `MYSQL_FLAVOR`.

Signed-off-by: Dirkjan Bussink <[email protected]>

---------

Signed-off-by: Dirkjan Bussink <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug Report: PITR recovery uses local mysql directly
3 participants