-
Notifications
You must be signed in to change notification settings - Fork 2.3k
[tm_state] updateLocked should re-populate local metadata tables to reflect promotion rule changes #8107
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
[tm_state] updateLocked should re-populate local metadata tables to reflect promotion rule changes #8107
Changes from all commits
3890523
4493513
a407234
049d4b5
449f852
6d9af98
cf15b31
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 |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ import ( | |
|
|
||
| "vitess.io/vitess/go/mysql" | ||
| "vitess.io/vitess/go/sqltypes" | ||
| "vitess.io/vitess/go/vt/dbconnpool" | ||
| "vitess.io/vitess/go/vt/log" | ||
| ) | ||
|
|
||
|
|
@@ -58,20 +59,44 @@ var ( | |
| } | ||
| ) | ||
|
|
||
| // PopulateMetadataTables creates and fills the _vt.local_metadata table and | ||
| // creates _vt.shard_metadata table. _vt.local_metadata table is | ||
| // a per-tablet table that is never replicated. This allows queries | ||
| // against local_metadata to return different values on different tablets, | ||
| // which is used for communicating between Vitess and MySQL-level tools like | ||
| // Orchestrator (https://github.com/openark/orchestrator). | ||
| // MetadataManager manages the creation and filling of the _vt.local_metadata | ||
| // and _vt.shard_metadata tables. | ||
| type MetadataManager struct{} | ||
|
|
||
| // CreateMetadataTables creates the metadata tables. See the package-level | ||
| // function for more details. | ||
| func (m *MetadataManager) CreateMetadataTables(mysqld MysqlDaemon, dbName string) error { | ||
| return CreateMetadataTables(mysqld, dbName) | ||
| } | ||
|
|
||
| // PopulateMetadataTables creates and fills the metadata tables. See the | ||
| // package-level function for more details. | ||
| func (m *MetadataManager) PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, dbName string) error { | ||
| return PopulateMetadataTables(mysqld, localMetadata, dbName) | ||
| } | ||
|
|
||
| // UpsertLocalMetadata adds the given metadata map to the _vt.local_metadata | ||
| // table, updating any duplicate rows to the values in the map. See the package- | ||
| // level function for more details. | ||
| func (m *MetadataManager) UpsertLocalMetadata(mysqld MysqlDaemon, localMetadata map[string]string, dbName string) error { | ||
| return UpsertLocalMetadata(mysqld, localMetadata, dbName) | ||
| } | ||
|
|
||
| // CreateMetadataTables creates the _vt.local_metadata and _vt.shard_metadata | ||
| // tables. | ||
| // | ||
| // _vt.local_metadata table is a per-tablet table that is never replicated. | ||
| // This allows queries against local_metadata to return different values on | ||
| // different tablets, which is used for communicating between Vitess and | ||
| // MySQL-level tools like Orchestrator (https://github.com/openark/orchestrator). | ||
| // | ||
| // _vt.shard_metadata is a replicated table with per-shard information, but it's | ||
| // created here to make it easier to create it on databases that were running | ||
| // old version of Vitess, or databases that are getting converted to run under | ||
| // Vitess. | ||
| func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, dbName string) error { | ||
| log.Infof("Populating _vt.local_metadata table...") | ||
| func CreateMetadataTables(mysqld MysqlDaemon, dbName string) error { | ||
| log.Infof("Creating _vt.local_metadata and _vt.shard_metadata tables ...") | ||
|
|
||
| // Get a non-pooled DBA connection. | ||
| conn, err := mysqld.GetDbaConnection(context.TODO()) | ||
| if err != nil { | ||
| return err | ||
|
|
@@ -84,13 +109,30 @@ func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, | |
| return err | ||
| } | ||
|
|
||
| // Create the database and table if necessary. | ||
| return createMetadataTables(conn, dbName) | ||
| } | ||
|
|
||
| func createMetadataTables(conn *dbconnpool.DBConnection, dbName string) error { | ||
|
Contributor
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. ... following up on my previous comment, we now have one method
Contributor
Author
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. Yeah, how about this:
Then, we do: type MetadataManager struct {}
func (m *MetadataManager) PopulateMetadataTables(mysqld MysqldDaemon, dbName string) error {
log.Infof("....")
conn, err := mysqld.GetDbaConnection(...)
if err != nil {
return err
}
defer conn.Close()
return m.populateMetadataTablesWithConn(conn, dbName)
}
func PopulateMetadataTables(mysqld MysqldDaemon, localMetadata map[string]string, dbName string) error {
m := &MetadataManager{}
return m.PopulateMetadataTables(mysqld, localMetadata, dbName)
}and then the private function does all the logic, and has a slightly cleaner naming (due to the "WithConn" suffix, or at least that's my goal!). And if we want, I can update those last few callsites and remove the package-level public function as well. What do you think?
Contributor
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. Sounds good. We can do so iteratively in followup PRs. |
||
| if _, err := conn.ExecuteFetch("CREATE DATABASE IF NOT EXISTS _vt", 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := createLocalMetadataTable(conn, dbName); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := createShardMetadataTable(conn, dbName); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func createLocalMetadataTable(conn *dbconnpool.DBConnection, dbName string) error { | ||
| if _, err := conn.ExecuteFetch(sqlCreateLocalMetadataTable, 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| for _, sql := range sqlAlterLocalMetadataTable { | ||
| if _, err := conn.ExecuteFetch(sql, 0, false); err != nil { | ||
| // Ignore "Duplicate column name 'db_name'" errors which can happen on every restart. | ||
|
|
@@ -100,13 +142,20 @@ func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, | |
| } | ||
| } | ||
| } | ||
|
|
||
| sql := fmt.Sprintf(sqlUpdateLocalMetadataTable, dbName) | ||
| if _, err := conn.ExecuteFetch(sql, 0, false); err != nil { | ||
| log.Errorf("Error executing %v: %v, continuing. Please check the data in _vt.local_metadata and take corrective action.", sql, err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func createShardMetadataTable(conn *dbconnpool.DBConnection, dbName string) error { | ||
| if _, err := conn.ExecuteFetch(sqlCreateShardMetadataTable, 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| for _, sql := range sqlAlterShardMetadataTable { | ||
| if _, err := conn.ExecuteFetch(sql, 0, false); err != nil { | ||
| // Ignore "Duplicate column name 'db_name'" errors which can happen on every restart. | ||
|
|
@@ -116,11 +165,73 @@ func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, | |
| } | ||
| } | ||
| } | ||
| sql = fmt.Sprintf(sqlUpdateShardMetadataTable, dbName) | ||
|
|
||
| sql := fmt.Sprintf(sqlUpdateShardMetadataTable, dbName) | ||
| if _, err := conn.ExecuteFetch(sql, 0, false); err != nil { | ||
| log.Errorf("Error executing %v: %v, continuing. Please check the data in _vt.shard_metadata and take corrective action.", sql, err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // PopulateMetadataTables creates and fills the _vt.local_metadata table and | ||
| // creates _vt.shard_metadata table. | ||
| // | ||
| // This function is semantically equivalent to calling CreateMetadataTables | ||
| // followed immediately by UpsertLocalMetadata. | ||
| func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, dbName string) error { | ||
| log.Infof("Populating _vt.local_metadata table...") | ||
|
|
||
| // Get a non-pooled DBA connection. | ||
| conn, err := mysqld.GetDbaConnection(context.TODO()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer conn.Close() | ||
|
|
||
| // Disable replication on this session. We close the connection after using | ||
| // it, so there's no need to re-enable replication when we're done. | ||
| if _, err := conn.ExecuteFetch("SET @@session.sql_log_bin = 0", 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Create the database and table if necessary. | ||
| if err := createMetadataTables(conn, dbName); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Populate local_metadata from the passed list of values. | ||
| return upsertLocalMetadata(conn, localMetadata, dbName) | ||
| } | ||
|
|
||
| // UpsertLocalMetadata adds the given metadata map to the _vt.local_metadata | ||
| // table, updating any rows that exist for a given `_vt.local_metadata.name` | ||
| // with the map value. The session that performs these upserts sets | ||
| // sql_log_bin=0, as the _vt.local_metadata table is meant to never be | ||
| // replicated. | ||
| // | ||
| // Callers are responsible for ensuring the _vt.local_metadata table exists | ||
| // before calling this function, usually by calling CreateMetadataTables at | ||
| // least once prior. | ||
| func UpsertLocalMetadata(mysqld MysqlDaemon, localMetadata map[string]string, dbName string) error { | ||
|
Contributor
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. this function is only called locally, reduce its visibility by lowercasing it? |
||
| log.Infof("Upserting _vt.local_metadata ...") | ||
|
|
||
| conn, err := mysqld.GetDbaConnection(context.TODO()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer conn.Close() | ||
|
|
||
| // Disable replication on this session. We close the connection after using | ||
| // it, so there's no need to re-enable replication when we're done. | ||
| if _, err := conn.ExecuteFetch("SET @@session.sql_log_bin = 0", 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return upsertLocalMetadata(conn, localMetadata, dbName) | ||
| } | ||
|
|
||
| func upsertLocalMetadata(conn *dbconnpool.DBConnection, localMetadata map[string]string, dbName string) error { | ||
|
Contributor
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. similarly, we have three different functions now called |
||
| // Populate local_metadata from the passed list of values. | ||
| if _, err := conn.ExecuteFetch("BEGIN", 0, false); err != nil { | ||
| return err | ||
|
|
@@ -144,6 +255,10 @@ func PopulateMetadataTables(mysqld MysqlDaemon, localMetadata map[string]string, | |
| return err | ||
| } | ||
| } | ||
| _, err = conn.ExecuteFetch("COMMIT", 0, false) | ||
| return err | ||
|
|
||
| if _, err := conn.ExecuteFetch("COMMIT", 0, false); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
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.
It seems like this function is only called locally, rename it to
createMetadataTables()?