diff --git a/go/vt/proto/topodata/topodata.pb.go b/go/vt/proto/topodata/topodata.pb.go index 2a014a19876..b5a704f817b 100644 --- a/go/vt/proto/topodata/topodata.pb.go +++ b/go/vt/proto/topodata/topodata.pb.go @@ -288,10 +288,20 @@ type Tablet struct { // MySQL port. Use topoproto.MysqlPort and topoproto.SetMysqlPort // to access this variable. The functions provide support // for legacy behavior. - MysqlPort int32 `protobuf:"varint,13,opt,name=mysql_port,json=mysqlPort,proto3" json:"mysql_port,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + MysqlPort int32 `protobuf:"varint,13,opt,name=mysql_port,json=mysqlPort,proto3" json:"mysql_port,omitempty"` + // master_term_start_time is the time (in UTC) at which the current term of + // the current tablet began as master. If this tablet is not currently the + // master, this value is ignored. + // + // A new master term begins any time an authoritative decision is communicated + // about which tablet should be the master, such as via Vitess + // replication-management commands like PlannedReparentShard, + // EmergencyReparentShard, and TabletExternallyReparented. + // + MasterTermStartTime *vttime.Time `protobuf:"bytes,14,opt,name=master_term_start_time,json=masterTermStartTime,proto3" json:"master_term_start_time,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Tablet) Reset() { *m = Tablet{} } @@ -396,6 +406,13 @@ func (m *Tablet) GetMysqlPort() int32 { return 0 } +func (m *Tablet) GetMasterTermStartTime() *vttime.Time { + if m != nil { + return m.MasterTermStartTime + } + return nil +} + // A Shard contains data about a subset of the data whithin a keyspace. type Shard struct { // master_alias is the tablet alias of the master for the shard. @@ -1359,89 +1376,90 @@ func init() { func init() { proto.RegisterFile("topodata.proto", fileDescriptor_52c350cb619f972e) } var fileDescriptor_52c350cb619f972e = []byte{ - // 1342 bytes of a gzipped FileDescriptorProto + // 1349 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6e, 0xdb, 0x46, - 0x13, 0x0f, 0xf5, 0xcf, 0xd2, 0x88, 0x92, 0x99, 0x8d, 0x63, 0x10, 0xfa, 0xbe, 0xa0, 0x86, 0x8a, + 0x13, 0x0f, 0xf5, 0xcf, 0xd4, 0x88, 0x92, 0x99, 0x8d, 0x63, 0x10, 0xfa, 0xbe, 0xa0, 0x86, 0x8a, 0xa0, 0x82, 0x8b, 0xca, 0xad, 0x93, 0xb4, 0x46, 0x8a, 0x02, 0x51, 0x64, 0xa5, 0x71, 0x6c, 0xcb, - 0xc2, 0x4a, 0x46, 0x9b, 0x5e, 0x08, 0x5a, 0x5a, 0x3b, 0x84, 0x29, 0x52, 0xd9, 0x5d, 0x0b, 0x50, - 0x5f, 0xa1, 0x87, 0xf6, 0xdc, 0x37, 0xe8, 0x23, 0xf4, 0x3d, 0x7a, 0xec, 0xa5, 0x7d, 0x92, 0x62, - 0x67, 0x49, 0x8a, 0x92, 0x12, 0xd7, 0x29, 0x7c, 0x9b, 0x99, 0x9d, 0x19, 0xce, 0xfc, 0x76, 0x7e, - 0xb3, 0x12, 0x54, 0x65, 0x38, 0x09, 0x47, 0xae, 0x74, 0x9b, 0x13, 0x1e, 0xca, 0x90, 0x14, 0x63, - 0xbd, 0x06, 0xd2, 0x1b, 0x33, 0x6d, 0xad, 0xef, 0x42, 0xf1, 0x90, 0xcd, 0xa8, 0x1b, 0x5c, 0x30, - 0xb2, 0x01, 0x79, 0x21, 0x5d, 0x2e, 0x6d, 0x63, 0xcb, 0x68, 0x98, 0x54, 0x2b, 0xc4, 0x82, 0x2c, - 0x0b, 0x46, 0x76, 0x06, 0x6d, 0x4a, 0xac, 0x3f, 0x82, 0xf2, 0xc0, 0x3d, 0xf3, 0x99, 0x6c, 0xf9, - 0x9e, 0x2b, 0x08, 0x81, 0xdc, 0x90, 0xf9, 0x3e, 0x46, 0x95, 0x28, 0xca, 0x2a, 0xe8, 0xca, 0xd3, - 0x41, 0x15, 0xaa, 0xc4, 0xfa, 0xef, 0x39, 0x28, 0xe8, 0x28, 0xf2, 0x29, 0xe4, 0x5d, 0x15, 0x89, - 0x11, 0xe5, 0xdd, 0xfb, 0xcd, 0xa4, 0xd2, 0x54, 0x5a, 0xaa, 0x7d, 0x48, 0x0d, 0x8a, 0x6f, 0x42, - 0x21, 0x03, 0x77, 0xcc, 0x30, 0x5d, 0x89, 0x26, 0x3a, 0xd9, 0x83, 0xe2, 0x24, 0xe4, 0xd2, 0x19, - 0xbb, 0x13, 0x3b, 0xb7, 0x95, 0x6d, 0x94, 0x77, 0x1f, 0x2c, 0xe7, 0x6a, 0xf6, 0x42, 0x2e, 0x8f, - 0xdd, 0x49, 0x27, 0x90, 0x7c, 0x46, 0xd7, 0x26, 0x5a, 0x53, 0x59, 0x2f, 0xd9, 0x4c, 0x4c, 0xdc, - 0x21, 0xb3, 0xf3, 0x3a, 0x6b, 0xac, 0x23, 0x0c, 0x6f, 0x5c, 0x3e, 0xb2, 0x0b, 0x78, 0xa0, 0x15, - 0xb2, 0x03, 0xa5, 0x4b, 0x36, 0x73, 0xb8, 0x42, 0xca, 0x5e, 0xc3, 0xc2, 0xc9, 0xfc, 0x63, 0x31, - 0x86, 0x98, 0x46, 0xa3, 0xd9, 0x80, 0x9c, 0x9c, 0x4d, 0x98, 0x5d, 0xdc, 0x32, 0x1a, 0xd5, 0xdd, - 0x8d, 0xe5, 0xc2, 0x06, 0xb3, 0x09, 0xa3, 0xe8, 0x41, 0x1a, 0x60, 0x8d, 0xce, 0x1c, 0xd5, 0x91, - 0x13, 0x4e, 0x19, 0xe7, 0xde, 0x88, 0xd9, 0x25, 0xfc, 0x76, 0x75, 0x74, 0xd6, 0x75, 0xc7, 0xec, - 0x24, 0xb2, 0x92, 0x26, 0xe4, 0xa4, 0x7b, 0x21, 0x6c, 0xc0, 0x66, 0x6b, 0x2b, 0xcd, 0x0e, 0xdc, - 0x0b, 0xa1, 0x3b, 0x45, 0x3f, 0xf2, 0x10, 0xaa, 0xe3, 0x99, 0x78, 0xeb, 0x3b, 0x09, 0x84, 0x26, - 0xe6, 0xad, 0xa0, 0xf5, 0x65, 0x8c, 0xe3, 0x03, 0x00, 0xed, 0xa6, 0xe0, 0xb1, 0x2b, 0x5b, 0x46, - 0x23, 0x4f, 0x4b, 0x68, 0x51, 0xe8, 0xd5, 0x9e, 0x82, 0x99, 0x46, 0x51, 0x5d, 0xee, 0x25, 0x9b, - 0x45, 0xf7, 0xad, 0x44, 0x05, 0xd9, 0xd4, 0xf5, 0xaf, 0xf4, 0x0d, 0xe5, 0xa9, 0x56, 0x9e, 0x66, - 0xf6, 0x8c, 0xda, 0x57, 0x50, 0x4a, 0x8a, 0xfa, 0xb7, 0xc0, 0x52, 0x2a, 0xf0, 0x55, 0xae, 0x98, - 0xb5, 0x72, 0xaf, 0x72, 0xc5, 0xb2, 0x65, 0xd6, 0xff, 0x28, 0x40, 0xbe, 0x8f, 0xb7, 0xb0, 0x07, - 0xe6, 0xd8, 0x15, 0x92, 0x71, 0xe7, 0x06, 0x13, 0x54, 0xd6, 0xae, 0x7a, 0x4a, 0x5b, 0xb0, 0x19, - 0x45, 0x4a, 0xc6, 0xc7, 0x0e, 0xce, 0xb6, 0xa3, 0x88, 0x80, 0x17, 0x54, 0xde, 0x35, 0x9b, 0x53, - 0x89, 0xbc, 0x18, 0x78, 0x63, 0x46, 0xef, 0x69, 0xdf, 0x01, 0xe3, 0xe3, 0xbe, 0xf2, 0x54, 0xc6, - 0xc5, 0x11, 0xc8, 0xdc, 0x60, 0x04, 0xbe, 0x01, 0x53, 0x30, 0x3e, 0x65, 0x23, 0x47, 0xdd, 0xb3, - 0xb0, 0xb3, 0xcb, 0xd7, 0x86, 0x4d, 0x35, 0xfb, 0xe8, 0x83, 0x03, 0x51, 0x16, 0x89, 0x2c, 0xc8, - 0x33, 0xa8, 0x88, 0xf0, 0x8a, 0x0f, 0x99, 0x83, 0x23, 0x28, 0xa2, 0x19, 0xff, 0xdf, 0x4a, 0x3c, - 0x3a, 0xa1, 0x4c, 0x4d, 0x31, 0x57, 0x04, 0x79, 0x01, 0xeb, 0x12, 0x01, 0x71, 0x86, 0x61, 0x20, - 0x79, 0xe8, 0x0b, 0xbb, 0xb0, 0xcc, 0x13, 0x9d, 0x43, 0xe3, 0xd6, 0xd6, 0x5e, 0xb4, 0x2a, 0xd3, - 0xaa, 0x20, 0xdb, 0x70, 0xd7, 0x13, 0x4e, 0x84, 0x9f, 0x2a, 0xd1, 0x0b, 0x2e, 0x90, 0x04, 0x45, - 0xba, 0xee, 0x89, 0x63, 0xb4, 0xf7, 0xb5, 0xb9, 0xf6, 0x1a, 0x60, 0xde, 0x10, 0x79, 0x02, 0xe5, - 0xa8, 0x02, 0x24, 0x83, 0x71, 0x0d, 0x19, 0x40, 0x26, 0xb2, 0x9a, 0x0b, 0xb5, 0x47, 0x84, 0x9d, - 0xd9, 0xca, 0xaa, 0xb9, 0x40, 0xa5, 0xf6, 0xab, 0x01, 0xe5, 0x54, 0xb3, 0xf1, 0x96, 0x31, 0x92, - 0x2d, 0xb3, 0xc0, 0xeb, 0xcc, 0xfb, 0x78, 0x9d, 0x7d, 0x2f, 0xaf, 0x73, 0x37, 0xb8, 0xd4, 0x4d, - 0x28, 0x60, 0xa1, 0xc2, 0xce, 0x63, 0x6d, 0x91, 0x56, 0xfb, 0xcd, 0x80, 0xca, 0x02, 0x8a, 0xb7, - 0xda, 0x3b, 0xf9, 0x0c, 0xc8, 0x99, 0xef, 0x0e, 0x2f, 0x7d, 0x4f, 0x48, 0x35, 0x50, 0xba, 0x84, - 0x1c, 0xba, 0xdc, 0x4d, 0x9d, 0x60, 0x52, 0xa1, 0xaa, 0x3c, 0xe7, 0xe1, 0x8f, 0x2c, 0xc0, 0xf5, - 0x56, 0xa4, 0x91, 0x96, 0xd0, 0x2a, 0x6f, 0x15, 0xea, 0x7f, 0x66, 0x71, 0xf9, 0x6b, 0x74, 0x3e, - 0x87, 0x0d, 0x04, 0xc4, 0x0b, 0x2e, 0x9c, 0x61, 0xe8, 0x5f, 0x8d, 0x03, 0xdc, 0x48, 0x11, 0x59, - 0x49, 0x7c, 0xd6, 0xc6, 0x23, 0xb5, 0x94, 0xc8, 0xab, 0xd5, 0x08, 0xec, 0x33, 0x83, 0x7d, 0xda, - 0x0b, 0x20, 0xe2, 0x37, 0x0e, 0xf4, 0x8c, 0x2f, 0xe5, 0xc2, 0x9e, 0x9f, 0x25, 0x4c, 0x39, 0xe7, - 0xe1, 0x58, 0xac, 0x6e, 0xf3, 0x38, 0x47, 0x44, 0x96, 0x17, 0x3c, 0x1c, 0xc7, 0x64, 0x51, 0xb2, - 0x20, 0x5f, 0x43, 0x25, 0xbe, 0x69, 0x5d, 0x46, 0x1e, 0xcb, 0xd8, 0x5c, 0x4d, 0x81, 0x45, 0x98, - 0x97, 0x29, 0x8d, 0x7c, 0x0c, 0x95, 0x33, 0x57, 0x30, 0x27, 0x99, 0x1d, 0xbd, 0xfa, 0x4d, 0x65, - 0x4c, 0x10, 0xfa, 0x02, 0x2a, 0x22, 0x70, 0x27, 0xe2, 0x4d, 0x18, 0x2d, 0x8e, 0xb5, 0x77, 0x2c, - 0x0e, 0x33, 0x76, 0x51, 0x5a, 0xed, 0x2a, 0xe6, 0x82, 0xaa, 0xf1, 0x76, 0xe7, 0x21, 0x3d, 0xe9, - 0xd9, 0xc5, 0x49, 0xd7, 0x97, 0x5c, 0xff, 0xc9, 0x00, 0x4b, 0x2f, 0x05, 0x36, 0xf1, 0xbd, 0xa1, - 0x2b, 0xbd, 0x30, 0x20, 0x4f, 0x20, 0x1f, 0x84, 0x23, 0xa6, 0x36, 0xa7, 0x42, 0xf8, 0xa3, 0xa5, - 0x3d, 0x90, 0x72, 0x6d, 0x76, 0xc3, 0x11, 0xa3, 0xda, 0xbb, 0xf6, 0x0c, 0x72, 0x4a, 0x55, 0xfb, - 0x37, 0x6a, 0xe1, 0x26, 0xfb, 0x57, 0xce, 0x95, 0xfa, 0x29, 0x54, 0xa3, 0x2f, 0x9c, 0x33, 0xce, - 0x82, 0x21, 0x53, 0xbf, 0x1b, 0x52, 0x13, 0x86, 0xf2, 0x07, 0xaf, 0xd8, 0xfa, 0xcf, 0x06, 0x10, - 0xcc, 0xbb, 0x48, 0xbd, 0xdb, 0xc8, 0x4d, 0x1e, 0xc3, 0xe6, 0xdb, 0x2b, 0xc6, 0x67, 0x7a, 0xe3, - 0x0d, 0x99, 0x33, 0xf2, 0x84, 0xfa, 0x8a, 0xde, 0x20, 0x45, 0xba, 0x81, 0xa7, 0x7d, 0x7d, 0xb8, - 0x1f, 0x9d, 0xd5, 0xff, 0xce, 0x41, 0xb9, 0xcf, 0xa7, 0xc9, 0xd8, 0x7c, 0x0b, 0x30, 0x71, 0xb9, - 0xf4, 0x14, 0xa6, 0x31, 0xec, 0x9f, 0xa4, 0x60, 0x9f, 0xbb, 0x26, 0x13, 0xda, 0x8b, 0xfd, 0x69, - 0x2a, 0xf4, 0xbd, 0x0c, 0xcd, 0x7c, 0x30, 0x43, 0xb3, 0xff, 0x81, 0xa1, 0x2d, 0x28, 0xa7, 0x18, - 0x1a, 0x11, 0x74, 0xeb, 0xdd, 0x7d, 0xa4, 0x38, 0x0a, 0x73, 0x8e, 0xd6, 0xfe, 0x32, 0xe0, 0xee, - 0x4a, 0x8b, 0x8a, 0x15, 0xa9, 0x47, 0xf2, 0x7a, 0x56, 0xcc, 0x5f, 0x47, 0xd2, 0x06, 0x0b, 0xab, - 0x74, 0x78, 0x3c, 0x50, 0x9a, 0x20, 0xe5, 0x74, 0x5f, 0x8b, 0x13, 0x47, 0xd7, 0xc5, 0x82, 0x2e, - 0x48, 0x0f, 0xee, 0xeb, 0x24, 0xcb, 0xaf, 0xa4, 0x7e, 0xa9, 0xff, 0xbf, 0x94, 0x69, 0xf1, 0x91, - 0xbc, 0x27, 0x56, 0x6c, 0xa2, 0xe6, 0xdc, 0x06, 0xe3, 0xaf, 0x79, 0xc5, 0xa2, 0xd5, 0x7d, 0x08, - 0xc5, 0x36, 0xf3, 0xfd, 0x83, 0xe0, 0x3c, 0x54, 0x3f, 0xf2, 0x10, 0x17, 0xee, 0xb8, 0xa3, 0x11, - 0x67, 0x42, 0x44, 0x53, 0x5f, 0xd1, 0xd6, 0x96, 0x36, 0x2a, 0x4a, 0xf0, 0x30, 0x94, 0x51, 0x42, - 0x94, 0xa3, 0x45, 0x51, 0x07, 0x50, 0xc9, 0x84, 0xfe, 0xa1, 0xf4, 0xce, 0x75, 0xb3, 0xdd, 0x00, - 0x33, 0xbd, 0x3f, 0x09, 0x40, 0xa1, 0x7b, 0x42, 0x8f, 0x5b, 0x47, 0xd6, 0x1d, 0x62, 0x42, 0xb1, - 0xdf, 0x6d, 0xf5, 0xfa, 0x2f, 0x4f, 0x06, 0x96, 0xb1, 0xbd, 0x0b, 0xd5, 0xc5, 0x71, 0x22, 0x25, - 0xc8, 0x9f, 0x76, 0xfb, 0x9d, 0x81, 0x75, 0x47, 0x85, 0x9d, 0x1e, 0x74, 0x07, 0x5f, 0x3e, 0xb6, - 0x0c, 0x65, 0x7e, 0xfe, 0x7a, 0xd0, 0xe9, 0x5b, 0x99, 0xed, 0x5f, 0x0c, 0x80, 0x39, 0x16, 0xa4, - 0x0c, 0x6b, 0xa7, 0xdd, 0xc3, 0xee, 0xc9, 0x77, 0x5d, 0x1d, 0x72, 0xdc, 0xea, 0x0f, 0x3a, 0xd4, - 0x32, 0xd4, 0x01, 0xed, 0xf4, 0x8e, 0x0e, 0xda, 0x2d, 0x2b, 0xa3, 0x0e, 0xe8, 0xfe, 0x49, 0xf7, - 0xe8, 0xb5, 0x95, 0xc5, 0x5c, 0xad, 0x41, 0xfb, 0xa5, 0x16, 0xfb, 0xbd, 0x16, 0xed, 0x58, 0x39, - 0x62, 0x81, 0xd9, 0xf9, 0xbe, 0xd7, 0xa1, 0x07, 0xc7, 0x9d, 0xee, 0xa0, 0x75, 0x64, 0xe5, 0x55, - 0xcc, 0xf3, 0x56, 0xfb, 0xf0, 0xb4, 0x67, 0x15, 0x74, 0xb2, 0xfe, 0xe0, 0x84, 0x76, 0xac, 0x35, - 0xa5, 0xec, 0xd3, 0xd6, 0x41, 0xb7, 0xb3, 0x6f, 0x15, 0x6b, 0x19, 0xcb, 0x78, 0xbe, 0x07, 0xeb, - 0x5e, 0xd8, 0x9c, 0x7a, 0x92, 0x09, 0xa1, 0xff, 0x2b, 0xfd, 0xf0, 0x30, 0xd2, 0xbc, 0x70, 0x47, - 0x4b, 0x3b, 0x17, 0xe1, 0xce, 0x54, 0xee, 0xe0, 0xe9, 0x4e, 0x7c, 0xa9, 0x67, 0x05, 0xd4, 0x1f, - 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xde, 0x20, 0xb2, 0x37, 0x81, 0x0d, 0x00, 0x00, + 0xc2, 0x4a, 0x46, 0x9b, 0x5e, 0x08, 0x5a, 0x5a, 0x3b, 0x84, 0x25, 0x52, 0xd9, 0x5d, 0x0b, 0x50, + 0x5f, 0xa1, 0x87, 0xf6, 0xdc, 0x37, 0xe8, 0xfb, 0xf4, 0xd8, 0x4b, 0xfb, 0x1c, 0x3d, 0x14, 0x3b, + 0x4b, 0x52, 0x94, 0x14, 0xa7, 0x4e, 0xe1, 0xdb, 0xcc, 0xec, 0xcc, 0x70, 0xe6, 0xb7, 0xbf, 0x99, + 0x95, 0xa0, 0x22, 0xc3, 0x49, 0x38, 0xf4, 0xa4, 0xd7, 0x98, 0xf0, 0x50, 0x86, 0xc4, 0x8c, 0xf5, + 0x2a, 0x48, 0x7f, 0xcc, 0xb4, 0xb5, 0xb6, 0x0b, 0xe6, 0x21, 0x9b, 0x51, 0x2f, 0xb8, 0x60, 0x64, + 0x03, 0xf2, 0x42, 0x7a, 0x5c, 0x3a, 0xc6, 0x96, 0x51, 0xb7, 0xa8, 0x56, 0x88, 0x0d, 0x59, 0x16, + 0x0c, 0x9d, 0x0c, 0xda, 0x94, 0x58, 0x7b, 0x04, 0xa5, 0xbe, 0x77, 0x36, 0x62, 0xb2, 0x39, 0xf2, + 0x3d, 0x41, 0x08, 0xe4, 0x06, 0x6c, 0x34, 0xc2, 0xa8, 0x22, 0x45, 0x59, 0x05, 0x5d, 0xf9, 0x3a, + 0xa8, 0x4c, 0x95, 0x58, 0xfb, 0x3b, 0x07, 0x05, 0x1d, 0x45, 0x3e, 0x85, 0xbc, 0xa7, 0x22, 0x31, + 0xa2, 0xb4, 0x7b, 0xbf, 0x91, 0x54, 0x9a, 0x4a, 0x4b, 0xb5, 0x0f, 0xa9, 0x82, 0xf9, 0x26, 0x14, + 0x32, 0xf0, 0xc6, 0x0c, 0xd3, 0x15, 0x69, 0xa2, 0x93, 0x3d, 0x30, 0x27, 0x21, 0x97, 0xee, 0xd8, + 0x9b, 0x38, 0xb9, 0xad, 0x6c, 0xbd, 0xb4, 0xfb, 0x60, 0x39, 0x57, 0xa3, 0x1b, 0x72, 0x79, 0xec, + 0x4d, 0xda, 0x81, 0xe4, 0x33, 0xba, 0x36, 0xd1, 0x9a, 0xca, 0x7a, 0xc9, 0x66, 0x62, 0xe2, 0x0d, + 0x98, 0x93, 0xd7, 0x59, 0x63, 0x1d, 0x61, 0x78, 0xe3, 0xf1, 0xa1, 0x53, 0xc0, 0x03, 0xad, 0x90, + 0x1d, 0x28, 0x5e, 0xb2, 0x99, 0xcb, 0x15, 0x52, 0xce, 0x1a, 0x16, 0x4e, 0xe6, 0x1f, 0x8b, 0x31, + 0xc4, 0x34, 0x1a, 0xcd, 0x3a, 0xe4, 0xe4, 0x6c, 0xc2, 0x1c, 0x73, 0xcb, 0xa8, 0x57, 0x76, 0x37, + 0x96, 0x0b, 0xeb, 0xcf, 0x26, 0x8c, 0xa2, 0x07, 0xa9, 0x83, 0x3d, 0x3c, 0x73, 0x55, 0x47, 0x6e, + 0x38, 0x65, 0x9c, 0xfb, 0x43, 0xe6, 0x14, 0xf1, 0xdb, 0x95, 0xe1, 0x59, 0xc7, 0x1b, 0xb3, 0x93, + 0xc8, 0x4a, 0x1a, 0x90, 0x93, 0xde, 0x85, 0x70, 0x00, 0x9b, 0xad, 0xae, 0x34, 0xdb, 0xf7, 0x2e, + 0x84, 0xee, 0x14, 0xfd, 0xc8, 0x43, 0xa8, 0x8c, 0x67, 0xe2, 0xed, 0xc8, 0x4d, 0x20, 0xb4, 0x30, + 0x6f, 0x19, 0xad, 0x2f, 0x63, 0x1c, 0x1f, 0x00, 0x68, 0x37, 0x05, 0x8f, 0x53, 0xde, 0x32, 0xea, + 0x79, 0x5a, 0x44, 0x8b, 0x42, 0x8f, 0x34, 0x61, 0x73, 0xec, 0x09, 0xc9, 0xb8, 0x2b, 0x19, 0x1f, + 0xbb, 0x48, 0x0b, 0x57, 0x71, 0xc8, 0xa9, 0x20, 0x0e, 0x56, 0x63, 0x2a, 0x91, 0x52, 0x7d, 0x7f, + 0xcc, 0xe8, 0x3d, 0xed, 0xdb, 0x67, 0x7c, 0xdc, 0x53, 0x9e, 0xca, 0x58, 0x7d, 0x0a, 0x56, 0xfa, + 0x22, 0x14, 0x3f, 0x2e, 0xd9, 0x2c, 0xa2, 0x8c, 0x12, 0x15, 0xea, 0x53, 0x6f, 0x74, 0xa5, 0x2f, + 0x39, 0x4f, 0xb5, 0xf2, 0x34, 0xb3, 0x67, 0x54, 0xbf, 0x82, 0x62, 0xd2, 0xd7, 0xbf, 0x05, 0x16, + 0x53, 0x81, 0xaf, 0x72, 0x66, 0xd6, 0xce, 0xbd, 0xca, 0x99, 0x25, 0xdb, 0xaa, 0xfd, 0x5e, 0x80, + 0x7c, 0x0f, 0x2f, 0x72, 0x0f, 0xac, 0xa8, 0x9b, 0x1b, 0x90, 0xb0, 0xa4, 0x5d, 0x35, 0xd1, 0xaf, + 0xc7, 0xc1, 0xbc, 0x21, 0x0e, 0x8b, 0x2c, 0xca, 0xdc, 0x80, 0x45, 0xdf, 0x80, 0x25, 0x18, 0x9f, + 0xb2, 0xa1, 0xab, 0xa8, 0x22, 0x9c, 0xec, 0xf2, 0xcd, 0x63, 0x53, 0x8d, 0x1e, 0xfa, 0x20, 0xa7, + 0x4a, 0x22, 0x91, 0x05, 0x79, 0x06, 0x65, 0x11, 0x5e, 0xf1, 0x01, 0x73, 0x91, 0xc5, 0x22, 0x1a, + 0x93, 0xff, 0xad, 0xc4, 0xa3, 0x13, 0xca, 0xd4, 0x12, 0x73, 0x45, 0x90, 0x17, 0xb0, 0x2e, 0x11, + 0x10, 0x77, 0x10, 0x06, 0x92, 0x87, 0x23, 0xe1, 0x14, 0x96, 0x47, 0x4d, 0xe7, 0xd0, 0xb8, 0xb5, + 0xb4, 0x17, 0xad, 0xc8, 0xb4, 0x2a, 0xc8, 0x36, 0xdc, 0xf5, 0x85, 0x1b, 0xe1, 0xa7, 0x4a, 0xf4, + 0x83, 0x0b, 0x9c, 0x23, 0x93, 0xae, 0xfb, 0xe2, 0x18, 0xed, 0x3d, 0x6d, 0xae, 0xbe, 0x06, 0x98, + 0x37, 0x44, 0x9e, 0x40, 0x29, 0xaa, 0x00, 0xe7, 0xc9, 0x78, 0xcf, 0x3c, 0x81, 0x4c, 0x64, 0xc5, + 0x0b, 0xb5, 0x8a, 0x84, 0x93, 0xd9, 0xca, 0x2a, 0x5e, 0xa0, 0x52, 0xfd, 0xd5, 0x80, 0x52, 0xaa, + 0xd9, 0x78, 0x51, 0x19, 0xc9, 0xa2, 0x5a, 0x58, 0x0d, 0x99, 0xeb, 0x56, 0x43, 0xf6, 0xda, 0xd5, + 0x90, 0xbb, 0xc1, 0xa5, 0x6e, 0x42, 0x01, 0x0b, 0x15, 0x4e, 0x1e, 0x6b, 0x8b, 0xb4, 0xea, 0x6f, + 0x06, 0x94, 0x17, 0x50, 0xbc, 0xd5, 0xde, 0xc9, 0x67, 0x40, 0xce, 0x46, 0xde, 0xe0, 0x72, 0xe4, + 0x0b, 0xa9, 0x08, 0xa5, 0x4b, 0xc8, 0xa1, 0xcb, 0xdd, 0xd4, 0x09, 0x26, 0x15, 0xaa, 0xca, 0x73, + 0x1e, 0xfe, 0xc8, 0x02, 0xdc, 0x90, 0x26, 0x8d, 0xb4, 0x64, 0xac, 0xf2, 0x76, 0xa1, 0xf6, 0x47, + 0x16, 0xdf, 0x0f, 0x8d, 0xce, 0xe7, 0xb0, 0x81, 0x80, 0xf8, 0xc1, 0x85, 0x3b, 0x08, 0x47, 0x57, + 0xe3, 0x00, 0x97, 0x5a, 0x34, 0xac, 0x24, 0x3e, 0x6b, 0xe1, 0x91, 0xda, 0x6b, 0xe4, 0xd5, 0x6a, + 0x04, 0xf6, 0x99, 0xc1, 0x3e, 0x9d, 0x05, 0x10, 0xf1, 0x1b, 0x07, 0x9a, 0xe3, 0x4b, 0xb9, 0xb0, + 0xe7, 0x67, 0xc9, 0xa4, 0x9c, 0xf3, 0x70, 0x2c, 0x56, 0x1f, 0x84, 0x38, 0x47, 0x34, 0x2c, 0x2f, + 0x78, 0x38, 0x8e, 0x87, 0x45, 0xc9, 0x82, 0x7c, 0x0d, 0xe5, 0xf8, 0xa6, 0x75, 0x19, 0x79, 0x2c, + 0x63, 0x73, 0x35, 0x05, 0x16, 0x61, 0x5d, 0xa6, 0x34, 0xf2, 0x31, 0x94, 0xcf, 0x3c, 0xc1, 0xdc, + 0x84, 0x3b, 0xfa, 0xf5, 0xb0, 0x94, 0x31, 0x41, 0xe8, 0x0b, 0x28, 0x8b, 0xc0, 0x9b, 0x88, 0x37, + 0x61, 0xb4, 0x38, 0xd6, 0xde, 0xb1, 0x38, 0xac, 0xd8, 0x05, 0x37, 0xe7, 0x55, 0x3c, 0x0b, 0xaa, + 0xc6, 0xdb, 0xe5, 0x43, 0x9a, 0xe9, 0xd9, 0x45, 0xa6, 0xeb, 0x4b, 0xae, 0xfd, 0x64, 0x80, 0xad, + 0x97, 0x02, 0x9b, 0x8c, 0xfc, 0x81, 0x27, 0xfd, 0x30, 0x20, 0x4f, 0x20, 0x1f, 0x84, 0x43, 0xa6, + 0x36, 0xa7, 0x42, 0xf8, 0xa3, 0xa5, 0x3d, 0x90, 0x72, 0x6d, 0x74, 0xc2, 0x21, 0xa3, 0xda, 0xbb, + 0xfa, 0x0c, 0x72, 0x4a, 0x55, 0xfb, 0x37, 0x6a, 0xe1, 0x26, 0xfb, 0x57, 0xce, 0x95, 0xda, 0x29, + 0x54, 0xa2, 0x2f, 0x9c, 0x33, 0xce, 0x82, 0x01, 0x53, 0x3f, 0x3d, 0x52, 0x0c, 0x43, 0xf9, 0x83, + 0x57, 0x6c, 0xed, 0x67, 0x03, 0x08, 0xe6, 0x5d, 0x1c, 0xbd, 0xdb, 0xc8, 0x4d, 0x1e, 0xc3, 0xe6, + 0xdb, 0x2b, 0xc6, 0x67, 0x7a, 0xe3, 0x0d, 0x98, 0x3b, 0xf4, 0x85, 0xfa, 0x8a, 0xde, 0x20, 0x26, + 0xdd, 0xc0, 0xd3, 0x9e, 0x3e, 0xdc, 0x8f, 0xce, 0x6a, 0x7f, 0xe5, 0xa0, 0xd4, 0xe3, 0xd3, 0x84, + 0x36, 0xdf, 0x02, 0x4c, 0x3c, 0x2e, 0x7d, 0x85, 0x69, 0x0c, 0xfb, 0x27, 0x29, 0xd8, 0xe7, 0xae, + 0x09, 0x43, 0xbb, 0xb1, 0x3f, 0x4d, 0x85, 0x5e, 0x3b, 0xa1, 0x99, 0x0f, 0x9e, 0xd0, 0xec, 0x7f, + 0x98, 0xd0, 0x26, 0x94, 0x52, 0x13, 0x1a, 0x0d, 0xe8, 0xd6, 0xbb, 0xfb, 0x48, 0xcd, 0x28, 0xcc, + 0x67, 0xb4, 0xfa, 0xa7, 0x01, 0x77, 0x57, 0x5a, 0x54, 0x53, 0x91, 0x7a, 0x24, 0xdf, 0x3f, 0x15, + 0xf3, 0xd7, 0x91, 0xb4, 0xc0, 0xc6, 0x2a, 0x5d, 0x1e, 0x13, 0x4a, 0x0f, 0x48, 0x29, 0xdd, 0xd7, + 0x22, 0xe3, 0xe8, 0xba, 0x58, 0xd0, 0x05, 0xe9, 0xc2, 0x7d, 0x9d, 0x64, 0xf9, 0x95, 0xd4, 0x2f, + 0xf5, 0xff, 0x97, 0x32, 0x2d, 0x3e, 0x92, 0xf7, 0xc4, 0x8a, 0x4d, 0x54, 0xdd, 0xdb, 0x98, 0xf8, + 0xf7, 0xbc, 0x62, 0xd1, 0xea, 0x3e, 0x04, 0xb3, 0xc5, 0x46, 0xa3, 0x83, 0xe0, 0x3c, 0x54, 0xbf, + 0x13, 0x11, 0x17, 0xee, 0x7a, 0xc3, 0x21, 0x67, 0x42, 0x44, 0xac, 0x2f, 0x6b, 0x6b, 0x53, 0x1b, + 0xd5, 0x48, 0xf0, 0x30, 0x94, 0x51, 0x42, 0x94, 0xa3, 0x45, 0x51, 0x03, 0x50, 0xc9, 0x84, 0xfe, + 0xa1, 0xf4, 0xce, 0x75, 0xb3, 0x5d, 0x07, 0x2b, 0xbd, 0x3f, 0x09, 0x40, 0xa1, 0x73, 0x42, 0x8f, + 0x9b, 0x47, 0xf6, 0x1d, 0x62, 0x81, 0xd9, 0xeb, 0x34, 0xbb, 0xbd, 0x97, 0x27, 0x7d, 0xdb, 0xd8, + 0xde, 0x85, 0xca, 0x22, 0x9d, 0x48, 0x11, 0xf2, 0xa7, 0x9d, 0x5e, 0xbb, 0x6f, 0xdf, 0x51, 0x61, + 0xa7, 0x07, 0x9d, 0xfe, 0x97, 0x8f, 0x6d, 0x43, 0x99, 0x9f, 0xbf, 0xee, 0xb7, 0x7b, 0x76, 0x66, + 0xfb, 0x17, 0x03, 0x60, 0x8e, 0x05, 0x29, 0xc1, 0xda, 0x69, 0xe7, 0xb0, 0x73, 0xf2, 0x5d, 0x47, + 0x87, 0x1c, 0x37, 0x7b, 0xfd, 0x36, 0xb5, 0x0d, 0x75, 0x40, 0xdb, 0xdd, 0xa3, 0x83, 0x56, 0xd3, + 0xce, 0xa8, 0x03, 0xba, 0x7f, 0xd2, 0x39, 0x7a, 0x6d, 0x67, 0x31, 0x57, 0xb3, 0xdf, 0x7a, 0xa9, + 0xc5, 0x5e, 0xb7, 0x49, 0xdb, 0x76, 0x8e, 0xd8, 0x60, 0xb5, 0xbf, 0xef, 0xb6, 0xe9, 0xc1, 0x71, + 0xbb, 0xd3, 0x6f, 0x1e, 0xd9, 0x79, 0x15, 0xf3, 0xbc, 0xd9, 0x3a, 0x3c, 0xed, 0xda, 0x05, 0x9d, + 0xac, 0xd7, 0x3f, 0xa1, 0x6d, 0x7b, 0x4d, 0x29, 0xfb, 0xb4, 0x79, 0xd0, 0x69, 0xef, 0xdb, 0x66, + 0x35, 0x63, 0x1b, 0xcf, 0xf7, 0x60, 0xdd, 0x0f, 0x1b, 0x53, 0x5f, 0x32, 0x21, 0xf4, 0xdf, 0xad, + 0x1f, 0x1e, 0x46, 0x9a, 0x1f, 0xee, 0x68, 0x69, 0xe7, 0x22, 0xdc, 0x99, 0xca, 0x1d, 0x3c, 0xdd, + 0x89, 0x2f, 0xf5, 0xac, 0x80, 0xfa, 0xa3, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe2, 0xab, 0xbe, + 0xeb, 0xc4, 0x0d, 0x00, 0x00, } diff --git a/go/vt/topotools/tablet.go b/go/vt/topotools/tablet.go index a5527045187..af7c98cd3e2 100644 --- a/go/vt/topotools/tablet.go +++ b/go/vt/topotools/tablet.go @@ -37,6 +37,7 @@ import ( "errors" "fmt" + "github.com/golang/protobuf/proto" "golang.org/x/net/context" "vitess.io/vitess/go/vt/hook" @@ -46,6 +47,7 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/proto/vttime" ) // ConfigureTabletHook configures the right parameters for a hook @@ -61,11 +63,27 @@ func ConfigureTabletHook(hk *hook.Hook, tabletAlias *topodatapb.TabletAlias) { // transitions need to be forced from time to time. // // If successful, the updated tablet record is returned. -func ChangeType(ctx context.Context, ts *topo.Server, tabletAlias *topodatapb.TabletAlias, newType topodatapb.TabletType) (*topodatapb.Tablet, error) { - return ts.UpdateTabletFields(ctx, tabletAlias, func(tablet *topodatapb.Tablet) error { +func ChangeType(ctx context.Context, ts *topo.Server, tabletAlias *topodatapb.TabletAlias, newType topodatapb.TabletType, masterTermStartTime *vttime.Time) (*topodatapb.Tablet, error) { + var result *topodatapb.Tablet + // Always clear out the master timestamp if not master. + if newType != topodatapb.TabletType_MASTER { + masterTermStartTime = nil + } + _, err := ts.UpdateTabletFields(ctx, tabletAlias, func(tablet *topodatapb.Tablet) error { + // Save the most recent tablet value so we can return it + // either if the update succeeds or if no update is needed. + result = tablet + if tablet.Type == newType && proto.Equal(tablet.MasterTermStartTime, masterTermStartTime) { + return topo.NewError(topo.NoUpdateNeeded, topoproto.TabletAliasString(tabletAlias)) + } tablet.Type = newType + tablet.MasterTermStartTime = masterTermStartTime return nil }) + if err != nil { + return nil, err + } + return result, nil } // CheckOwnership returns nil iff the Hostname and port match on oldTablet and diff --git a/go/vt/vtctld/api_test.go b/go/vt/vtctld/api_test.go index 66244c807f4..243cf76ab02 100644 --- a/go/vt/vtctld/api_test.go +++ b/go/vt/vtctld/api_test.go @@ -205,7 +205,8 @@ func TestAPI(t *testing.T) { "db_name_override": "", "tags": {}, "mysql_hostname":"", - "mysql_port":0 + "mysql_port":0, + "master_term_start_time":null }`}, {"GET", "tablets/nonexistent-999", "", "404 page not found"}, {"POST", "tablets/cell1-100?action=TestTabletAction", "", `{ diff --git a/go/vt/vttablet/tabletmanager/healthcheck_test.go b/go/vt/vttablet/tabletmanager/healthcheck_test.go index 88b8eec0e7c..2ecee1b0b0d 100644 --- a/go/vt/vttablet/tabletmanager/healthcheck_test.go +++ b/go/vt/vttablet/tabletmanager/healthcheck_test.go @@ -723,6 +723,29 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { t.Fatalf("TabletExternallyReparented failed: %v", err) } <-agent.finalizeReparentCtx.Done() + // It is not enough to wait for finalizeReparentCtx to be done, we have to wait for shard_sync to finish + startTime := time.Now() + for { + if time.Since(startTime) > 10*time.Second /* timeout */ { + si, err := agent.TopoServer.GetShard(ctx, agent.Tablet().Keyspace, agent.Tablet().Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", agent.Tablet().Keyspace, agent.Tablet().Shard, err) + } + if !topoproto.TabletAliasEqual(si.MasterAlias, agent.Tablet().Alias) { + t.Fatalf("ShardInfo should have MasterAlias %v but has %v", topoproto.TabletAliasString(agent.Tablet().Alias), topoproto.TabletAliasString(si.MasterAlias)) + } + } + si, err := agent.TopoServer.GetShard(ctx, agent.Tablet().Keyspace, agent.Tablet().Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", agent.Tablet().Keyspace, agent.Tablet().Shard, err) + } + if topoproto.TabletAliasEqual(si.MasterAlias, agent.Tablet().Alias) { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to re-check the shard record */) + } + } + ti, err := agent.TopoServer.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) @@ -795,9 +818,8 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { } // Consume health broadcast sent out due to QueryService state change from // (MASTER, SERVING) to (MASTER, NOT_SERVING). - // Since we didn't run healthcheck again yet, the broadcast data contains the - // cached replication lag of 20 instead of 21. - if _, err := expectBroadcastData(agent.QueryServiceControl, false, "", 20); err != nil { + // RefreshState on MASTER always sets the replicationDelay to 0 + if _, err := expectBroadcastData(agent.QueryServiceControl, false, "", 0); err != nil { t.Fatal(err) } if err := expectStateChange(agent.QueryServiceControl, false, topodatapb.TabletType_MASTER); err != nil { @@ -845,8 +867,9 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { t.Errorf("Query service should not be running") } // Since we didn't run healthcheck again yet, the broadcast data contains the - // cached replication lag of 22 instead of 23. - if _, err := expectBroadcastData(agent.QueryServiceControl, true, "", 22); err != nil { + // cached replication lag of 0. This is because + // RefreshState on MASTER always sets the replicationDelay to 0 + if _, err := expectBroadcastData(agent.QueryServiceControl, true, "", 0); err != nil { t.Fatal(err) } if err := expectStateChange(agent.QueryServiceControl, true, topodatapb.TabletType_MASTER); err != nil { @@ -907,7 +930,7 @@ func TestBackupStateChange(t *testing.T) { agent.HealthReporter.(*fakeHealthCheck).reportReplicationDelay = 16 * time.Second // change to BACKUP, query service will turn off - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_BACKUP); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_BACKUP, nil); err != nil { t.Fatal(err) } if err := agent.RefreshState(ctx); err != nil { @@ -921,7 +944,7 @@ func TestBackupStateChange(t *testing.T) { } // change back to REPLICA, query service should not start // because replication delay > unhealthyThreshold - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA, nil); err != nil { t.Fatal(err) } if err := agent.RefreshState(ctx); err != nil { @@ -961,7 +984,7 @@ func TestRestoreStateChange(t *testing.T) { agent.HealthReporter.(*fakeHealthCheck).reportReplicationDelay = 16 * time.Second // change to RESTORE, query service will turn off - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_RESTORE); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_RESTORE, nil); err != nil { t.Fatal(err) } if err := agent.RefreshState(ctx); err != nil { @@ -975,7 +998,7 @@ func TestRestoreStateChange(t *testing.T) { } // change back to REPLICA, query service should not start // because replication delay > unhealthyThreshold - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA, nil); err != nil { t.Fatal(err) } if err := agent.RefreshState(ctx); err != nil { diff --git a/go/vt/vttablet/tabletmanager/init_tablet.go b/go/vt/vttablet/tabletmanager/init_tablet.go index 22a0757d6fb..8e260fe5f58 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet.go +++ b/go/vt/vttablet/tabletmanager/init_tablet.go @@ -117,8 +117,33 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int32) error { // We're marked as master in the shard record, // and our existing tablet record agrees. tabletType = topodatapb.TabletType_MASTER - // Same comment as above. Update tiebreaking timestamp to now. - agent.setMasterTermStartTime(time.Now()) + // Read the master term start time from tablet. + // If it is nil, it might mean that we are upgrading, so use current time instead + if oldTablet.MasterTermStartTime != nil { + agent.setMasterTermStartTime(logutil.ProtoToTime(oldTablet.MasterTermStartTime)) + } else { + agent.setMasterTermStartTime(time.Now()) + } + } + default: + return vterrors.Wrap(err, "InitTablet failed to read existing tablet record") + } + } else { + oldTablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias) + switch { + case topo.IsErrType(err, topo.NoNode): + // There's no existing tablet record, so there is nothing to do + case err == nil: + if oldTablet.Type == topodatapb.TabletType_MASTER { + // Our existing tablet type is master, but the shard record does not agree. + // Only take over if our master_term_start_time is after what is in the shard record + oldMasterTermStartTime := logutil.ProtoToTime(oldTablet.MasterTermStartTime) + currentShardTime := logutil.ProtoToTime(si.MasterTermStartTime) + if oldMasterTermStartTime.After(currentShardTime) { + tabletType = topodatapb.TabletType_MASTER + // read the master term start time from tablet + agent.setMasterTermStartTime(oldMasterTermStartTime) + } } default: return vterrors.Wrap(err, "InitTablet failed to read existing tablet record") @@ -176,6 +201,9 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int32) error { DbNameOverride: *initDbNameOverride, Tags: initTags, } + if !agent.masterTermStartTime().IsZero() { + tablet.MasterTermStartTime = logutil.TimeToProto(agent.masterTermStartTime()) + } if port != 0 { tablet.PortMap["vt"] = port } @@ -219,9 +247,9 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int32) error { return vterrors.Wrap(err, "CreateTablet failed") } + agent.setTablet(tablet) // optionally populate metadata records if *initPopulateMetadata { - agent.setTablet(tablet) localMetadata := agent.getLocalMetadataValues(tablet.Type) err := mysqlctl.PopulateMetadataTables(agent.MysqlDaemon, localMetadata, topoproto.TabletDbName(tablet)) if err != nil { diff --git a/go/vt/vttablet/tabletmanager/init_tablet_test.go b/go/vt/vttablet/tabletmanager/init_tablet_test.go index f674571d5bd..fee66d58d47 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet_test.go +++ b/go/vt/vttablet/tabletmanager/init_tablet_test.go @@ -289,7 +289,7 @@ func TestInitTablet(t *testing.T) { t.Errorf("wrong tablet type: %v", ti.Type) } if got := agent._masterTermStartTime; !got.IsZero() { - t.Fatalf("REPLICA tablet should not have an ExternallyReparentedTimestamp set: %v", got) + t.Fatalf("REPLICA tablet should not have a masterTermStartTime set: %v", got) } // 3. Delete the tablet record. The shard record still says that we are the @@ -310,7 +310,7 @@ func TestInitTablet(t *testing.T) { } ter1 := agent._masterTermStartTime if ter1.IsZero() { - t.Fatalf("MASTER tablet should have an ExternallyReparentedTimestamp set") + t.Fatalf("MASTER tablet should have a masterTermStartTime set") } // 4. Fix the tablet record to agree that we're master. @@ -331,8 +331,8 @@ func TestInitTablet(t *testing.T) { t.Errorf("wrong tablet type: %v", ti.Type) } ter2 := agent._masterTermStartTime - if ter2.IsZero() || !ter2.After(ter1) { - t.Fatalf("After a restart, ExternallyReparentedTimestamp must be set to the current time. Previous timestamp: %v current timestamp: %v", ter1, ter2) + if ter2.IsZero() || !ter2.Equal(ter1) { + t.Fatalf("After a restart, masterTermStartTime must be equal to the previous time saved in the tablet record. Previous timestamp: %v current timestamp: %v", ter1, ter2) } // 5. Subsequent inits will still start the vttablet as MASTER. @@ -356,7 +356,7 @@ func TestInitTablet(t *testing.T) { t.Errorf("wrong tablet tags: %v", ti.Tags) } ter3 := agent._masterTermStartTime - if ter3.IsZero() || !ter3.After(ter2) { - t.Fatalf("After a restart, ExternallyReparentedTimestamp must be set to the current time. Previous timestamp: %v current timestamp: %v", ter2, ter3) + if ter3.IsZero() || !ter3.Equal(ter2) { + t.Fatalf("After a restart, masterTermStartTime must be set to the previous time saved in the tablet record. Previous timestamp: %v current timestamp: %v", ter2, ter3) } } diff --git a/go/vt/vttablet/tabletmanager/rpc_actions.go b/go/vt/vttablet/tabletmanager/rpc_actions.go index 23371341643..b5c61869b6d 100644 --- a/go/vt/vttablet/tabletmanager/rpc_actions.go +++ b/go/vt/vttablet/tabletmanager/rpc_actions.go @@ -21,6 +21,7 @@ import ( "regexp" "time" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -70,15 +71,22 @@ func (agent *ActionAgent) ChangeType(ctx context.Context, tabletType topodatapb. if tabletType == topodatapb.TabletType_DRAINED && agent.Tablet().Type == topodatapb.TabletType_DRAINED { return fmt.Errorf("Tablet: %v, is already drained", agent.TabletAlias) } - // change our type in the topology - _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, tabletType) + + agentMasterTermStartTime := time.Time{} + // If we have been told we're master, set master term start time to Now + if tabletType == topodatapb.TabletType_MASTER { + agentMasterTermStartTime = time.Now() + } + // change our type in the topology, and set masterTermStartTime on tablet record if applicable + _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, tabletType, logutil.TimeToProto(agentMasterTermStartTime)) if err != nil { return err } - - // If we have been told we're master, update master term start time. + // We only update agent's masterTermStartTime if we were able to update the topo. + // This ensures that in case of a failure, we are never in a situation where the + // tablet's timestamp is ahead of the topo's timestamp. if tabletType == topodatapb.TabletType_MASTER { - agent.setMasterTermStartTime(time.Now()) + agent.setMasterTermStartTime(agentMasterTermStartTime) } // let's update our internal state (stop query service and other things) diff --git a/go/vt/vttablet/tabletmanager/rpc_backup.go b/go/vt/vttablet/tabletmanager/rpc_backup.go index 5c10ca512cb..06ad5b66349 100644 --- a/go/vt/vttablet/tabletmanager/rpc_backup.go +++ b/go/vt/vttablet/tabletmanager/rpc_backup.go @@ -84,7 +84,7 @@ func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger lo } originalType = tablet.Type // update our type to BACKUP - if _, err := topotools.ChangeType(ctx, agent.TopoServer, tablet.Alias, topodatapb.TabletType_BACKUP); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, tablet.Alias, topodatapb.TabletType_BACKUP, nil); err != nil { return err } @@ -118,8 +118,9 @@ func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger lo // context. It is also possible that the context already timed out during the // above call to Backup. Thus we use the background context to get through to the finish. - // change our type back to the original value - _, err = topotools.ChangeType(bgCtx, agent.TopoServer, tablet.Alias, originalType) + // Change our type back to the original value. + // Original type could be master so pass in a real value for masterTermStartTime + _, err = topotools.ChangeType(bgCtx, agent.TopoServer, tablet.Alias, originalType, tablet.MasterTermStartTime) if err != nil { // failure in changing the topology type is probably worse, // so returning that (we logged the snapshot error anyway) diff --git a/go/vt/vttablet/tabletmanager/rpc_external_reparent.go b/go/vt/vttablet/tabletmanager/rpc_external_reparent.go index ecd9d4b7361..ced7a719414 100644 --- a/go/vt/vttablet/tabletmanager/rpc_external_reparent.go +++ b/go/vt/vttablet/tabletmanager/rpc_external_reparent.go @@ -28,8 +28,10 @@ import ( "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/topotools/events" "vitess.io/vitess/go/vt/vttablet/tmclient" @@ -106,7 +108,7 @@ func (agent *ActionAgent) TabletExternallyReparented(ctx context.Context, extern // tablet record. The actual record in topo will be updated later. newTablet := proto.Clone(tablet).(*topodatapb.Tablet) newTablet.Type = topodatapb.TabletType_MASTER - + newTablet.MasterTermStartTime = logutil.TimeToProto(agent.masterTermStartTime()) // This is where updateState will block for gracePeriod, while it gives // vtgate a chance to stop sending replica queries. agent.updateState(ctx, newTablet, "fastTabletExternallyReparented") @@ -151,15 +153,7 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context defer wg.Done() log.Infof("finalizeTabletExternallyReparented: updating tablet record for new master: %v", agent.TabletAlias) // Update our own record to master if needed - _, err := agent.TopoServer.UpdateTabletFields(ctx, agent.TabletAlias, - func(tablet *topodatapb.Tablet) error { - if tablet.Type != topodatapb.TabletType_MASTER { - tablet.Type = topodatapb.TabletType_MASTER - return nil - } - // returning NoUpdateNeeded avoids unnecessary calls to UpdateTablet - return topo.NewError(topo.NoUpdateNeeded, agent.TabletAlias.String()) - }) + _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER, logutil.TimeToProto(agent.masterTermStartTime())) if err != nil { errs.RecordError(err) } @@ -174,16 +168,10 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context // Forcibly demote the old master in topology, since we can't rely on the // old master to be up to change its own record. + // Call UpdateTabletFields instead of ChangeType so that we can check the type + // before changing it and avoid unnecessary topo updates var err error - oldMasterTablet, err = agent.TopoServer.UpdateTabletFields(ctx, oldMasterAlias, - func(tablet *topodatapb.Tablet) error { - if tablet.Type == topodatapb.TabletType_MASTER { - tablet.Type = topodatapb.TabletType_REPLICA - return nil - } - // returning NoUpdateNeeded avoids unnecessary calls to UpdateTablet - return topo.NewError(topo.NoUpdateNeeded, oldMasterAlias.String()) - }) + oldMasterTablet, err = topotools.ChangeType(ctx, agent.TopoServer, oldMasterAlias, topodatapb.TabletType_REPLICA, nil) if err != nil { errs.RecordError(err) return @@ -271,14 +259,7 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context go func(alias *topodatapb.TabletAlias) { defer wg.Done() var err error - tab, err := agent.TopoServer.UpdateTabletFields(ctx, alias, - func(tablet *topodatapb.Tablet) error { - if tablet.Type == topodatapb.TabletType_MASTER { - tablet.Type = topodatapb.TabletType_REPLICA - return nil - } - return topo.NewError(topo.NoUpdateNeeded, alias.String()) - }) + tab, err := topotools.ChangeType(ctx, agent.TopoServer, alias, topodatapb.TabletType_REPLICA, nil) if err != nil { errs.RecordError(err) return diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 85cbf96ae58..357ef93da5c 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -21,6 +21,8 @@ import ( "fmt" "time" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -28,7 +30,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" @@ -216,16 +217,16 @@ func (agent *ActionAgent) InitMaster(ctx context.Context) (string, error) { if err := agent.MysqlDaemon.SetReadOnly(false); err != nil { return "", err } - agent.setMasterTermStartTime(startTime) // Change our type to master if not already - if _, err := agent.TopoServer.UpdateTabletFields(ctx, agent.TabletAlias, func(tablet *topodatapb.Tablet) error { - tablet.Type = topodatapb.TabletType_MASTER - return nil - }); err != nil { + _, err = topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER, logutil.TimeToProto(startTime)) + if err != nil { return "", err } - + // We only update agent's masterTermStartTime if we were able to update the topo. + // This ensures that in case of a failure, we are never in a situation where the + // tablet's timestamp is ahead of the topo's timestamp. + agent.setMasterTermStartTime(startTime) // and refresh our state agent.initReplication = true if err := agent.refreshTablet(ctx, "InitMaster"); err != nil { @@ -288,7 +289,7 @@ func (agent *ActionAgent) InitSlave(ctx context.Context, parent *topodatapb.Tabl // is used on the old master when using InitShardMaster with // -force, and the new master is different from the old master. if agent.Tablet().Type == topodatapb.TabletType_MASTER { - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_REPLICA, nil); err != nil { return err } @@ -479,11 +480,15 @@ func (agent *ActionAgent) PromoteSlaveWhenCaughtUp(ctx context.Context, position if err := agent.MysqlDaemon.SetReadOnly(false); err != nil { return "", err } - agent.setMasterTermStartTime(startTime) - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER); err != nil { + _, err = topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER, logutil.TimeToProto(startTime)) + if err != nil { return "", err } + // We only update agent's masterTermStartTime if we were able to update the topo. + // This ensures that in case of a failure, we are never in a situation where the + // tablet's timestamp is ahead of the topo's timestamp. + agent.setMasterTermStartTime(startTime) if err := agent.refreshTablet(ctx, "PromoteSlaveWhenCaughtUp"); err != nil { return "", err @@ -498,10 +503,15 @@ func (agent *ActionAgent) SlaveWasPromoted(ctx context.Context) error { return err } defer agent.unlock() + startTime := time.Now() - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER, logutil.TimeToProto(startTime)); err != nil { return err } + // We only update agent's masterTermStartTime if we were able to update the topo. + // This ensures that in case of a failure, we are never in a situation where the + // tablet's timestamp is ahead of the topo's timestamp. + agent.setMasterTermStartTime(startTime) if err := agent.refreshTablet(ctx, "SlaveWasPromoted"); err != nil { return err @@ -567,9 +577,12 @@ func (agent *ActionAgent) setMasterLocked(ctx context.Context, parentAlias *topo // Being sent SetMaster means another MASTER has been successfully promoted, // so we convert to REPLICA first, since we want to do it even if other // steps fail below. + // Note it is important to check for MASTER here so that we don't + // unintentionally change the type of RDONLY tablets _, err = agent.TopoServer.UpdateTabletFields(ctx, agent.TabletAlias, func(tablet *topodatapb.Tablet) error { if tablet.Type == topodatapb.TabletType_MASTER { tablet.Type = topodatapb.TabletType_REPLICA + tablet.MasterTermStartTime = nil return nil } return topo.NewError(topo.NoUpdateNeeded, agent.TabletAlias.String()) @@ -653,12 +666,13 @@ func (agent *ActionAgent) SlaveWasRestarted(ctx context.Context, parent *topodat } defer agent.unlock() + // Only change type of former MASTER tablets. + // Don't change type of RDONLY typeChanged := false - - // Once this action completes, update authoritative tablet node first. if _, err := agent.TopoServer.UpdateTabletFields(ctx, agent.TabletAlias, func(tablet *topodatapb.Tablet) error { if tablet.Type == topodatapb.TabletType_MASTER { tablet.Type = topodatapb.TabletType_REPLICA + tablet.MasterTermStartTime = nil typeChanged = true return nil } @@ -726,11 +740,14 @@ func (agent *ActionAgent) PromoteSlave(ctx context.Context) (string, error) { if err := agent.MysqlDaemon.SetReadOnly(false); err != nil { return "", err } - agent.setMasterTermStartTime(startTime) - if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER); err != nil { + if _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, topodatapb.TabletType_MASTER, logutil.TimeToProto(startTime)); err != nil { return "", err } + // We only update agent's masterTermStartTime if we were able to update the topo. + // This ensures that in case of a failure, we are never in a situation where the + // tablet's timestamp is ahead of the topo's timestamp. + agent.setMasterTermStartTime(startTime) if err := agent.refreshTablet(ctx, "PromoteSlave"); err != nil { return "", err diff --git a/go/vt/vttablet/tabletmanager/state_change.go b/go/vt/vttablet/tabletmanager/state_change.go index fdae444672e..ad921cd8cf8 100644 --- a/go/vt/vttablet/tabletmanager/state_change.go +++ b/go/vt/vttablet/tabletmanager/state_change.go @@ -29,6 +29,7 @@ import ( "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -153,7 +154,10 @@ func (agent *ActionAgent) refreshTablet(ctx context.Context, reason string) erro if updatedTablet := agent.checkTabletMysqlPort(ctx, tablet); updatedTablet != nil { tablet = updatedTablet } - + // Also refresh masterTermStartTime + if tablet.MasterTermStartTime != nil { + agent.setMasterTermStartTime(logutil.ProtoToTime(tablet.MasterTermStartTime)) + } agent.updateState(ctx, tablet, reason) log.Infof("Done with post-action state refresh") return nil diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index e58ae3618db..73de8b98f09 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -28,40 +28,6 @@ import ( // shard related methods for Wrangler -// updateShardCellsAndMaster will update the 'Cells' and possibly -// MasterAlias records for the shard, if needed. -func (wr *Wrangler) updateShardMaster(ctx context.Context, si *topo.ShardInfo, tabletAlias *topodatapb.TabletAlias, tabletType topodatapb.TabletType, allowMasterOverride bool) error { - // See if we need to update the Shard: - // - add the tablet's cell to the shard's Cells if needed - // - change the master if needed - shardUpdateRequired := false - if tabletType == topodatapb.TabletType_MASTER && !topoproto.TabletAliasEqual(si.MasterAlias, tabletAlias) { - shardUpdateRequired = true - } - if !shardUpdateRequired { - return nil - } - - // run the update - _, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(s *topo.ShardInfo) error { - wasUpdated := false - - if tabletType == topodatapb.TabletType_MASTER && !topoproto.TabletAliasEqual(s.MasterAlias, tabletAlias) { - if !topoproto.TabletAliasIsZero(s.MasterAlias) && !allowMasterOverride { - return fmt.Errorf("creating this tablet would override old master %v in shard %v/%v", topoproto.TabletAliasString(s.MasterAlias), si.Keyspace(), si.ShardName()) - } - s.MasterAlias = tabletAlias - wasUpdated = true - } - - if !wasUpdated { - return topo.NewError(topo.NoUpdateNeeded, si.Keyspace()+"/"+si.ShardName()) - } - return nil - }) - return err -} - // SetShardIsMasterServing changes the IsMasterServing parameter of a shard. // It does not rebuild any serving graph or do any consistency check. // This is an emergency manual operation. diff --git a/go/vt/wrangler/tablet.go b/go/vt/wrangler/tablet.go index 3f22a67081b..fab0ab2d089 100644 --- a/go/vt/wrangler/tablet.go +++ b/go/vt/wrangler/tablet.go @@ -18,9 +18,11 @@ package wrangler import ( "fmt" + "time" "golang.org/x/net/context" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" @@ -70,9 +72,10 @@ func (wr *Wrangler) InitTablet(ctx context.Context, tablet *topodatapb.Tablet, a return fmt.Errorf("creating this tablet would override old master %v in shard %v/%v, use allow_master_override flag", topoproto.TabletAliasString(si.MasterAlias), tablet.Keyspace, tablet.Shard) } - // update the shard record if needed - if err := wr.updateShardMaster(ctx, si, tablet.Alias, tablet.Type, allowMasterOverride); err != nil { - return err + if tablet.Type == topodatapb.TabletType_MASTER { + // we update master_term_start_time even if the master hasn't changed + // because that means a new master term with the same master + tablet.MasterTermStartTime = logutil.TimeToProto(time.Now()) } err = wr.ts.CreateTablet(ctx, tablet) @@ -88,7 +91,6 @@ func (wr *Wrangler) InitTablet(ctx context.Context, tablet *topodatapb.Tablet, a if oldTablet.Keyspace != tablet.Keyspace || oldTablet.Shard != tablet.Shard { return fmt.Errorf("old tablet has shard %v/%v. Cannot override with shard %v/%v. Delete and re-add tablet if you want to change the tablet's keyspace/shard", oldTablet.Keyspace, oldTablet.Shard, tablet.Keyspace, tablet.Shard) } - *(oldTablet.Tablet) = *tablet if err := wr.ts.UpdateTablet(ctx, oldTablet); err != nil { return fmt.Errorf("failed updating tablet %v: %v", topoproto.TabletAliasString(tablet.Alias), err) diff --git a/go/vt/wrangler/testlib/external_reparent_test.go b/go/vt/wrangler/testlib/external_reparent_test.go index 4bf726d223e..5fbfd239f5e 100644 --- a/go/vt/wrangler/testlib/external_reparent_test.go +++ b/go/vt/wrangler/testlib/external_reparent_test.go @@ -100,30 +100,24 @@ func TestTabletExternallyReparentedBasic(t *testing.T) { } // We have to wait for shard sync to do its magic in the background - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - -loop: + startTime := time.Now() for { - select { - case <-timer.C: - // we timed out + if time.Since(startTime) > 10*time.Second /* timeout */ { tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) if err != nil { t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) } t.Fatalf("old master (%v) should be replica but is: %v", topoproto.TabletAliasString(oldMaster.Tablet.Alias), tablet.Type) - default: - // check the old master was converted to replica - tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) - if err != nil { - t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) - } - if tablet.Type != topodatapb.TabletType_REPLICA { - time.Sleep(100 * time.Millisecond) - } else { - break loop - } + } + // check the old master was converted to replica + tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) + if err != nil { + t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) + } + if tablet.Type == topodatapb.TabletType_REPLICA { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to check again */) } } } @@ -179,30 +173,24 @@ func TestTabletExternallyReparentedToSlave(t *testing.T) { } // We have to wait for shard sync to do its magic in the background - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - -loop: + startTime := time.Now() for { - select { - case <-timer.C: - // we timed out + if time.Since(startTime) > 10*time.Second /* timeout */ { tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) if err != nil { t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) } t.Fatalf("old master (%v) should be replica but is: %v", topoproto.TabletAliasString(oldMaster.Tablet.Alias), tablet.Type) - default: - // check the old master was converted to replica - tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) - if err != nil { - t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) - } - if tablet.Type != topodatapb.TabletType_REPLICA { - time.Sleep(100 * time.Millisecond) - } else { - break loop - } + } + // check the old master was converted to replica + tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) + if err != nil { + t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) + } + if tablet.Type == topodatapb.TabletType_REPLICA { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to check again */) } } } @@ -265,30 +253,24 @@ func TestTabletExternallyReparentedWithDifferentMysqlPort(t *testing.T) { } // We have to wait for shard sync to do its magic in the background - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - -loop: + startTime := time.Now() for { - select { - case <-timer.C: - // we timed out + if time.Since(startTime) > 10*time.Second /* timeout */ { tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) if err != nil { t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) } t.Fatalf("old master (%v) should be replica but is: %v", topoproto.TabletAliasString(oldMaster.Tablet.Alias), tablet.Type) - default: - // check the old master was converted to replica - tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) - if err != nil { - t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) - } - if tablet.Type != topodatapb.TabletType_REPLICA { - time.Sleep(100 * time.Millisecond) - } else { - break loop - } + } + // check the old master was converted to replica + tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) + if err != nil { + t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) + } + if tablet.Type == topodatapb.TabletType_REPLICA { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to check again */) } } } @@ -345,30 +327,24 @@ func TestTabletExternallyReparentedContinueOnUnexpectedMaster(t *testing.T) { t.Fatalf("new master should be MASTER but is: %v", tablet.Type) } // We have to wait for shard sync to do its magic in the background - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - -loop: + startTime := time.Now() for { - select { - case <-timer.C: - // we timed out + if time.Since(startTime) > 10*time.Second /* timeout */ { tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) if err != nil { t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) } t.Fatalf("old master (%v) should be replica but is: %v", topoproto.TabletAliasString(oldMaster.Tablet.Alias), tablet.Type) - default: - // check the old master was converted to replica - tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) - if err != nil { - t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) - } - if tablet.Type != topodatapb.TabletType_REPLICA { - time.Sleep(100 * time.Millisecond) - } else { - break loop - } + } + // check the old master was converted to replica + tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) + if err != nil { + t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) + } + if tablet.Type == topodatapb.TabletType_REPLICA { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to check again */) } } } @@ -424,30 +400,24 @@ func TestTabletExternallyReparentedRerun(t *testing.T) { } // We have to wait for shard sync to do its magic in the background - timer := time.NewTimer(10 * time.Second) - defer timer.Stop() - -loop: + startTime := time.Now() for { - select { - case <-timer.C: - // we timed out + if time.Since(startTime) > 10*time.Second /* timeout */ { tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) if err != nil { t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) } t.Fatalf("old master (%v) should be replica but is: %v", topoproto.TabletAliasString(oldMaster.Tablet.Alias), tablet.Type) - default: - // check the old master was converted to replica - tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) - if err != nil { - t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) - } - if tablet.Type != topodatapb.TabletType_REPLICA { - time.Sleep(100 * time.Millisecond) - } else { - break loop - } + } + // check the old master was converted to replica + tablet, err = ts.GetTablet(ctx, oldMaster.Tablet.Alias) + if err != nil { + t.Fatalf("GetTablet(%v) failed: %v", oldMaster.Tablet.Alias, err) + } + if tablet.Type == topodatapb.TabletType_REPLICA { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to check again */) } } diff --git a/go/vt/wrangler/testlib/init_shard_master_test.go b/go/vt/wrangler/testlib/init_shard_master_test.go index 8f10a297c16..73e5c2d7cfa 100644 --- a/go/vt/wrangler/testlib/init_shard_master_test.go +++ b/go/vt/wrangler/testlib/init_shard_master_test.go @@ -78,6 +78,29 @@ func TestInitMasterShard(t *testing.T) { master.StartActionLoop(t, wr) defer master.StopActionLoop(t) + // wait for shard record to be updated with master + startTime := time.Now() + for { + if time.Since(startTime) > 10*time.Second /* timeout */ { + si, err := ts.GetShard(ctx, master.Tablet.Keyspace, master.Tablet.Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", master.Tablet.Keyspace, master.Tablet.Shard, err) + } + if !topoproto.TabletAliasEqual(si.MasterAlias, master.Tablet.Alias) { + t.Fatalf("ShardInfo should have MasterAlias %v but has %v", topoproto.TabletAliasString(master.Tablet.Alias), topoproto.TabletAliasString(si.MasterAlias)) + } + } + si, err := ts.GetShard(ctx, master.Tablet.Keyspace, master.Tablet.Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", master.Tablet.Keyspace, master.Tablet.Shard, err) + } + if topoproto.TabletAliasEqual(si.MasterAlias, master.Tablet.Alias) { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to re-check the shard record */) + } + } + // Slave1: expect to be reset and re-parented goodSlave1.FakeMysqlDaemon.ReadOnly = true goodSlave1.FakeMysqlDaemon.SetSlavePositionPos = master.FakeMysqlDaemon.CurrentMasterPosition @@ -155,7 +178,8 @@ func TestInitMasterShardChecks(t *testing.T) { // (master2 needs to run InitTablet with -force, as it is the second // master in the same shard) master2 := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_MASTER, db, ForceInitTablet()) - if err := wr.InitShardMaster(ctx, master2.Tablet.Keyspace, master2.Tablet.Shard, master2.Tablet.Alias, false /*force*/, 10*time.Second); err == nil || !strings.Contains(err.Error(), "is not the only master in the shard") { + + if err := wr.InitShardMaster(ctx, master2.Tablet.Keyspace, master2.Tablet.Shard, master2.Tablet.Alias, false /*force*/, 10*time.Second); err == nil || !strings.Contains(err.Error(), "is not the shard master") { t.Errorf("InitShardMaster with two masters returned wrong error: %v", err) } @@ -208,6 +232,29 @@ func TestInitMasterShardOneSlaveFails(t *testing.T) { master.StartActionLoop(t, wr) defer master.StopActionLoop(t) + // wait for shard record to be updated with master + startTime := time.Now() + for { + if time.Since(startTime) > 10*time.Second /* timeout */ { + si, err := ts.GetShard(ctx, master.Tablet.Keyspace, master.Tablet.Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", master.Tablet.Keyspace, master.Tablet.Shard, err) + } + if !topoproto.TabletAliasEqual(si.MasterAlias, master.Tablet.Alias) { + t.Fatalf("ShardInfo should have MasterAlias %v but has %v", topoproto.TabletAliasString(master.Tablet.Alias), topoproto.TabletAliasString(si.MasterAlias)) + } + } + si, err := ts.GetShard(ctx, master.Tablet.Keyspace, master.Tablet.Shard) + if err != nil { + t.Fatalf("GetShard(%v, %v) failed: %v", master.Tablet.Keyspace, master.Tablet.Shard, err) + } + if topoproto.TabletAliasEqual(si.MasterAlias, master.Tablet.Alias) { + break + } else { + time.Sleep(100 * time.Millisecond /* interval at which to re-check the shard record */) + } + } + // goodSlave: expect to be re-parented goodSlave.FakeMysqlDaemon.ReadOnly = true goodSlave.FakeMysqlDaemon.SetSlavePositionPos = master.FakeMysqlDaemon.CurrentMasterPosition diff --git a/proto/topodata.proto b/proto/topodata.proto index 59d05ac5073..92beffb4f08 100644 --- a/proto/topodata.proto +++ b/proto/topodata.proto @@ -158,6 +158,17 @@ message Tablet { // for legacy behavior. int32 mysql_port = 13; + // master_term_start_time is the time (in UTC) at which the current term of + // the current tablet began as master. If this tablet is not currently the + // master, this value is ignored. + // + // A new master term begins any time an authoritative decision is communicated + // about which tablet should be the master, such as via Vitess + // replication-management commands like PlannedReparentShard, + // EmergencyReparentShard, and TabletExternallyReparented. + // + vttime.Time master_term_start_time = 14; + // OBSOLETE: ip and tablet health information // string ip = 3; // map health_map = 11; diff --git a/py/vtproto/topodata_pb2.py b/py/vtproto/topodata_pb2.py index 6d22e359669..4947f3dff6a 100644 --- a/py/vtproto/topodata_pb2.py +++ b/py/vtproto/topodata_pb2.py @@ -21,7 +21,7 @@ package='topodata', syntax='proto3', serialized_options=_b('\n\017io.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodata'), - serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\x1a\ntime.proto\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xb6\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\x81\x05\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12,\n\x16master_term_start_time\x18\x08 \x01(\x0b\x32\x0c.vttime.Time\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x30\n\x0cserved_types\x18\x03 \x03(\x0b\x32\x1a.topodata.Shard.ServedType\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x12\x19\n\x11is_master_serving\x18\x07 \x01(\x08\x1a\x46\n\nServedType\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a{\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08J\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06\"\xe0\x02\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x12-\n\rkeyspace_type\x18\x05 \x01(\x0e\x32\x16.topodata.KeyspaceType\x12\x15\n\rbase_keyspace\x18\x06 \x01(\t\x12#\n\rsnapshot_time\x18\x07 \x01(\x0b\x32\x0c.vttime.Time\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"i\n\x12ShardTabletControl\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x1e\n\x16query_service_disabled\x18\x03 \x01(\x08\"\xda\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1a\xaf\x01\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x12;\n\x15shard_tablet_controls\x18\x03 \x03(\x0b\x32\x1c.topodata.ShardTabletControl\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"6\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tJ\x04\x08\x03\x10\x04\"\x1b\n\nCellsAlias\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t*(\n\x0cKeyspaceType\x12\n\n\x06NORMAL\x10\x00\x12\x0c\n\x08SNAPSHOT\x10\x01*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') + serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\x1a\ntime.proto\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xe4\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x12,\n\x16master_term_start_time\x18\x0e \x01(\x0b\x32\x0c.vttime.Time\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\x81\x05\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12,\n\x16master_term_start_time\x18\x08 \x01(\x0b\x32\x0c.vttime.Time\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x30\n\x0cserved_types\x18\x03 \x03(\x0b\x32\x1a.topodata.Shard.ServedType\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x12\x19\n\x11is_master_serving\x18\x07 \x01(\x08\x1a\x46\n\nServedType\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a{\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08J\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06\"\xe0\x02\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x12-\n\rkeyspace_type\x18\x05 \x01(\x0e\x32\x16.topodata.KeyspaceType\x12\x15\n\rbase_keyspace\x18\x06 \x01(\t\x12#\n\rsnapshot_time\x18\x07 \x01(\x0b\x32\x0c.vttime.Time\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"i\n\x12ShardTabletControl\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x1e\n\x16query_service_disabled\x18\x03 \x01(\x08\"\xda\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1a\xaf\x01\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x12;\n\x15shard_tablet_controls\x18\x03 \x03(\x0b\x32\x1c.topodata.ShardTabletControl\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"6\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\tJ\x04\x08\x03\x10\x04\"\x1b\n\nCellsAlias\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t*(\n\x0cKeyspaceType\x12\n\n\x06NORMAL\x10\x00\x12\x0c\n\x08SNAPSHOT\x10\x01*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') , dependencies=[time__pb2.DESCRIPTOR,]) @@ -42,8 +42,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2423, - serialized_end=2463, + serialized_start=2469, + serialized_end=2509, ) _sym_db.RegisterEnumDescriptor(_KEYSPACETYPE) @@ -69,8 +69,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2465, - serialized_end=2515, + serialized_start=2511, + serialized_end=2561, ) _sym_db.RegisterEnumDescriptor(_KEYSPACEIDTYPE) @@ -124,8 +124,8 @@ ], containing_type=None, serialized_options=_b('\020\001'), - serialized_start=2518, - serialized_end=2662, + serialized_start=2564, + serialized_end=2708, ) _sym_db.RegisterEnumDescriptor(_TABLETTYPE) @@ -257,8 +257,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=458, - serialized_end=504, + serialized_start=504, + serialized_end=550, ) _TABLET_TAGSENTRY = _descriptor.Descriptor( @@ -294,8 +294,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=506, - serialized_end=549, + serialized_start=552, + serialized_end=595, ) _TABLET = _descriptor.Descriptor( @@ -382,6 +382,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='master_term_start_time', full_name='topodata.Tablet.master_term_start_time', index=11, + number=14, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -395,7 +402,7 @@ oneofs=[ ], serialized_start=123, - serialized_end=561, + serialized_end=607, ) @@ -432,8 +439,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=888, - serialized_end=958, + serialized_start=934, + serialized_end=1004, ) _SHARD_SOURCESHARD = _descriptor.Descriptor( @@ -490,8 +497,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=960, - serialized_end=1074, + serialized_start=1006, + serialized_end=1120, ) _SHARD_TABLETCONTROL = _descriptor.Descriptor( @@ -541,8 +548,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1076, - serialized_end=1199, + serialized_start=1122, + serialized_end=1245, ) _SHARD = _descriptor.Descriptor( @@ -613,8 +620,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=564, - serialized_end=1205, + serialized_start=610, + serialized_end=1251, ) @@ -658,8 +665,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1466, - serialized_end=1554, + serialized_start=1512, + serialized_end=1600, ) _KEYSPACE = _descriptor.Descriptor( @@ -723,8 +730,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1208, - serialized_end=1560, + serialized_start=1254, + serialized_end=1606, ) @@ -754,8 +761,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1630, - serialized_end=1681, + serialized_start=1676, + serialized_end=1727, ) _SHARDREPLICATION = _descriptor.Descriptor( @@ -784,8 +791,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1562, - serialized_end=1681, + serialized_start=1608, + serialized_end=1727, ) @@ -822,8 +829,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1683, - serialized_end=1752, + serialized_start=1729, + serialized_end=1798, ) @@ -867,8 +874,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1754, - serialized_end=1859, + serialized_start=1800, + serialized_end=1905, ) @@ -912,8 +919,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2080, - serialized_end=2255, + serialized_start=2126, + serialized_end=2301, ) _SRVKEYSPACE_SERVEDFROM = _descriptor.Descriptor( @@ -949,8 +956,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2257, - serialized_end=2330, + serialized_start=2303, + serialized_end=2376, ) _SRVKEYSPACE = _descriptor.Descriptor( @@ -1000,8 +1007,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1862, - serialized_end=2336, + serialized_start=1908, + serialized_end=2382, ) @@ -1038,8 +1045,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2338, - serialized_end=2392, + serialized_start=2384, + serialized_end=2438, ) @@ -1069,8 +1076,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2394, - serialized_end=2421, + serialized_start=2440, + serialized_end=2467, ) _TABLET_PORTMAPENTRY.containing_type = _TABLET @@ -1080,6 +1087,7 @@ _TABLET.fields_by_name['key_range'].message_type = _KEYRANGE _TABLET.fields_by_name['type'].enum_type = _TABLETTYPE _TABLET.fields_by_name['tags'].message_type = _TABLET_TAGSENTRY +_TABLET.fields_by_name['master_term_start_time'].message_type = time__pb2._TIME _SHARD_SERVEDTYPE.fields_by_name['tablet_type'].enum_type = _TABLETTYPE _SHARD_SERVEDTYPE.containing_type = _SHARD _SHARD_SOURCESHARD.fields_by_name['key_range'].message_type = _KEYRANGE diff --git a/py/vtproto/vtrpc_pb2.py b/py/vtproto/vtrpc_pb2.py index 5c9cfc4cc6a..39c07d0a732 100644 --- a/py/vtproto/vtrpc_pb2.py +++ b/py/vtproto/vtrpc_pb2.py @@ -8,7 +8,6 @@ from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -20,6 +19,7 @@ name='vtrpc.proto', package='vtrpc', syntax='proto3', + serialized_options=_b('\n\017io.vitess.protoZ\"vitess.io/vitess/go/vt/proto/vtrpc'), serialized_pb=_b('\n\x0bvtrpc.proto\x12\x05vtrpc\"F\n\x08\x43\x61llerID\x12\x11\n\tprincipal\x18\x01 \x01(\t\x12\x11\n\tcomponent\x18\x02 \x01(\t\x12\x14\n\x0csubcomponent\x18\x03 \x01(\t\"c\n\x08RPCError\x12+\n\x0blegacy_code\x18\x01 \x01(\x0e\x32\x16.vtrpc.LegacyErrorCode\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x19\n\x04\x63ode\x18\x03 \x01(\x0e\x32\x0b.vtrpc.Code*\xb6\x02\n\x04\x43ode\x12\x06\n\x02OK\x10\x00\x12\x0c\n\x08\x43\x41NCELED\x10\x01\x12\x0b\n\x07UNKNOWN\x10\x02\x12\x14\n\x10INVALID_ARGUMENT\x10\x03\x12\x15\n\x11\x44\x45\x41\x44LINE_EXCEEDED\x10\x04\x12\r\n\tNOT_FOUND\x10\x05\x12\x12\n\x0e\x41LREADY_EXISTS\x10\x06\x12\x15\n\x11PERMISSION_DENIED\x10\x07\x12\x13\n\x0fUNAUTHENTICATED\x10\x10\x12\x16\n\x12RESOURCE_EXHAUSTED\x10\x08\x12\x17\n\x13\x46\x41ILED_PRECONDITION\x10\t\x12\x0b\n\x07\x41\x42ORTED\x10\n\x12\x10\n\x0cOUT_OF_RANGE\x10\x0b\x12\x11\n\rUNIMPLEMENTED\x10\x0c\x12\x0c\n\x08INTERNAL\x10\r\x12\x0f\n\x0bUNAVAILABLE\x10\x0e\x12\r\n\tDATA_LOSS\x10\x0f*\xe8\x02\n\x0fLegacyErrorCode\x12\x12\n\x0eSUCCESS_LEGACY\x10\x00\x12\x14\n\x10\x43\x41NCELLED_LEGACY\x10\x01\x12\x18\n\x14UNKNOWN_ERROR_LEGACY\x10\x02\x12\x14\n\x10\x42\x41\x44_INPUT_LEGACY\x10\x03\x12\x1c\n\x18\x44\x45\x41\x44LINE_EXCEEDED_LEGACY\x10\x04\x12\x1a\n\x16INTEGRITY_ERROR_LEGACY\x10\x05\x12\x1c\n\x18PERMISSION_DENIED_LEGACY\x10\x06\x12\x1d\n\x19RESOURCE_EXHAUSTED_LEGACY\x10\x07\x12\x1b\n\x17QUERY_NOT_SERVED_LEGACY\x10\x08\x12\x14\n\x10NOT_IN_TX_LEGACY\x10\t\x12\x19\n\x15INTERNAL_ERROR_LEGACY\x10\n\x12\x1a\n\x16TRANSIENT_ERROR_LEGACY\x10\x0b\x12\x1a\n\x16UNAUTHENTICATED_LEGACY\x10\x0c\x42\x35\n\x0fio.vitess.protoZ\"vitess.io/vitess/go/vt/proto/vtrpcb\x06proto3') ) @@ -31,75 +31,75 @@ values=[ _descriptor.EnumValueDescriptor( name='OK', index=0, number=0, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='CANCELED', index=1, number=1, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNKNOWN', index=2, number=2, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='INVALID_ARGUMENT', index=3, number=3, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='DEADLINE_EXCEEDED', index=4, number=4, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='NOT_FOUND', index=5, number=5, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='ALREADY_EXISTS', index=6, number=6, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='PERMISSION_DENIED', index=7, number=7, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNAUTHENTICATED', index=8, number=16, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='RESOURCE_EXHAUSTED', index=9, number=8, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='FAILED_PRECONDITION', index=10, number=9, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='ABORTED', index=11, number=10, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='OUT_OF_RANGE', index=12, number=11, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNIMPLEMENTED', index=13, number=12, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='INTERNAL', index=14, number=13, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNAVAILABLE', index=15, number=14, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='DATA_LOSS', index=16, number=15, - options=None, + serialized_options=None, type=None), ], containing_type=None, - options=None, + serialized_options=None, serialized_start=196, serialized_end=506, ) @@ -114,59 +114,59 @@ values=[ _descriptor.EnumValueDescriptor( name='SUCCESS_LEGACY', index=0, number=0, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='CANCELLED_LEGACY', index=1, number=1, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNKNOWN_ERROR_LEGACY', index=2, number=2, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='BAD_INPUT_LEGACY', index=3, number=3, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='DEADLINE_EXCEEDED_LEGACY', index=4, number=4, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='INTEGRITY_ERROR_LEGACY', index=5, number=5, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='PERMISSION_DENIED_LEGACY', index=6, number=6, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='RESOURCE_EXHAUSTED_LEGACY', index=7, number=7, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='QUERY_NOT_SERVED_LEGACY', index=8, number=8, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='NOT_IN_TX_LEGACY', index=9, number=9, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='INTERNAL_ERROR_LEGACY', index=10, number=10, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='TRANSIENT_ERROR_LEGACY', index=11, number=11, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='UNAUTHENTICATED_LEGACY', index=12, number=12, - options=None, + serialized_options=None, type=None), ], containing_type=None, - options=None, + serialized_options=None, serialized_start=509, serialized_end=869, ) @@ -219,28 +219,28 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='component', full_name='vtrpc.CallerID.component', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='subcomponent', full_name='vtrpc.CallerID.subcomponent', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -264,28 +264,28 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='message', full_name='vtrpc.RPCError.message', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='code', full_name='vtrpc.RPCError.code', index=2, number=3, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -318,6 +318,5 @@ _sym_db.RegisterMessage(RPCError) -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\017io.vitess.protoZ\"vitess.io/vitess/go/vt/proto/vtrpc')) +DESCRIPTOR._options = None # @@protoc_insertion_point(module_scope) diff --git a/test/tabletmanager.py b/test/tabletmanager.py index 706034663c8..f191e024220 100755 --- a/test/tabletmanager.py +++ b/test/tabletmanager.py @@ -100,8 +100,6 @@ def _test_sanity(self): utils.run_vtctl(['createshard', '-force', 'test_keyspace/0']) tablet_62344.init_tablet('master', 'test_keyspace', '0', parent=False) utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace']) - utils.validate_topology() - # if these statements don't run before the tablet it will wedge # waiting for the db to become accessible. this is more a bug than # a feature. @@ -109,6 +107,8 @@ def _test_sanity(self): self._populate_vt_select_test) tablet_62344.start_vttablet() + utils.validate_topology() + # make sure the query service is started right away. qr = tablet_62344.execute('select id, msg from vt_select_test') @@ -202,9 +202,18 @@ def test_actions_and_timeouts(self): utils.run_vtctl(['CreateKeyspace', 'test_keyspace']) tablet_62344.init_tablet('master', 'test_keyspace', '0') - utils.validate_topology() tablet_62344.create_db('vt_test_keyspace') tablet_62344.start_vttablet() + # validate topology after starting tablet so that tablet has a chance + # to update shard master_alias + timeout = 10 + while True: + shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/0']) + if shard['master_alias']['uid'] == 62344: + break + wait_step('master_alias has been set', timeout) + + utils.validate_topology() utils.run_vtctl(['Ping', tablet_62344.tablet_alias]) @@ -759,7 +768,7 @@ def test_master_restart_sets_ter_timestamp(self): init_keyspace='test_keyspace', init_shard='0') - # Make sure that the TER increased i.e. it was set to the current time. + # Make sure that the TER did not change health_after_restart = utils.run_vtctl_json(['VtTabletStreamHealth', '-count', '1', master.tablet_alias]) @@ -767,11 +776,11 @@ def test_master_restart_sets_ter_timestamp(self): health_after_restart['target']['tablet_type']) self.assertIn('tablet_externally_reparented_timestamp', health_after_restart) - self.assertGreater( + self.assertEqual( health_after_restart['tablet_externally_reparented_timestamp'], health['tablet_externally_reparented_timestamp'], 'When the MASTER vttablet was restarted, the TER timestamp must be set' - ' to the current time.') + ' by reading the old value from the tablet record. Old: %s, New: %s' % (str(health['tablet_externally_reparented_timestamp']), str(health_after_restart['tablet_externally_reparented_timestamp']))) # Shutdown. for t in tablets: @@ -788,8 +797,6 @@ def test_topocustomrule(self): utils.run_vtctl(['createshard', '-force', 'test_keyspace/0']) tablet_62344.init_tablet('master', 'test_keyspace', '0', parent=False) utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace']) - utils.validate_topology() - # Copy config file into topo. topocustomrule_path = '/keyspaces/test_keyspace/configs/CustomRules' utils.run_vtctl(['TopoCp', '-to_topo', topocustomrule_file, @@ -800,6 +807,8 @@ def test_topocustomrule(self): self._populate_vt_select_test) tablet_62344.start_vttablet(topocustomrule_path=topocustomrule_path) + utils.validate_topology() + # make sure the query service is working qr = tablet_62344.execute('select id, msg from vt_select_test') self.assertEqual(len(qr['rows']), 4, diff --git a/test/worker.py b/test/worker.py index 5c51f811289..9ea02b3c3b9 100755 --- a/test/worker.py +++ b/test/worker.py @@ -217,6 +217,12 @@ def run_shard_tablets( utils.run_vtctl( ['InitShardMaster', '-force', 'test_keyspace/%s' % shard_name, shard_tablets.master.tablet_alias], auto_log=True) + timeout = 10 + while True: + shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/%s' % shard_name]) + if shard['master_alias']['uid'] == shard_tablets.master.tablet_uid: + break + wait_step('master_alias has been set', timeout) utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) # Enforce a health check instead of waiting for the next periodic one.