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

[tm_state] updateLocked should re-populate local metadata tables to reflect promotion rule changes #8107

Merged
merged 7 commits into from
May 18, 2021

Conversation

ajm188
Copy link
Contributor

@ajm188 ajm188 commented May 12, 2021

Signed-off-by: Andrew Mason amason@slack-corp.com

Description

TODO.

This means we call PopulateMetadataTables on:

  • (*tmState).ChangeTabletType
  • (*tmState).RefreshFromTopoInfo
  • (*tmState).RefreshFromTopo (via RefreshFromTopoInfo)
  • (*tmState).Open

See it in action

❯ vtctldclient --server "localhost:15999" GetTablets
zone1-0000000100 commerce 0 master SFO-M-AMASON02:15100 SFO-M-AMASON02:17100 [] 2021-05-12T15:48:34Z
zone1-0000000101 commerce 0 replica SFO-M-AMASON02:15101 SFO-M-AMASON02:17101 [] <null>
zone1-0000000102 commerce 0 rdonly SFO-M-AMASON02:15102 SFO-M-AMASON02:17102 [] <null>

# on zone1-101
mysql> select * from _vt.local_metadata;
+---------------+------------------+-------------+
| name          | value            | db_name     |
+---------------+------------------+-------------+
| Alias         | zone1-0000000101 | vt_commerce |
| ClusterAlias  | commerce.0       | vt_commerce |
| DataCenter    | zone1            | vt_commerce |
| PromotionRule | neutral          | vt_commerce |
+---------------+------------------+-------------+
4 rows in set (0.00 sec)

# now, the tablet type change
❯ vtctldclient --server "localhost:15999" ChangeTabletType zone1-0000000101 rdonly
- zone1-0000000101 commerce 0 replica SFO-M-AMASON02:15101 SFO-M-AMASON02:17101 [] <null>
+ zone1-0000000101 commerce 0 rdonly SFO-M-AMASON02:15101 SFO-M-AMASON02:17101 [] <null>

mysql> mysql> select * from _vt.local_metadata;
+---------------+------------------+-------------+
| name          | value            | db_name     |
+---------------+------------------+-------------+
| Alias         | zone1-0000000101 | vt_commerce |
| ClusterAlias  | commerce.0       | vt_commerce |
| DataCenter    | zone1            | vt_commerce |
| PromotionRule | must_not         | vt_commerce |
+---------------+------------------+-------------+
4 rows in set (0.01 sec)

Related Issue(s)

Checklist

  • Tests were added or are not required
  • Documentation was added or is not required

Deployment Notes

@ajm188 ajm188 requested a review from rafael May 12, 2021 14:09
@ajm188 ajm188 force-pushed the am_populate_metadata_on_type_change branch from 7881b90 to 9953560 Compare May 12, 2021 14:13
@ajm188 ajm188 changed the title [tm_state] updateLocked should re-populated local metadata tables to reflect promotion rule changes [tm_state] updateLocked should re-populate local metadata tables to reflect promotion rule changes May 12, 2021
@ajm188 ajm188 force-pushed the am_populate_metadata_on_type_change branch 2 times, most recently from 85e47b9 to 217fd18 Compare May 13, 2021 00:05
@@ -229,12 +229,21 @@ func (ts *tmState) updateLocked(ctx context.Context) {
return
}

populateMetadata := func() {
Copy link
Member

Choose a reason for hiding this comment

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

Populate metadata does some extra work that only makes sense when the tablet is bootstrapping (like creating the metadata table). All the instructions are idempotent, but I think it will be clearer/cleaner to explicitly add a method to only update the metadata

@ajm188
Copy link
Contributor Author

ajm188 commented May 13, 2021

Ugh, I've fixed (mostly, there are some flaky tests) all the unit tests, but this is very much breaking the faketablet/fakesqldb invariants expected by the legacy workflow tests, and I'm not sure how to best tackle that

@ajm188
Copy link
Contributor Author

ajm188 commented May 14, 2021

At last!! Only the true failures:

    tablet_test.go:107: 
        	Error Trace:	tablet_test.go:107
        	Error:      	Expected nil, but got: [][]sqltypes.Value{[]sqltypes.Value{sqltypes.Value{typ:6165, val:[]uint8{0x41, 0x6c, 0x69, 0x61, 0x73}}, sqltypes.Value{typ:10260, val:[]uint8{0x7a, 0x6f, 0x6e, 0x65, 0x31, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x36}}, sqltypes.Value{typ:10262, val:[]uint8{0x76, 0x74, 0x5f, 0x6b, 0x73}}}, []sqltypes.Value{sqltypes.Value{typ:6165, val:[]uint8{0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x6c, 0x69, 0x61, 0x73}}, sqltypes.Value{typ:10260, val:[]uint8{0x6b, 0x73, 0x2e, 0x30}}, sqltypes.Value{typ:10262, val:[]uint8{0x76, 0x74, 0x5f, 0x6b, 0x73}}}, []sqltypes.Value{sqltypes.Value{typ:6165, val:[]uint8{0x44, 0x61, 0x74, 0x61, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72}}, sqltypes.Value{typ:10260, val:[]uint8{0x7a, 0x6f, 0x6e, 0x65, 0x31}}, sqltypes.Value{typ:10262, val:[]uint8{0x76, 0x74, 0x5f, 0x6b, 0x73}}}, []sqltypes.Value{sqltypes.Value{typ:6165, val:[]uint8{0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65}}, sqltypes.Value{typ:10260, val:[]uint8{0x6e, 0x65, 0x75, 0x74, 0x72, 0x61, 0x6c}}, sqltypes.Value{typ:10262, val:[]uint8{0x76, 0x74, 0x5f, 0x6b, 0x73}}}}
        	Test:       	TestLocalMetadata

Looks like I will need to some additional plumbing of state through to tell whether we're initializing or going through a state transition, which will also help incorporating your suggestion @rafael simpler.

@ajm188 ajm188 force-pushed the am_populate_metadata_on_type_change branch from 1824722 to 765346d Compare May 15, 2021 02:30
…eflect promotion rule changes

Signed-off-by: Andrew Mason <amason@slack-corp.com>
If we're enabling the queryservice, wait until afterwards to populate
the metadata. On the other hand, if we're disabling the queryservice,
then populate the metadata just before shutting down the queryservice.

Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
…ate_metadata` flag

Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
…ator func

Also, track if we've previously called PopulateMetadataTables, and if
so, only do the Upsert rather than Create+Upsert

Signed-off-by: Andrew Mason <amason@slack-corp.com>
Copy link
Contributor

@shlomi-noach shlomi-noach left a comment

Choose a reason for hiding this comment

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

@ajm188 nice work and thank you for the contribution! Code looks good, I do wish to reduce some confusion about function names and visibility of functions, please see inline comments.

// _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 {
Copy link
Contributor

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()?

return createMetadataTables(conn, dbName)
}

func createMetadataTables(conn *dbconnpool.DBConnection, dbName string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

... following up on my previous comment, we now have one method CreateMetadataTables, one function CreateMetadataTables, one function createMetadataTables. Let's try and make these less ambiguous by renaming the latter two?

Copy link
Contributor Author

@ajm188 ajm188 May 18, 2021

Choose a reason for hiding this comment

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

Yeah, how about this:

  • MetadataManager has public methods: {Create,Populate}MetadataTables and UpsertMetadataTables
  • The main reason I did this "public function and also public method on struct" thing was to reduce the number of changes I needed to do (because otherwise I would have to update everyone that called mysqlctl.PopulateMetadataTables .... which now that i look is just two places in mysqlctl/backup.go so maybe I should just change them 🤔 )
  • The other reason for the public/private with the same name was to allow code reuse without having to get new dba connections for each stage, so in Populate, we first get a connection, and then call private create and private upsert, whereas if we called public Create and public Upsert then we would get a new connection for each of those.

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?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good. We can do so iteratively in followup PRs.

// 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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

this function is only called locally, reduce its visibility by lowercasing it?

return upsertLocalMetadata(conn, localMetadata, dbName)
}

func upsertLocalMetadata(conn *dbconnpool.DBConnection, localMetadata map[string]string, dbName string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

similarly, we have three different functions now called upsertLocalMetadata with different capitalization. Let's change names to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Cluster management Type: Enhancement Logical improvement (somewhere between a bug and feature)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants