diff --git a/go/cmd/vtorc/cli/cli.go b/go/cmd/vtorc/cli/cli.go index 7e65121c155..86e00633d57 100644 --- a/go/cmd/vtorc/cli/cli.go +++ b/go/cmd/vtorc/cli/cli.go @@ -59,6 +59,10 @@ func run(cmd *cobra.Command, args []string) { inst.EnableAuditSyslog() } config.MarkConfigurationLoaded() + if err := config.Validate(); err != nil { + log.Error(fmt.Sprintf("Failed to validate config: %+v", err)) + os.Exit(1) + } // Log final config values to debug if something goes wrong. log.Info(fmt.Sprintf("Running with Configuration - %v", debug.AllSettings())) diff --git a/go/flags/endtoend/vtorc.txt b/go/flags/endtoend/vtorc.txt index df6d1952764..f88e1686982 100644 --- a/go/flags/endtoend/vtorc.txt +++ b/go/flags/endtoend/vtorc.txt @@ -109,4 +109,6 @@ Flags: --topo-zk-tls-cert string the cert to use to connect to the zk topo server, requires topo-zk-tls-key, enables TLS --topo-zk-tls-key string the key to use to connect to the zk topo server, enables TLS -v, --version print binary version + --wait-for-relaylogs-mode string Specifies the number of tablets to wait for relaylog applying during an EmergencyReparentShard action. ALL: wait for all tablets, MAJORITY: wait for a majority of tablets, COUNT: wait for an exact number of tablets (using --wait-for-relaylogs-tablet-count flag) (default "ALL") + --wait-for-relaylogs-tablet-count int Specifies the exact number of tablets to wait for relaylogs during EmergencyReparentShard actions. This setting must be > 0 when --wait-for-relaylogs-mode=COUNT is set --wait-replicas-timeout duration Duration for which to wait for replica's to respond when issuing RPCs (default 30s) diff --git a/go/vt/proto/replicationdata/replicationdata.pb.go b/go/vt/proto/replicationdata/replicationdata.pb.go index fc5e581437b..bed1ba62d5f 100644 --- a/go/vt/proto/replicationdata/replicationdata.pb.go +++ b/go/vt/proto/replicationdata/replicationdata.pb.go @@ -86,6 +86,60 @@ func (StopReplicationMode) EnumDescriptor() ([]byte, []int) { return file_replicationdata_proto_rawDescGZIP(), []int{0} } +// WaitForRelayLogsMode represents what approach to use for deciding the number +// of tablets to for the wait-for-relaylogs phase of EmergencyReparentShard. +type WaitForRelayLogsMode int32 + +const ( + WaitForRelayLogsMode_DEFAULT WaitForRelayLogsMode = 0 + WaitForRelayLogsMode_ALL WaitForRelayLogsMode = 1 + WaitForRelayLogsMode_MAJORITY WaitForRelayLogsMode = 2 + WaitForRelayLogsMode_COUNT WaitForRelayLogsMode = 3 +) + +// Enum value maps for WaitForRelayLogsMode. +var ( + WaitForRelayLogsMode_name = map[int32]string{ + 0: "DEFAULT", + 1: "ALL", + 2: "MAJORITY", + 3: "COUNT", + } + WaitForRelayLogsMode_value = map[string]int32{ + "DEFAULT": 0, + "ALL": 1, + "MAJORITY": 2, + "COUNT": 3, + } +) + +func (x WaitForRelayLogsMode) Enum() *WaitForRelayLogsMode { + p := new(WaitForRelayLogsMode) + *p = x + return p +} + +func (x WaitForRelayLogsMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WaitForRelayLogsMode) Descriptor() protoreflect.EnumDescriptor { + return file_replicationdata_proto_enumTypes[1].Descriptor() +} + +func (WaitForRelayLogsMode) Type() protoreflect.EnumType { + return &file_replicationdata_proto_enumTypes[1] +} + +func (x WaitForRelayLogsMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WaitForRelayLogsMode.Descriptor instead. +func (WaitForRelayLogsMode) EnumDescriptor() ([]byte, []int) { + return file_replicationdata_proto_rawDescGZIP(), []int{1} +} + // Status is the replication status for MySQL/MariaDB/File-based. Returned by a // flavor-specific command and parsed into a Position and fields. type Status struct { @@ -832,7 +886,12 @@ const file_replicationdata_proto_rawDesc = "" + "tabletType*;\n" + "\x13StopReplicationMode\x12\x12\n" + "\x0eIOANDSQLTHREAD\x10\x00\x12\x10\n" + - "\fIOTHREADONLY\x10\x01B.Z,vitess.io/vitess/go/vt/proto/replicationdatab\x06proto3" + "\fIOTHREADONLY\x10\x01*E\n" + + "\x14WaitForRelayLogsMode\x12\v\n" + + "\aDEFAULT\x10\x00\x12\a\n" + + "\x03ALL\x10\x01\x12\f\n" + + "\bMAJORITY\x10\x02\x12\t\n" + + "\x05COUNT\x10\x03B.Z,vitess.io/vitess/go/vt/proto/replicationdatab\x06proto3" var ( file_replicationdata_proto_rawDescOnce sync.Once @@ -846,24 +905,25 @@ func file_replicationdata_proto_rawDescGZIP() []byte { return file_replicationdata_proto_rawDescData } -var file_replicationdata_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_replicationdata_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_replicationdata_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_replicationdata_proto_goTypes = []any{ (StopReplicationMode)(0), // 0: replicationdata.StopReplicationMode - (*Status)(nil), // 1: replicationdata.Status - (*Configuration)(nil), // 2: replicationdata.Configuration - (*StopReplicationStatus)(nil), // 3: replicationdata.StopReplicationStatus - (*PrimaryStatus)(nil), // 4: replicationdata.PrimaryStatus - (*FullStatus)(nil), // 5: replicationdata.FullStatus - (topodata.TabletType)(0), // 6: topodata.TabletType + (WaitForRelayLogsMode)(0), // 1: replicationdata.WaitForRelayLogsMode + (*Status)(nil), // 2: replicationdata.Status + (*Configuration)(nil), // 3: replicationdata.Configuration + (*StopReplicationStatus)(nil), // 4: replicationdata.StopReplicationStatus + (*PrimaryStatus)(nil), // 5: replicationdata.PrimaryStatus + (*FullStatus)(nil), // 6: replicationdata.FullStatus + (topodata.TabletType)(0), // 7: topodata.TabletType } var file_replicationdata_proto_depIdxs = []int32{ - 1, // 0: replicationdata.StopReplicationStatus.before:type_name -> replicationdata.Status - 1, // 1: replicationdata.StopReplicationStatus.after:type_name -> replicationdata.Status - 1, // 2: replicationdata.FullStatus.replication_status:type_name -> replicationdata.Status - 4, // 3: replicationdata.FullStatus.primary_status:type_name -> replicationdata.PrimaryStatus - 2, // 4: replicationdata.FullStatus.replication_configuration:type_name -> replicationdata.Configuration - 6, // 5: replicationdata.FullStatus.tablet_type:type_name -> topodata.TabletType + 2, // 0: replicationdata.StopReplicationStatus.before:type_name -> replicationdata.Status + 2, // 1: replicationdata.StopReplicationStatus.after:type_name -> replicationdata.Status + 2, // 2: replicationdata.FullStatus.replication_status:type_name -> replicationdata.Status + 5, // 3: replicationdata.FullStatus.primary_status:type_name -> replicationdata.PrimaryStatus + 3, // 4: replicationdata.FullStatus.replication_configuration:type_name -> replicationdata.Configuration + 7, // 5: replicationdata.FullStatus.tablet_type:type_name -> topodata.TabletType 6, // [6:6] is the sub-list for method output_type 6, // [6:6] is the sub-list for method input_type 6, // [6:6] is the sub-list for extension type_name @@ -881,7 +941,7 @@ func file_replicationdata_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_replicationdata_proto_rawDesc), len(file_replicationdata_proto_rawDesc)), - NumEnums: 1, + NumEnums: 2, NumMessages: 5, NumExtensions: 0, NumServices: 0, diff --git a/go/vt/proto/vtctldata/vtctldata.pb.go b/go/vt/proto/vtctldata/vtctldata.pb.go index 4afdbb28cc9..0a7cbd11c49 100644 --- a/go/vt/proto/vtctldata/vtctldata.pb.go +++ b/go/vt/proto/vtctldata/vtctldata.pb.go @@ -4340,8 +4340,13 @@ type EmergencyReparentShardRequest struct { // ExpectedPrimary is the optional alias we expect to be the current primary in order for // the reparent operation to succeed. ExpectedPrimary *topodata.TabletAlias `protobuf:"bytes,8,opt,name=expected_primary,json=expectedPrimary,proto3" json:"expected_primary,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // WaitForRelayLogsMode is the mode to use during the wait for relay logs phase. + WaitForRelayLogsMode replicationdata.WaitForRelayLogsMode `protobuf:"varint,9,opt,name=wait_for_relay_logs_mode,json=waitForRelayLogsMode,proto3,enum=replicationdata.WaitForRelayLogsMode" json:"wait_for_relay_logs_mode,omitempty"` + // WaitForRelayLogsTabletCount is the number of most-advanced tablets to use during the + // wait for relay logs phase. This is only relevant when using COUNT mode. + WaitForRelayLogsTabletCount int64 `protobuf:"varint,10,opt,name=wait_for_relay_logs_tablet_count,json=waitForRelayLogsTabletCount,proto3" json:"wait_for_relay_logs_tablet_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *EmergencyReparentShardRequest) Reset() { @@ -4430,6 +4435,20 @@ func (x *EmergencyReparentShardRequest) GetExpectedPrimary() *topodata.TabletAli return nil } +func (x *EmergencyReparentShardRequest) GetWaitForRelayLogsMode() replicationdata.WaitForRelayLogsMode { + if x != nil { + return x.WaitForRelayLogsMode + } + return replicationdata.WaitForRelayLogsMode(0) +} + +func (x *EmergencyReparentShardRequest) GetWaitForRelayLogsTabletCount() int64 { + if x != nil { + return x.WaitForRelayLogsTabletCount + } + return 0 +} + type EmergencyReparentShardResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Keyspace is the name of the keyspace the Emergency Reparent took place in. @@ -17827,7 +17846,7 @@ const file_vtctldata_proto_rawDesc = "" + "\x14DeleteTabletsRequest\x12<\n" + "\x0etablet_aliases\x18\x01 \x03(\v2\x15.topodata.TabletAliasR\rtabletAliases\x12#\n" + "\rallow_primary\x18\x02 \x01(\bR\fallowPrimary\"\x17\n" + - "\x15DeleteTabletsResponse\"\xc3\x03\n" + + "\x15DeleteTabletsResponse\"\xe9\x04\n" + "\x1dEmergencyReparentShardRequest\x12\x1a\n" + "\bkeyspace\x18\x01 \x01(\tR\bkeyspace\x12\x14\n" + "\x05shard\x18\x02 \x01(\tR\x05shard\x126\n" + @@ -17837,7 +17856,10 @@ const file_vtctldata_proto_rawDesc = "" + "\x15wait_replicas_timeout\x18\x05 \x01(\v2\x10.vttime.DurationR\x13waitReplicasTimeout\x12?\n" + "\x1cprevent_cross_cell_promotion\x18\x06 \x01(\bR\x19preventCrossCellPromotion\x12/\n" + "\x14wait_for_all_tablets\x18\a \x01(\bR\x11waitForAllTablets\x12@\n" + - "\x10expected_primary\x18\b \x01(\v2\x15.topodata.TabletAliasR\x0fexpectedPrimary\"\xbc\x01\n" + + "\x10expected_primary\x18\b \x01(\v2\x15.topodata.TabletAliasR\x0fexpectedPrimary\x12]\n" + + "\x18wait_for_relay_logs_mode\x18\t \x01(\x0e2%.replicationdata.WaitForRelayLogsModeR\x14waitForRelayLogsMode\x12E\n" + + " wait_for_relay_logs_tablet_count\x18\n" + + " \x01(\x03R\x1bwaitForRelayLogsTabletCount\"\xbc\x01\n" + "\x1eEmergencyReparentShardResponse\x12\x1a\n" + "\bkeyspace\x18\x01 \x01(\tR\bkeyspace\x12\x14\n" + "\x05shard\x18\x02 \x01(\tR\x05shard\x12@\n" + @@ -19060,29 +19082,30 @@ var file_vtctldata_proto_goTypes = []any{ (*topodata.Tablet)(nil), // 334: topodata.Tablet (*tabletmanagerdata.CheckThrottlerResponse)(nil), // 335: tabletmanagerdata.CheckThrottlerResponse (topodata.KeyspaceType)(0), // 336: topodata.KeyspaceType - (*query.QueryResult)(nil), // 337: query.QueryResult - (*tabletmanagerdata.ExecuteHookRequest)(nil), // 338: tabletmanagerdata.ExecuteHookRequest - (*tabletmanagerdata.ExecuteHookResponse)(nil), // 339: tabletmanagerdata.ExecuteHookResponse - (*mysqlctl.BackupInfo)(nil), // 340: mysqlctl.BackupInfo - (*replicationdata.FullStatus)(nil), // 341: replicationdata.FullStatus - (*tabletmanagerdata.Permissions)(nil), // 342: tabletmanagerdata.Permissions - (*tabletmanagerdata.SchemaDefinition)(nil), // 343: tabletmanagerdata.SchemaDefinition - (*topodata.ThrottledAppRule)(nil), // 344: topodata.ThrottledAppRule - (*vschema.SrvVSchema)(nil), // 345: vschema.SrvVSchema - (*tabletmanagerdata.GetThrottlerStatusResponse)(nil), // 346: tabletmanagerdata.GetThrottlerStatusResponse - (*query.TransactionMetadata)(nil), // 347: query.TransactionMetadata - (*query.Target)(nil), // 348: query.Target - (*topodata.ShardReplicationError)(nil), // 349: topodata.ShardReplicationError - (*topodata.KeyRange)(nil), // 350: topodata.KeyRange - (*topodata.CellsAlias)(nil), // 351: topodata.CellsAlias - (*tabletmanagerdata.UpdateVReplicationWorkflowRequest)(nil), // 352: tabletmanagerdata.UpdateVReplicationWorkflowRequest - (*vschema.MirrorRules)(nil), // 353: vschema.MirrorRules - (*topodata.Shard_TabletControl)(nil), // 354: topodata.Shard.TabletControl - (*binlogdata.BinlogSource)(nil), // 355: binlogdata.BinlogSource - (*topodata.ShardReplication)(nil), // 356: topodata.ShardReplication - (*topodata.SrvKeyspace)(nil), // 357: topodata.SrvKeyspace - (*replicationdata.Status)(nil), // 358: replicationdata.Status - (*tabletmanagerdata.VDiffResponse)(nil), // 359: tabletmanagerdata.VDiffResponse + (replicationdata.WaitForRelayLogsMode)(0), // 337: replicationdata.WaitForRelayLogsMode + (*query.QueryResult)(nil), // 338: query.QueryResult + (*tabletmanagerdata.ExecuteHookRequest)(nil), // 339: tabletmanagerdata.ExecuteHookRequest + (*tabletmanagerdata.ExecuteHookResponse)(nil), // 340: tabletmanagerdata.ExecuteHookResponse + (*mysqlctl.BackupInfo)(nil), // 341: mysqlctl.BackupInfo + (*replicationdata.FullStatus)(nil), // 342: replicationdata.FullStatus + (*tabletmanagerdata.Permissions)(nil), // 343: tabletmanagerdata.Permissions + (*tabletmanagerdata.SchemaDefinition)(nil), // 344: tabletmanagerdata.SchemaDefinition + (*topodata.ThrottledAppRule)(nil), // 345: topodata.ThrottledAppRule + (*vschema.SrvVSchema)(nil), // 346: vschema.SrvVSchema + (*tabletmanagerdata.GetThrottlerStatusResponse)(nil), // 347: tabletmanagerdata.GetThrottlerStatusResponse + (*query.TransactionMetadata)(nil), // 348: query.TransactionMetadata + (*query.Target)(nil), // 349: query.Target + (*topodata.ShardReplicationError)(nil), // 350: topodata.ShardReplicationError + (*topodata.KeyRange)(nil), // 351: topodata.KeyRange + (*topodata.CellsAlias)(nil), // 352: topodata.CellsAlias + (*tabletmanagerdata.UpdateVReplicationWorkflowRequest)(nil), // 353: tabletmanagerdata.UpdateVReplicationWorkflowRequest + (*vschema.MirrorRules)(nil), // 354: vschema.MirrorRules + (*topodata.Shard_TabletControl)(nil), // 355: topodata.Shard.TabletControl + (*binlogdata.BinlogSource)(nil), // 356: binlogdata.BinlogSource + (*topodata.ShardReplication)(nil), // 357: topodata.ShardReplication + (*topodata.SrvKeyspace)(nil), // 358: topodata.SrvKeyspace + (*replicationdata.Status)(nil), // 359: replicationdata.Status + (*tabletmanagerdata.VDiffResponse)(nil), // 360: tabletmanagerdata.VDiffResponse } var file_vtctldata_proto_depIdxs = []int32{ 319, // 0: vtctldata.ExecuteVtctlCommandResponse.event:type_name -> logutil.Event @@ -19161,191 +19184,192 @@ var file_vtctldata_proto_depIdxs = []int32{ 323, // 73: vtctldata.EmergencyReparentShardRequest.ignore_replicas:type_name -> topodata.TabletAlias 324, // 74: vtctldata.EmergencyReparentShardRequest.wait_replicas_timeout:type_name -> vttime.Duration 323, // 75: vtctldata.EmergencyReparentShardRequest.expected_primary:type_name -> topodata.TabletAlias - 323, // 76: vtctldata.EmergencyReparentShardResponse.promoted_primary:type_name -> topodata.TabletAlias - 319, // 77: vtctldata.EmergencyReparentShardResponse.events:type_name -> logutil.Event - 323, // 78: vtctldata.ExecuteFetchAsAppRequest.tablet_alias:type_name -> topodata.TabletAlias - 337, // 79: vtctldata.ExecuteFetchAsAppResponse.result:type_name -> query.QueryResult - 323, // 80: vtctldata.ExecuteFetchAsDBARequest.tablet_alias:type_name -> topodata.TabletAlias - 337, // 81: vtctldata.ExecuteFetchAsDBAResponse.result:type_name -> query.QueryResult - 323, // 82: vtctldata.ExecuteHookRequest.tablet_alias:type_name -> topodata.TabletAlias - 338, // 83: vtctldata.ExecuteHookRequest.tablet_hook_request:type_name -> tabletmanagerdata.ExecuteHookRequest - 339, // 84: vtctldata.ExecuteHookResponse.hook_result:type_name -> tabletmanagerdata.ExecuteHookResponse - 323, // 85: vtctldata.ExecuteMultiFetchAsDBARequest.tablet_alias:type_name -> topodata.TabletAlias - 337, // 86: vtctldata.ExecuteMultiFetchAsDBAResponse.results:type_name -> query.QueryResult - 293, // 87: vtctldata.FindAllShardsInKeyspaceResponse.shards:type_name -> vtctldata.FindAllShardsInKeyspaceResponse.ShardsEntry - 330, // 88: vtctldata.ForceCutOverSchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID - 294, // 89: vtctldata.ForceCutOverSchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.ForceCutOverSchemaMigrationResponse.RowsAffectedByShardEntry - 340, // 90: vtctldata.GetBackupsResponse.backups:type_name -> mysqlctl.BackupInfo - 326, // 91: vtctldata.GetCellInfoResponse.cell_info:type_name -> topodata.CellInfo - 295, // 92: vtctldata.GetCellsAliasesResponse.aliases:type_name -> vtctldata.GetCellsAliasesResponse.AliasesEntry - 323, // 93: vtctldata.GetFullStatusRequest.tablet_alias:type_name -> topodata.TabletAlias - 341, // 94: vtctldata.GetFullStatusResponse.status:type_name -> replicationdata.FullStatus - 10, // 95: vtctldata.GetKeyspacesResponse.keyspaces:type_name -> vtctldata.Keyspace - 10, // 96: vtctldata.GetKeyspaceResponse.keyspace:type_name -> vtctldata.Keyspace - 323, // 97: vtctldata.GetPermissionsRequest.tablet_alias:type_name -> topodata.TabletAlias - 342, // 98: vtctldata.GetPermissionsResponse.permissions:type_name -> tabletmanagerdata.Permissions - 327, // 99: vtctldata.GetKeyspaceRoutingRulesResponse.keyspace_routing_rules:type_name -> vschema.KeyspaceRoutingRules - 328, // 100: vtctldata.GetRoutingRulesResponse.routing_rules:type_name -> vschema.RoutingRules - 323, // 101: vtctldata.GetSchemaRequest.tablet_alias:type_name -> topodata.TabletAlias - 343, // 102: vtctldata.GetSchemaResponse.schema:type_name -> tabletmanagerdata.SchemaDefinition - 5, // 103: vtctldata.GetSchemaMigrationsRequest.status:type_name -> vtctldata.SchemaMigration.Status - 324, // 104: vtctldata.GetSchemaMigrationsRequest.recent:type_name -> vttime.Duration - 1, // 105: vtctldata.GetSchemaMigrationsRequest.order:type_name -> vtctldata.QueryOrdering - 11, // 106: vtctldata.GetSchemaMigrationsResponse.migrations:type_name -> vtctldata.SchemaMigration - 296, // 107: vtctldata.GetShardReplicationResponse.shard_replication_by_cell:type_name -> vtctldata.GetShardReplicationResponse.ShardReplicationByCellEntry - 12, // 108: vtctldata.GetShardResponse.shard:type_name -> vtctldata.Shard - 329, // 109: vtctldata.GetShardRoutingRulesResponse.shard_routing_rules:type_name -> vschema.ShardRoutingRules - 297, // 110: vtctldata.GetSrvKeyspaceNamesResponse.names:type_name -> vtctldata.GetSrvKeyspaceNamesResponse.NamesEntry - 299, // 111: vtctldata.GetSrvKeyspacesResponse.srv_keyspaces:type_name -> vtctldata.GetSrvKeyspacesResponse.SrvKeyspacesEntry - 344, // 112: vtctldata.UpdateThrottlerConfigRequest.throttled_app:type_name -> topodata.ThrottledAppRule - 345, // 113: vtctldata.GetSrvVSchemaResponse.srv_v_schema:type_name -> vschema.SrvVSchema - 300, // 114: vtctldata.GetSrvVSchemasResponse.srv_v_schemas:type_name -> vtctldata.GetSrvVSchemasResponse.SrvVSchemasEntry - 323, // 115: vtctldata.GetTabletRequest.tablet_alias:type_name -> topodata.TabletAlias - 334, // 116: vtctldata.GetTabletResponse.tablet:type_name -> topodata.Tablet - 323, // 117: vtctldata.GetTabletsRequest.tablet_aliases:type_name -> topodata.TabletAlias - 333, // 118: vtctldata.GetTabletsRequest.tablet_type:type_name -> topodata.TabletType - 334, // 119: vtctldata.GetTabletsResponse.tablets:type_name -> topodata.Tablet - 323, // 120: vtctldata.GetThrottlerStatusRequest.tablet_alias:type_name -> topodata.TabletAlias - 346, // 121: vtctldata.GetThrottlerStatusResponse.status:type_name -> tabletmanagerdata.GetThrottlerStatusResponse - 124, // 122: vtctldata.GetTopologyPathResponse.cell:type_name -> vtctldata.TopologyCell - 347, // 123: vtctldata.GetUnresolvedTransactionsResponse.transactions:type_name -> query.TransactionMetadata - 347, // 124: vtctldata.GetTransactionInfoResponse.metadata:type_name -> query.TransactionMetadata - 128, // 125: vtctldata.GetTransactionInfoResponse.shard_states:type_name -> vtctldata.ShardTransactionState - 348, // 126: vtctldata.ConcludeTransactionRequest.participants:type_name -> query.Target - 323, // 127: vtctldata.GetVersionRequest.tablet_alias:type_name -> topodata.TabletAlias - 331, // 128: vtctldata.GetVSchemaResponse.v_schema:type_name -> vschema.Keyspace - 14, // 129: vtctldata.GetWorkflowsResponse.workflows:type_name -> vtctldata.Workflow - 323, // 130: vtctldata.InitShardPrimaryRequest.primary_elect_tablet_alias:type_name -> topodata.TabletAlias - 324, // 131: vtctldata.InitShardPrimaryRequest.wait_replicas_timeout:type_name -> vttime.Duration - 319, // 132: vtctldata.InitShardPrimaryResponse.events:type_name -> logutil.Event - 330, // 133: vtctldata.LaunchSchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID - 301, // 134: vtctldata.LaunchSchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.LaunchSchemaMigrationResponse.RowsAffectedByShardEntry - 331, // 135: vtctldata.LookupVindexCreateRequest.vindex:type_name -> vschema.Keyspace - 333, // 136: vtctldata.LookupVindexCreateRequest.tablet_types:type_name -> topodata.TabletType - 320, // 137: vtctldata.LookupVindexCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 9, // 138: vtctldata.MaterializeCreateRequest.settings:type_name -> vtctldata.MaterializeSettings - 8, // 139: vtctldata.WorkflowAddTablesRequest.table_settings:type_name -> vtctldata.TableMaterializeSettings - 0, // 140: vtctldata.WorkflowAddTablesRequest.materialization_intent:type_name -> vtctldata.MaterializationIntent - 333, // 141: vtctldata.MigrateCreateRequest.tablet_types:type_name -> topodata.TabletType - 320, // 142: vtctldata.MigrateCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 333, // 143: vtctldata.MoveTablesCreateRequest.tablet_types:type_name -> topodata.TabletType - 320, // 144: vtctldata.MoveTablesCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 13, // 145: vtctldata.MoveTablesCreateRequest.workflow_options:type_name -> vtctldata.WorkflowOptions - 302, // 146: vtctldata.MoveTablesCreateResponse.details:type_name -> vtctldata.MoveTablesCreateResponse.TabletInfo - 323, // 147: vtctldata.PingTabletRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 148: vtctldata.PlannedReparentShardRequest.new_primary:type_name -> topodata.TabletAlias - 323, // 149: vtctldata.PlannedReparentShardRequest.avoid_primary:type_name -> topodata.TabletAlias - 324, // 150: vtctldata.PlannedReparentShardRequest.wait_replicas_timeout:type_name -> vttime.Duration - 324, // 151: vtctldata.PlannedReparentShardRequest.tolerable_replication_lag:type_name -> vttime.Duration - 323, // 152: vtctldata.PlannedReparentShardRequest.expected_primary:type_name -> topodata.TabletAlias - 323, // 153: vtctldata.PlannedReparentShardResponse.promoted_primary:type_name -> topodata.TabletAlias - 319, // 154: vtctldata.PlannedReparentShardResponse.events:type_name -> logutil.Event - 323, // 155: vtctldata.RefreshStateRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 156: vtctldata.ReloadSchemaRequest.tablet_alias:type_name -> topodata.TabletAlias - 319, // 157: vtctldata.ReloadSchemaKeyspaceResponse.events:type_name -> logutil.Event - 319, // 158: vtctldata.ReloadSchemaShardResponse.events:type_name -> logutil.Event - 323, // 159: vtctldata.ReparentTabletRequest.tablet:type_name -> topodata.TabletAlias - 323, // 160: vtctldata.ReparentTabletResponse.primary:type_name -> topodata.TabletAlias - 333, // 161: vtctldata.ReshardCreateRequest.tablet_types:type_name -> topodata.TabletType - 320, // 162: vtctldata.ReshardCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 13, // 163: vtctldata.ReshardCreateRequest.workflow_options:type_name -> vtctldata.WorkflowOptions - 323, // 164: vtctldata.RestoreFromBackupRequest.tablet_alias:type_name -> topodata.TabletAlias - 322, // 165: vtctldata.RestoreFromBackupRequest.backup_time:type_name -> vttime.Time - 322, // 166: vtctldata.RestoreFromBackupRequest.restore_to_timestamp:type_name -> vttime.Time - 323, // 167: vtctldata.RestoreFromBackupResponse.tablet_alias:type_name -> topodata.TabletAlias - 319, // 168: vtctldata.RestoreFromBackupResponse.event:type_name -> logutil.Event - 330, // 169: vtctldata.RetrySchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID - 303, // 170: vtctldata.RetrySchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.RetrySchemaMigrationResponse.RowsAffectedByShardEntry - 323, // 171: vtctldata.RunHealthCheckRequest.tablet_alias:type_name -> topodata.TabletAlias - 321, // 172: vtctldata.SetKeyspaceDurabilityPolicyResponse.keyspace:type_name -> topodata.Keyspace - 321, // 173: vtctldata.SetKeyspaceShardingInfoResponse.keyspace:type_name -> topodata.Keyspace - 325, // 174: vtctldata.SetShardIsPrimaryServingResponse.shard:type_name -> topodata.Shard - 333, // 175: vtctldata.SetShardTabletControlRequest.tablet_type:type_name -> topodata.TabletType - 325, // 176: vtctldata.SetShardTabletControlResponse.shard:type_name -> topodata.Shard - 323, // 177: vtctldata.SetWritableRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 178: vtctldata.ShardReplicationAddRequest.tablet_alias:type_name -> topodata.TabletAlias - 349, // 179: vtctldata.ShardReplicationFixResponse.error:type_name -> topodata.ShardReplicationError - 304, // 180: vtctldata.ShardReplicationPositionsResponse.replication_statuses:type_name -> vtctldata.ShardReplicationPositionsResponse.ReplicationStatusesEntry - 305, // 181: vtctldata.ShardReplicationPositionsResponse.tablet_map:type_name -> vtctldata.ShardReplicationPositionsResponse.TabletMapEntry - 323, // 182: vtctldata.ShardReplicationRemoveRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 183: vtctldata.SleepTabletRequest.tablet_alias:type_name -> topodata.TabletAlias - 324, // 184: vtctldata.SleepTabletRequest.duration:type_name -> vttime.Duration - 350, // 185: vtctldata.SourceShardAddRequest.key_range:type_name -> topodata.KeyRange - 325, // 186: vtctldata.SourceShardAddResponse.shard:type_name -> topodata.Shard - 325, // 187: vtctldata.SourceShardDeleteResponse.shard:type_name -> topodata.Shard - 323, // 188: vtctldata.StartReplicationRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 189: vtctldata.StopReplicationRequest.tablet_alias:type_name -> topodata.TabletAlias - 323, // 190: vtctldata.TabletExternallyReparentedRequest.tablet:type_name -> topodata.TabletAlias - 323, // 191: vtctldata.TabletExternallyReparentedResponse.new_primary:type_name -> topodata.TabletAlias - 323, // 192: vtctldata.TabletExternallyReparentedResponse.old_primary:type_name -> topodata.TabletAlias - 326, // 193: vtctldata.UpdateCellInfoRequest.cell_info:type_name -> topodata.CellInfo - 326, // 194: vtctldata.UpdateCellInfoResponse.cell_info:type_name -> topodata.CellInfo - 351, // 195: vtctldata.UpdateCellsAliasRequest.cells_alias:type_name -> topodata.CellsAlias - 351, // 196: vtctldata.UpdateCellsAliasResponse.cells_alias:type_name -> topodata.CellsAlias - 306, // 197: vtctldata.ValidateResponse.results_by_keyspace:type_name -> vtctldata.ValidateResponse.ResultsByKeyspaceEntry - 307, // 198: vtctldata.ValidateKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateKeyspaceResponse.ResultsByShardEntry - 308, // 199: vtctldata.ValidateSchemaKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateSchemaKeyspaceResponse.ResultsByShardEntry - 309, // 200: vtctldata.ValidateVersionKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateVersionKeyspaceResponse.ResultsByShardEntry - 310, // 201: vtctldata.ValidateVSchemaResponse.results_by_shard:type_name -> vtctldata.ValidateVSchemaResponse.ResultsByShardEntry - 333, // 202: vtctldata.VDiffCreateRequest.tablet_types:type_name -> topodata.TabletType - 320, // 203: vtctldata.VDiffCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 324, // 204: vtctldata.VDiffCreateRequest.filtered_replication_wait_time:type_name -> vttime.Duration - 324, // 205: vtctldata.VDiffCreateRequest.wait_update_interval:type_name -> vttime.Duration - 324, // 206: vtctldata.VDiffCreateRequest.max_diff_duration:type_name -> vttime.Duration - 311, // 207: vtctldata.VDiffShowResponse.tablet_responses:type_name -> vtctldata.VDiffShowResponse.TabletResponsesEntry - 312, // 208: vtctldata.WorkflowDeleteResponse.details:type_name -> vtctldata.WorkflowDeleteResponse.TabletInfo - 316, // 209: vtctldata.WorkflowStatusResponse.table_copy_state:type_name -> vtctldata.WorkflowStatusResponse.TableCopyStateEntry - 317, // 210: vtctldata.WorkflowStatusResponse.shard_streams:type_name -> vtctldata.WorkflowStatusResponse.ShardStreamsEntry - 333, // 211: vtctldata.WorkflowSwitchTrafficRequest.tablet_types:type_name -> topodata.TabletType - 324, // 212: vtctldata.WorkflowSwitchTrafficRequest.max_replication_lag_allowed:type_name -> vttime.Duration - 324, // 213: vtctldata.WorkflowSwitchTrafficRequest.timeout:type_name -> vttime.Duration - 352, // 214: vtctldata.WorkflowUpdateRequest.tablet_request:type_name -> tabletmanagerdata.UpdateVReplicationWorkflowRequest - 318, // 215: vtctldata.WorkflowUpdateResponse.details:type_name -> vtctldata.WorkflowUpdateResponse.TabletInfo - 353, // 216: vtctldata.GetMirrorRulesResponse.mirror_rules:type_name -> vschema.MirrorRules - 333, // 217: vtctldata.WorkflowMirrorTrafficRequest.tablet_types:type_name -> topodata.TabletType - 279, // 218: vtctldata.Workflow.ShardStreamsEntry.value:type_name -> vtctldata.Workflow.ShardStream - 280, // 219: vtctldata.Workflow.ShardStream.streams:type_name -> vtctldata.Workflow.Stream - 354, // 220: vtctldata.Workflow.ShardStream.tablet_controls:type_name -> topodata.Shard.TabletControl - 323, // 221: vtctldata.Workflow.Stream.tablet:type_name -> topodata.TabletAlias - 355, // 222: vtctldata.Workflow.Stream.binlog_source:type_name -> binlogdata.BinlogSource - 322, // 223: vtctldata.Workflow.Stream.transaction_timestamp:type_name -> vttime.Time - 322, // 224: vtctldata.Workflow.Stream.time_updated:type_name -> vttime.Time - 281, // 225: vtctldata.Workflow.Stream.copy_states:type_name -> vtctldata.Workflow.Stream.CopyState - 282, // 226: vtctldata.Workflow.Stream.logs:type_name -> vtctldata.Workflow.Stream.Log - 283, // 227: vtctldata.Workflow.Stream.throttler_status:type_name -> vtctldata.Workflow.Stream.ThrottlerStatus - 333, // 228: vtctldata.Workflow.Stream.tablet_types:type_name -> topodata.TabletType - 320, // 229: vtctldata.Workflow.Stream.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference - 322, // 230: vtctldata.Workflow.Stream.Log.created_at:type_name -> vttime.Time - 322, // 231: vtctldata.Workflow.Stream.Log.updated_at:type_name -> vttime.Time - 322, // 232: vtctldata.Workflow.Stream.ThrottlerStatus.time_throttled:type_name -> vttime.Time - 286, // 233: vtctldata.ApplyVSchemaResponse.UnknownVindexParamsEntry.value:type_name -> vtctldata.ApplyVSchemaResponse.ParamList - 12, // 234: vtctldata.FindAllShardsInKeyspaceResponse.ShardsEntry.value:type_name -> vtctldata.Shard - 351, // 235: vtctldata.GetCellsAliasesResponse.AliasesEntry.value:type_name -> topodata.CellsAlias - 356, // 236: vtctldata.GetShardReplicationResponse.ShardReplicationByCellEntry.value:type_name -> topodata.ShardReplication - 298, // 237: vtctldata.GetSrvKeyspaceNamesResponse.NamesEntry.value:type_name -> vtctldata.GetSrvKeyspaceNamesResponse.NameList - 357, // 238: vtctldata.GetSrvKeyspacesResponse.SrvKeyspacesEntry.value:type_name -> topodata.SrvKeyspace - 345, // 239: vtctldata.GetSrvVSchemasResponse.SrvVSchemasEntry.value:type_name -> vschema.SrvVSchema - 323, // 240: vtctldata.MoveTablesCreateResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias - 358, // 241: vtctldata.ShardReplicationPositionsResponse.ReplicationStatusesEntry.value:type_name -> replicationdata.Status - 334, // 242: vtctldata.ShardReplicationPositionsResponse.TabletMapEntry.value:type_name -> topodata.Tablet - 239, // 243: vtctldata.ValidateResponse.ResultsByKeyspaceEntry.value:type_name -> vtctldata.ValidateKeyspaceResponse - 245, // 244: vtctldata.ValidateKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse - 245, // 245: vtctldata.ValidateSchemaKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse - 245, // 246: vtctldata.ValidateVersionKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse - 245, // 247: vtctldata.ValidateVSchemaResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse - 359, // 248: vtctldata.VDiffShowResponse.TabletResponsesEntry.value:type_name -> tabletmanagerdata.VDiffResponse - 323, // 249: vtctldata.WorkflowDeleteResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias - 3, // 250: vtctldata.WorkflowStatusResponse.TableCopyState.phase:type_name -> vtctldata.TableCopyPhase - 323, // 251: vtctldata.WorkflowStatusResponse.ShardStreamState.tablet:type_name -> topodata.TabletAlias - 314, // 252: vtctldata.WorkflowStatusResponse.ShardStreams.streams:type_name -> vtctldata.WorkflowStatusResponse.ShardStreamState - 313, // 253: vtctldata.WorkflowStatusResponse.TableCopyStateEntry.value:type_name -> vtctldata.WorkflowStatusResponse.TableCopyState - 315, // 254: vtctldata.WorkflowStatusResponse.ShardStreamsEntry.value:type_name -> vtctldata.WorkflowStatusResponse.ShardStreams - 323, // 255: vtctldata.WorkflowUpdateResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias - 256, // [256:256] is the sub-list for method output_type - 256, // [256:256] is the sub-list for method input_type - 256, // [256:256] is the sub-list for extension type_name - 256, // [256:256] is the sub-list for extension extendee - 0, // [0:256] is the sub-list for field type_name + 337, // 76: vtctldata.EmergencyReparentShardRequest.wait_for_relay_logs_mode:type_name -> replicationdata.WaitForRelayLogsMode + 323, // 77: vtctldata.EmergencyReparentShardResponse.promoted_primary:type_name -> topodata.TabletAlias + 319, // 78: vtctldata.EmergencyReparentShardResponse.events:type_name -> logutil.Event + 323, // 79: vtctldata.ExecuteFetchAsAppRequest.tablet_alias:type_name -> topodata.TabletAlias + 338, // 80: vtctldata.ExecuteFetchAsAppResponse.result:type_name -> query.QueryResult + 323, // 81: vtctldata.ExecuteFetchAsDBARequest.tablet_alias:type_name -> topodata.TabletAlias + 338, // 82: vtctldata.ExecuteFetchAsDBAResponse.result:type_name -> query.QueryResult + 323, // 83: vtctldata.ExecuteHookRequest.tablet_alias:type_name -> topodata.TabletAlias + 339, // 84: vtctldata.ExecuteHookRequest.tablet_hook_request:type_name -> tabletmanagerdata.ExecuteHookRequest + 340, // 85: vtctldata.ExecuteHookResponse.hook_result:type_name -> tabletmanagerdata.ExecuteHookResponse + 323, // 86: vtctldata.ExecuteMultiFetchAsDBARequest.tablet_alias:type_name -> topodata.TabletAlias + 338, // 87: vtctldata.ExecuteMultiFetchAsDBAResponse.results:type_name -> query.QueryResult + 293, // 88: vtctldata.FindAllShardsInKeyspaceResponse.shards:type_name -> vtctldata.FindAllShardsInKeyspaceResponse.ShardsEntry + 330, // 89: vtctldata.ForceCutOverSchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID + 294, // 90: vtctldata.ForceCutOverSchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.ForceCutOverSchemaMigrationResponse.RowsAffectedByShardEntry + 341, // 91: vtctldata.GetBackupsResponse.backups:type_name -> mysqlctl.BackupInfo + 326, // 92: vtctldata.GetCellInfoResponse.cell_info:type_name -> topodata.CellInfo + 295, // 93: vtctldata.GetCellsAliasesResponse.aliases:type_name -> vtctldata.GetCellsAliasesResponse.AliasesEntry + 323, // 94: vtctldata.GetFullStatusRequest.tablet_alias:type_name -> topodata.TabletAlias + 342, // 95: vtctldata.GetFullStatusResponse.status:type_name -> replicationdata.FullStatus + 10, // 96: vtctldata.GetKeyspacesResponse.keyspaces:type_name -> vtctldata.Keyspace + 10, // 97: vtctldata.GetKeyspaceResponse.keyspace:type_name -> vtctldata.Keyspace + 323, // 98: vtctldata.GetPermissionsRequest.tablet_alias:type_name -> topodata.TabletAlias + 343, // 99: vtctldata.GetPermissionsResponse.permissions:type_name -> tabletmanagerdata.Permissions + 327, // 100: vtctldata.GetKeyspaceRoutingRulesResponse.keyspace_routing_rules:type_name -> vschema.KeyspaceRoutingRules + 328, // 101: vtctldata.GetRoutingRulesResponse.routing_rules:type_name -> vschema.RoutingRules + 323, // 102: vtctldata.GetSchemaRequest.tablet_alias:type_name -> topodata.TabletAlias + 344, // 103: vtctldata.GetSchemaResponse.schema:type_name -> tabletmanagerdata.SchemaDefinition + 5, // 104: vtctldata.GetSchemaMigrationsRequest.status:type_name -> vtctldata.SchemaMigration.Status + 324, // 105: vtctldata.GetSchemaMigrationsRequest.recent:type_name -> vttime.Duration + 1, // 106: vtctldata.GetSchemaMigrationsRequest.order:type_name -> vtctldata.QueryOrdering + 11, // 107: vtctldata.GetSchemaMigrationsResponse.migrations:type_name -> vtctldata.SchemaMigration + 296, // 108: vtctldata.GetShardReplicationResponse.shard_replication_by_cell:type_name -> vtctldata.GetShardReplicationResponse.ShardReplicationByCellEntry + 12, // 109: vtctldata.GetShardResponse.shard:type_name -> vtctldata.Shard + 329, // 110: vtctldata.GetShardRoutingRulesResponse.shard_routing_rules:type_name -> vschema.ShardRoutingRules + 297, // 111: vtctldata.GetSrvKeyspaceNamesResponse.names:type_name -> vtctldata.GetSrvKeyspaceNamesResponse.NamesEntry + 299, // 112: vtctldata.GetSrvKeyspacesResponse.srv_keyspaces:type_name -> vtctldata.GetSrvKeyspacesResponse.SrvKeyspacesEntry + 345, // 113: vtctldata.UpdateThrottlerConfigRequest.throttled_app:type_name -> topodata.ThrottledAppRule + 346, // 114: vtctldata.GetSrvVSchemaResponse.srv_v_schema:type_name -> vschema.SrvVSchema + 300, // 115: vtctldata.GetSrvVSchemasResponse.srv_v_schemas:type_name -> vtctldata.GetSrvVSchemasResponse.SrvVSchemasEntry + 323, // 116: vtctldata.GetTabletRequest.tablet_alias:type_name -> topodata.TabletAlias + 334, // 117: vtctldata.GetTabletResponse.tablet:type_name -> topodata.Tablet + 323, // 118: vtctldata.GetTabletsRequest.tablet_aliases:type_name -> topodata.TabletAlias + 333, // 119: vtctldata.GetTabletsRequest.tablet_type:type_name -> topodata.TabletType + 334, // 120: vtctldata.GetTabletsResponse.tablets:type_name -> topodata.Tablet + 323, // 121: vtctldata.GetThrottlerStatusRequest.tablet_alias:type_name -> topodata.TabletAlias + 347, // 122: vtctldata.GetThrottlerStatusResponse.status:type_name -> tabletmanagerdata.GetThrottlerStatusResponse + 124, // 123: vtctldata.GetTopologyPathResponse.cell:type_name -> vtctldata.TopologyCell + 348, // 124: vtctldata.GetUnresolvedTransactionsResponse.transactions:type_name -> query.TransactionMetadata + 348, // 125: vtctldata.GetTransactionInfoResponse.metadata:type_name -> query.TransactionMetadata + 128, // 126: vtctldata.GetTransactionInfoResponse.shard_states:type_name -> vtctldata.ShardTransactionState + 349, // 127: vtctldata.ConcludeTransactionRequest.participants:type_name -> query.Target + 323, // 128: vtctldata.GetVersionRequest.tablet_alias:type_name -> topodata.TabletAlias + 331, // 129: vtctldata.GetVSchemaResponse.v_schema:type_name -> vschema.Keyspace + 14, // 130: vtctldata.GetWorkflowsResponse.workflows:type_name -> vtctldata.Workflow + 323, // 131: vtctldata.InitShardPrimaryRequest.primary_elect_tablet_alias:type_name -> topodata.TabletAlias + 324, // 132: vtctldata.InitShardPrimaryRequest.wait_replicas_timeout:type_name -> vttime.Duration + 319, // 133: vtctldata.InitShardPrimaryResponse.events:type_name -> logutil.Event + 330, // 134: vtctldata.LaunchSchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID + 301, // 135: vtctldata.LaunchSchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.LaunchSchemaMigrationResponse.RowsAffectedByShardEntry + 331, // 136: vtctldata.LookupVindexCreateRequest.vindex:type_name -> vschema.Keyspace + 333, // 137: vtctldata.LookupVindexCreateRequest.tablet_types:type_name -> topodata.TabletType + 320, // 138: vtctldata.LookupVindexCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 9, // 139: vtctldata.MaterializeCreateRequest.settings:type_name -> vtctldata.MaterializeSettings + 8, // 140: vtctldata.WorkflowAddTablesRequest.table_settings:type_name -> vtctldata.TableMaterializeSettings + 0, // 141: vtctldata.WorkflowAddTablesRequest.materialization_intent:type_name -> vtctldata.MaterializationIntent + 333, // 142: vtctldata.MigrateCreateRequest.tablet_types:type_name -> topodata.TabletType + 320, // 143: vtctldata.MigrateCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 333, // 144: vtctldata.MoveTablesCreateRequest.tablet_types:type_name -> topodata.TabletType + 320, // 145: vtctldata.MoveTablesCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 13, // 146: vtctldata.MoveTablesCreateRequest.workflow_options:type_name -> vtctldata.WorkflowOptions + 302, // 147: vtctldata.MoveTablesCreateResponse.details:type_name -> vtctldata.MoveTablesCreateResponse.TabletInfo + 323, // 148: vtctldata.PingTabletRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 149: vtctldata.PlannedReparentShardRequest.new_primary:type_name -> topodata.TabletAlias + 323, // 150: vtctldata.PlannedReparentShardRequest.avoid_primary:type_name -> topodata.TabletAlias + 324, // 151: vtctldata.PlannedReparentShardRequest.wait_replicas_timeout:type_name -> vttime.Duration + 324, // 152: vtctldata.PlannedReparentShardRequest.tolerable_replication_lag:type_name -> vttime.Duration + 323, // 153: vtctldata.PlannedReparentShardRequest.expected_primary:type_name -> topodata.TabletAlias + 323, // 154: vtctldata.PlannedReparentShardResponse.promoted_primary:type_name -> topodata.TabletAlias + 319, // 155: vtctldata.PlannedReparentShardResponse.events:type_name -> logutil.Event + 323, // 156: vtctldata.RefreshStateRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 157: vtctldata.ReloadSchemaRequest.tablet_alias:type_name -> topodata.TabletAlias + 319, // 158: vtctldata.ReloadSchemaKeyspaceResponse.events:type_name -> logutil.Event + 319, // 159: vtctldata.ReloadSchemaShardResponse.events:type_name -> logutil.Event + 323, // 160: vtctldata.ReparentTabletRequest.tablet:type_name -> topodata.TabletAlias + 323, // 161: vtctldata.ReparentTabletResponse.primary:type_name -> topodata.TabletAlias + 333, // 162: vtctldata.ReshardCreateRequest.tablet_types:type_name -> topodata.TabletType + 320, // 163: vtctldata.ReshardCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 13, // 164: vtctldata.ReshardCreateRequest.workflow_options:type_name -> vtctldata.WorkflowOptions + 323, // 165: vtctldata.RestoreFromBackupRequest.tablet_alias:type_name -> topodata.TabletAlias + 322, // 166: vtctldata.RestoreFromBackupRequest.backup_time:type_name -> vttime.Time + 322, // 167: vtctldata.RestoreFromBackupRequest.restore_to_timestamp:type_name -> vttime.Time + 323, // 168: vtctldata.RestoreFromBackupResponse.tablet_alias:type_name -> topodata.TabletAlias + 319, // 169: vtctldata.RestoreFromBackupResponse.event:type_name -> logutil.Event + 330, // 170: vtctldata.RetrySchemaMigrationRequest.caller_id:type_name -> vtrpc.CallerID + 303, // 171: vtctldata.RetrySchemaMigrationResponse.rows_affected_by_shard:type_name -> vtctldata.RetrySchemaMigrationResponse.RowsAffectedByShardEntry + 323, // 172: vtctldata.RunHealthCheckRequest.tablet_alias:type_name -> topodata.TabletAlias + 321, // 173: vtctldata.SetKeyspaceDurabilityPolicyResponse.keyspace:type_name -> topodata.Keyspace + 321, // 174: vtctldata.SetKeyspaceShardingInfoResponse.keyspace:type_name -> topodata.Keyspace + 325, // 175: vtctldata.SetShardIsPrimaryServingResponse.shard:type_name -> topodata.Shard + 333, // 176: vtctldata.SetShardTabletControlRequest.tablet_type:type_name -> topodata.TabletType + 325, // 177: vtctldata.SetShardTabletControlResponse.shard:type_name -> topodata.Shard + 323, // 178: vtctldata.SetWritableRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 179: vtctldata.ShardReplicationAddRequest.tablet_alias:type_name -> topodata.TabletAlias + 350, // 180: vtctldata.ShardReplicationFixResponse.error:type_name -> topodata.ShardReplicationError + 304, // 181: vtctldata.ShardReplicationPositionsResponse.replication_statuses:type_name -> vtctldata.ShardReplicationPositionsResponse.ReplicationStatusesEntry + 305, // 182: vtctldata.ShardReplicationPositionsResponse.tablet_map:type_name -> vtctldata.ShardReplicationPositionsResponse.TabletMapEntry + 323, // 183: vtctldata.ShardReplicationRemoveRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 184: vtctldata.SleepTabletRequest.tablet_alias:type_name -> topodata.TabletAlias + 324, // 185: vtctldata.SleepTabletRequest.duration:type_name -> vttime.Duration + 351, // 186: vtctldata.SourceShardAddRequest.key_range:type_name -> topodata.KeyRange + 325, // 187: vtctldata.SourceShardAddResponse.shard:type_name -> topodata.Shard + 325, // 188: vtctldata.SourceShardDeleteResponse.shard:type_name -> topodata.Shard + 323, // 189: vtctldata.StartReplicationRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 190: vtctldata.StopReplicationRequest.tablet_alias:type_name -> topodata.TabletAlias + 323, // 191: vtctldata.TabletExternallyReparentedRequest.tablet:type_name -> topodata.TabletAlias + 323, // 192: vtctldata.TabletExternallyReparentedResponse.new_primary:type_name -> topodata.TabletAlias + 323, // 193: vtctldata.TabletExternallyReparentedResponse.old_primary:type_name -> topodata.TabletAlias + 326, // 194: vtctldata.UpdateCellInfoRequest.cell_info:type_name -> topodata.CellInfo + 326, // 195: vtctldata.UpdateCellInfoResponse.cell_info:type_name -> topodata.CellInfo + 352, // 196: vtctldata.UpdateCellsAliasRequest.cells_alias:type_name -> topodata.CellsAlias + 352, // 197: vtctldata.UpdateCellsAliasResponse.cells_alias:type_name -> topodata.CellsAlias + 306, // 198: vtctldata.ValidateResponse.results_by_keyspace:type_name -> vtctldata.ValidateResponse.ResultsByKeyspaceEntry + 307, // 199: vtctldata.ValidateKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateKeyspaceResponse.ResultsByShardEntry + 308, // 200: vtctldata.ValidateSchemaKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateSchemaKeyspaceResponse.ResultsByShardEntry + 309, // 201: vtctldata.ValidateVersionKeyspaceResponse.results_by_shard:type_name -> vtctldata.ValidateVersionKeyspaceResponse.ResultsByShardEntry + 310, // 202: vtctldata.ValidateVSchemaResponse.results_by_shard:type_name -> vtctldata.ValidateVSchemaResponse.ResultsByShardEntry + 333, // 203: vtctldata.VDiffCreateRequest.tablet_types:type_name -> topodata.TabletType + 320, // 204: vtctldata.VDiffCreateRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 324, // 205: vtctldata.VDiffCreateRequest.filtered_replication_wait_time:type_name -> vttime.Duration + 324, // 206: vtctldata.VDiffCreateRequest.wait_update_interval:type_name -> vttime.Duration + 324, // 207: vtctldata.VDiffCreateRequest.max_diff_duration:type_name -> vttime.Duration + 311, // 208: vtctldata.VDiffShowResponse.tablet_responses:type_name -> vtctldata.VDiffShowResponse.TabletResponsesEntry + 312, // 209: vtctldata.WorkflowDeleteResponse.details:type_name -> vtctldata.WorkflowDeleteResponse.TabletInfo + 316, // 210: vtctldata.WorkflowStatusResponse.table_copy_state:type_name -> vtctldata.WorkflowStatusResponse.TableCopyStateEntry + 317, // 211: vtctldata.WorkflowStatusResponse.shard_streams:type_name -> vtctldata.WorkflowStatusResponse.ShardStreamsEntry + 333, // 212: vtctldata.WorkflowSwitchTrafficRequest.tablet_types:type_name -> topodata.TabletType + 324, // 213: vtctldata.WorkflowSwitchTrafficRequest.max_replication_lag_allowed:type_name -> vttime.Duration + 324, // 214: vtctldata.WorkflowSwitchTrafficRequest.timeout:type_name -> vttime.Duration + 353, // 215: vtctldata.WorkflowUpdateRequest.tablet_request:type_name -> tabletmanagerdata.UpdateVReplicationWorkflowRequest + 318, // 216: vtctldata.WorkflowUpdateResponse.details:type_name -> vtctldata.WorkflowUpdateResponse.TabletInfo + 354, // 217: vtctldata.GetMirrorRulesResponse.mirror_rules:type_name -> vschema.MirrorRules + 333, // 218: vtctldata.WorkflowMirrorTrafficRequest.tablet_types:type_name -> topodata.TabletType + 279, // 219: vtctldata.Workflow.ShardStreamsEntry.value:type_name -> vtctldata.Workflow.ShardStream + 280, // 220: vtctldata.Workflow.ShardStream.streams:type_name -> vtctldata.Workflow.Stream + 355, // 221: vtctldata.Workflow.ShardStream.tablet_controls:type_name -> topodata.Shard.TabletControl + 323, // 222: vtctldata.Workflow.Stream.tablet:type_name -> topodata.TabletAlias + 356, // 223: vtctldata.Workflow.Stream.binlog_source:type_name -> binlogdata.BinlogSource + 322, // 224: vtctldata.Workflow.Stream.transaction_timestamp:type_name -> vttime.Time + 322, // 225: vtctldata.Workflow.Stream.time_updated:type_name -> vttime.Time + 281, // 226: vtctldata.Workflow.Stream.copy_states:type_name -> vtctldata.Workflow.Stream.CopyState + 282, // 227: vtctldata.Workflow.Stream.logs:type_name -> vtctldata.Workflow.Stream.Log + 283, // 228: vtctldata.Workflow.Stream.throttler_status:type_name -> vtctldata.Workflow.Stream.ThrottlerStatus + 333, // 229: vtctldata.Workflow.Stream.tablet_types:type_name -> topodata.TabletType + 320, // 230: vtctldata.Workflow.Stream.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference + 322, // 231: vtctldata.Workflow.Stream.Log.created_at:type_name -> vttime.Time + 322, // 232: vtctldata.Workflow.Stream.Log.updated_at:type_name -> vttime.Time + 322, // 233: vtctldata.Workflow.Stream.ThrottlerStatus.time_throttled:type_name -> vttime.Time + 286, // 234: vtctldata.ApplyVSchemaResponse.UnknownVindexParamsEntry.value:type_name -> vtctldata.ApplyVSchemaResponse.ParamList + 12, // 235: vtctldata.FindAllShardsInKeyspaceResponse.ShardsEntry.value:type_name -> vtctldata.Shard + 352, // 236: vtctldata.GetCellsAliasesResponse.AliasesEntry.value:type_name -> topodata.CellsAlias + 357, // 237: vtctldata.GetShardReplicationResponse.ShardReplicationByCellEntry.value:type_name -> topodata.ShardReplication + 298, // 238: vtctldata.GetSrvKeyspaceNamesResponse.NamesEntry.value:type_name -> vtctldata.GetSrvKeyspaceNamesResponse.NameList + 358, // 239: vtctldata.GetSrvKeyspacesResponse.SrvKeyspacesEntry.value:type_name -> topodata.SrvKeyspace + 346, // 240: vtctldata.GetSrvVSchemasResponse.SrvVSchemasEntry.value:type_name -> vschema.SrvVSchema + 323, // 241: vtctldata.MoveTablesCreateResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias + 359, // 242: vtctldata.ShardReplicationPositionsResponse.ReplicationStatusesEntry.value:type_name -> replicationdata.Status + 334, // 243: vtctldata.ShardReplicationPositionsResponse.TabletMapEntry.value:type_name -> topodata.Tablet + 239, // 244: vtctldata.ValidateResponse.ResultsByKeyspaceEntry.value:type_name -> vtctldata.ValidateKeyspaceResponse + 245, // 245: vtctldata.ValidateKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse + 245, // 246: vtctldata.ValidateSchemaKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse + 245, // 247: vtctldata.ValidateVersionKeyspaceResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse + 245, // 248: vtctldata.ValidateVSchemaResponse.ResultsByShardEntry.value:type_name -> vtctldata.ValidateShardResponse + 360, // 249: vtctldata.VDiffShowResponse.TabletResponsesEntry.value:type_name -> tabletmanagerdata.VDiffResponse + 323, // 250: vtctldata.WorkflowDeleteResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias + 3, // 251: vtctldata.WorkflowStatusResponse.TableCopyState.phase:type_name -> vtctldata.TableCopyPhase + 323, // 252: vtctldata.WorkflowStatusResponse.ShardStreamState.tablet:type_name -> topodata.TabletAlias + 314, // 253: vtctldata.WorkflowStatusResponse.ShardStreams.streams:type_name -> vtctldata.WorkflowStatusResponse.ShardStreamState + 313, // 254: vtctldata.WorkflowStatusResponse.TableCopyStateEntry.value:type_name -> vtctldata.WorkflowStatusResponse.TableCopyState + 315, // 255: vtctldata.WorkflowStatusResponse.ShardStreamsEntry.value:type_name -> vtctldata.WorkflowStatusResponse.ShardStreams + 323, // 256: vtctldata.WorkflowUpdateResponse.TabletInfo.tablet:type_name -> topodata.TabletAlias + 257, // [257:257] is the sub-list for method output_type + 257, // [257:257] is the sub-list for method input_type + 257, // [257:257] is the sub-list for extension type_name + 257, // [257:257] is the sub-list for extension extendee + 0, // [0:257] is the sub-list for field type_name } func init() { file_vtctldata_proto_init() } diff --git a/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go b/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go index 6f189a63a0e..9981108ce78 100644 --- a/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go +++ b/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go @@ -1495,6 +1495,8 @@ func (m *EmergencyReparentShardRequest) CloneVT() *EmergencyReparentShardRequest r.PreventCrossCellPromotion = m.PreventCrossCellPromotion r.WaitForAllTablets = m.WaitForAllTablets r.ExpectedPrimary = m.ExpectedPrimary.CloneVT() + r.WaitForRelayLogsMode = m.WaitForRelayLogsMode + r.WaitForRelayLogsTabletCount = m.WaitForRelayLogsTabletCount if rhs := m.IgnoreReplicas; rhs != nil { tmpContainer := make([]*topodata.TabletAlias, len(rhs)) for k, v := range rhs { @@ -10513,6 +10515,16 @@ func (m *EmergencyReparentShardRequest) MarshalToSizedBufferVT(dAtA []byte) (int i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.WaitForRelayLogsTabletCount != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.WaitForRelayLogsTabletCount)) + i-- + dAtA[i] = 0x50 + } + if m.WaitForRelayLogsMode != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.WaitForRelayLogsMode)) + i-- + dAtA[i] = 0x48 + } if m.ExpectedPrimary != nil { size, err := m.ExpectedPrimary.MarshalToSizedBufferVT(dAtA[:i]) if err != nil { @@ -24314,6 +24326,12 @@ func (m *EmergencyReparentShardRequest) SizeVT() (n int) { l = m.ExpectedPrimary.SizeVT() n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.WaitForRelayLogsMode != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.WaitForRelayLogsMode)) + } + if m.WaitForRelayLogsTabletCount != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.WaitForRelayLogsTabletCount)) + } n += len(m.unknownFields) return n } @@ -40856,6 +40874,44 @@ func (m *EmergencyReparentShardRequest) UnmarshalVT(dAtA []byte) error { return err } iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WaitForRelayLogsMode", wireType) + } + m.WaitForRelayLogsMode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WaitForRelayLogsMode |= replicationdata.WaitForRelayLogsMode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WaitForRelayLogsTabletCount", wireType) + } + m.WaitForRelayLogsTabletCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WaitForRelayLogsTabletCount |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/go/vt/vtctl/grpcvtctldserver/server.go b/go/vt/vtctl/grpcvtctldserver/server.go index b517b526f5c..55cb896cc5b 100644 --- a/go/vt/vtctl/grpcvtctldserver/server.go +++ b/go/vt/vtctl/grpcvtctldserver/server.go @@ -1304,6 +1304,8 @@ func (s *VtctldServer) EmergencyReparentShard(ctx context.Context, req *vtctldat span.Annotate("wait_replicas_timeout_sec", waitReplicasTimeout.Seconds()) span.Annotate("prevent_cross_cell_promotion", req.PreventCrossCellPromotion) span.Annotate("wait_for_all_tablets", req.WaitForAllTablets) + span.Annotate("wait_for_relay_logs_mode", req.WaitForRelayLogsMode) + span.Annotate("wait_for_relay_logs_tablet_count", req.WaitForRelayLogsTabletCount) m := sync.RWMutex{} logstream := []*logutilpb.Event{} @@ -1314,16 +1316,22 @@ func (s *VtctldServer) EmergencyReparentShard(ctx context.Context, req *vtctldat logstream = append(logstream, e) }) + if req.WaitForRelayLogsMode == replicationdatapb.WaitForRelayLogsMode_COUNT && req.WaitForRelayLogsTabletCount == 0 { + return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "WaitForRelaylogsTabletCount field must be > 0 when WaitForRelayLogsMode field is set to COUNT") + } + ev, err := reparentutil.NewEmergencyReparenter(s.ts, s.tmc, logger).ReparentShard(ctx, req.Keyspace, req.Shard, reparentutil.EmergencyReparentOptions{ - NewPrimaryAlias: req.NewPrimary, - IgnoreReplicas: sets.New(ignoreReplicaAliases...), - WaitReplicasTimeout: waitReplicasTimeout, - WaitAllTablets: req.WaitForAllTablets, - PreventCrossCellPromotion: req.PreventCrossCellPromotion, - ExpectedPrimaryAlias: req.ExpectedPrimary, + NewPrimaryAlias: req.NewPrimary, + IgnoreReplicas: sets.New(ignoreReplicaAliases...), + WaitReplicasTimeout: waitReplicasTimeout, + WaitAllTablets: req.WaitForAllTablets, + PreventCrossCellPromotion: req.PreventCrossCellPromotion, + ExpectedPrimaryAlias: req.ExpectedPrimary, + WaitForRelayLogsMode: req.WaitForRelayLogsMode, + WaitForRelayLogsTabletCount: req.WaitForRelayLogsTabletCount, }, ) diff --git a/go/vt/vtctl/reparentutil/emergency_reparenter.go b/go/vt/vtctl/reparentutil/emergency_reparenter.go index 3c5b0658af3..33ec860cabb 100644 --- a/go/vt/vtctl/reparentutil/emergency_reparenter.go +++ b/go/vt/vtctl/reparentutil/emergency_reparenter.go @@ -63,6 +63,11 @@ type EmergencyReparentOptions struct { PreventCrossCellPromotion bool ExpectedPrimaryAlias *topodatapb.TabletAlias + // WaitForRelayLogsMode + TabletCount determines how many tablets + // are used to apply relay logs before candidate selection. + WaitForRelayLogsMode replicationdatapb.WaitForRelayLogsMode + WaitForRelayLogsTabletCount int64 + // Private options managed internally. We use value passing to avoid leaking // these details back out. lockAction string @@ -101,6 +106,11 @@ func (erp *EmergencyReparenter) ReparentShard(ctx context.Context, keyspace stri var err error statsLabels := []string{keyspace, shard} + // convert DEFAULT mode to replicationdatapb.WaitForRelayLogsMode_ALL. + if opts.WaitForRelayLogsMode == replicationdatapb.WaitForRelayLogsMode_DEFAULT { + opts.WaitForRelayLogsMode = replicationdatapb.WaitForRelayLogsMode_ALL + } + opts.lockAction = erp.getLockAction(opts.NewPrimaryAlias) // First step is to lock the shard for the given operation, if not already locked if err = topo.CheckShardLocked(ctx, keyspace, shard); err != nil { @@ -221,7 +231,9 @@ func (erp *EmergencyReparenter) reparentShardLocked(ctx context.Context, ev *eve return err } // Restrict the valid candidates list. We remove any tablet which is of the type DRAINED, RESTORE or BACKUP. - validCandidates, err = restrictValidCandidates(validCandidates, tabletMap) + // When WaitForRelayLogsMode == replicationpb.WaitForRelayLogsMode_MAJORITY or _COUNT, the list is further + // reduced to a subset of most-advanced candidates in terms of replication relaylog positions. + validCandidates, err = restrictValidCandidates(validCandidates, tabletMap, opts, erp.logger) if err != nil { return err } else if len(validCandidates) == 0 { diff --git a/go/vt/vtctl/reparentutil/replication.go b/go/vt/vtctl/reparentutil/replication.go index 4777499589d..a22b5bb9c6c 100644 --- a/go/vt/vtctl/reparentutil/replication.go +++ b/go/vt/vtctl/reparentutil/replication.go @@ -19,6 +19,7 @@ package reparentutil import ( "context" "fmt" + "slices" "sync" "time" @@ -62,7 +63,6 @@ func (rlp *RelayLogPositions) AtLeast(pos *RelayLogPositions) bool { if pos == nil { return false } - if rlp.Combined.Equal(pos.Combined) { return rlp.Executed.AtLeast(pos.Executed) } @@ -83,6 +83,31 @@ func (rlp *RelayLogPositions) IsZero() bool { return rlp.Combined.IsZero() } +// compareRelayLogPositions compares two RelayLogPositions, returning: +// 0 if both a anb b are equal positions. +// 1 if a is > than b. +// -1 if a is < than b. +// This can be used as a sort function via +// slices.SortFunc and slices.SortFuncStable. +func compareRelayLogPositions(a, b *RelayLogPositions) int { + if a.Equal(b) { + return 0 + } + if a.AtLeast(b) && !b.AtLeast(a) { + return -1 + } + return 1 +} + +// sortRelayLogPositions sorts RelayLogPositions using replication positions. +func sortRelayLogPositions(p []*RelayLogPositions) []*RelayLogPositions { + positions := p + slices.SortFunc(positions, func(a, b *RelayLogPositions) int { + return compareRelayLogPositions(a, b) + }) + return positions +} + // FindPositionsOfAllCandidates will find candidates for an emergency // reparent, and, if successful, return a mapping of those tablet aliases (as // raw strings) to their replication positions for later comparison. diff --git a/go/vt/vtctl/reparentutil/replication_test.go b/go/vt/vtctl/reparentutil/replication_test.go index 43da8786ea3..8fba191a083 100644 --- a/go/vt/vtctl/reparentutil/replication_test.go +++ b/go/vt/vtctl/reparentutil/replication_test.go @@ -1574,3 +1574,93 @@ func TestRelayLogPositions_IsZero(t *testing.T) { rlp.Executed = replication.Position{GTIDSet: gtidSet} assert.False(t, rlp.IsZero()) } + +func TestSortRelayLogPositions(t *testing.T) { + gtidSet1, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-7") + gtidSet2, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-6") + gtidSet3, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5") + gtidSet4, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-3") + gtidSet5, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-2") + gtidSet6, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-3,3e11fa47-71ca-11e1-9e33-c80aa9429563:1-9999") + gtidSet7, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-1,3e11fa47-71ca-11e1-9e33-c80aa9429563:1-999") + + testCases := []struct { + name string + in []*RelayLogPositions + wanted []*RelayLogPositions + }{ + { + name: "default", + in: []*RelayLogPositions{ + { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet4}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet6}, + Executed: replication.Position{GTIDSet: gtidSet7}, + }, + }, + wanted: []*RelayLogPositions{ + { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet6}, + Executed: replication.Position{GTIDSet: gtidSet7}, + }, + { + Combined: replication.Position{GTIDSet: gtidSet4}, + Executed: replication.Position{GTIDSet: gtidSet5}, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + positions := sortRelayLogPositions(testCase.in) + for i, wanted := range testCase.wanted { + require.Equal(t, wanted.Combined.String(), positions[i].Combined.String()) + require.Equal(t, wanted.Executed.String(), positions[i].Executed.String()) + } + }) + } +} diff --git a/go/vt/vtctl/reparentutil/util.go b/go/vt/vtctl/reparentutil/util.go index c323ff86866..fef8ad433b4 100644 --- a/go/vt/vtctl/reparentutil/util.go +++ b/go/vt/vtctl/reparentutil/util.go @@ -19,6 +19,7 @@ package reparentutil import ( "context" "fmt" + "math" "strings" "sync" "time" @@ -315,9 +316,60 @@ func getValidCandidatesAndPositionsAsList(validCandidates map[string]*RelayLogPo return validTablets, tabletPositions, nil } +// getValidCandidatesMajorityCount returns a number equal to a majority of candidates. If +// there are fewer than 3 candidates, all provided candidates are the majority. +func getValidCandidatesMajorityCount(validCandidates map[string]*RelayLogPositions) int { + totalCandidates := len(validCandidates) + if totalCandidates < 3 { + return totalCandidates + } + return int(math.Floor(float64(totalCandidates)/2) + 1) +} + +// reduceValidCandidates reduces the set of valid candidates to a subset, if required. If MAJORITY or +// COUNT replicationdatapb.WaitForRelayLogsMode is used, a subset of most-advanced candidates will be +// used by comparing positions. +func reduceValidCandidates(validCandidates map[string]*RelayLogPositions, validPositions []*RelayLogPositions, opts EmergencyReparentOptions) ( + map[string]*RelayLogPositions, error, +) { + // sort by replication positions with greatest GTID set. + validPositions = sortRelayLogPositions(validPositions) + + // reduce sorted valid positions when in MAJORITY or COUNT mode. + candidatesCount := len(validCandidates) + switch opts.WaitForRelayLogsMode { + case replicationdatapb.WaitForRelayLogsMode_MAJORITY: + candidatesCount = getValidCandidatesMajorityCount(validCandidates) + case replicationdatapb.WaitForRelayLogsMode_COUNT: + candidatesCount = int(opts.WaitForRelayLogsTabletCount) + } + + resultCandidates := make(map[string]*RelayLogPositions, candidatesCount) + for _, validPosition := range validPositions { + for tabletAlias, position := range validCandidates { + if !validPosition.Equal(position) { + continue + } + resultCandidates[tabletAlias] = position + if len(resultCandidates) == candidatesCount { + // found all candidates + return resultCandidates, nil + } + } + } + if len(resultCandidates) != candidatesCount { + // this should never happen + return resultCandidates, vterrors.Errorf(vtrpc.Code_INTERNAL, "failed to find %d candidates, found %d candidates", candidatesCount, len(resultCandidates)) + } + return resultCandidates, nil +} + // restrictValidCandidates is used to restrict some candidates from being considered eligible for becoming the intermediate source or the final promotion candidate -func restrictValidCandidates(validCandidates map[string]*RelayLogPositions, tabletMap map[string]*topo.TabletInfo) (map[string]*RelayLogPositions, error) { +func restrictValidCandidates(validCandidates map[string]*RelayLogPositions, tabletMap map[string]*topo.TabletInfo, opts EmergencyReparentOptions, logger logutil.Logger) ( + map[string]*RelayLogPositions, error, +) { restrictedValidCandidates := make(map[string]*RelayLogPositions) + validPositions := make([]*RelayLogPositions, 0, len(validCandidates)) for candidate, position := range validCandidates { candidateInfo, ok := tabletMap[candidate] if !ok { @@ -328,8 +380,11 @@ func restrictValidCandidates(validCandidates map[string]*RelayLogPositions, tabl continue } restrictedValidCandidates[candidate] = position + validPositions = append(validPositions, position) } - return restrictedValidCandidates, nil + + // reduce the number of valid candidates based on valid positions. + return reduceValidCandidates(restrictedValidCandidates, validPositions, opts) } func findCandidate( diff --git a/go/vt/vtctl/reparentutil/util_test.go b/go/vt/vtctl/reparentutil/util_test.go index f5f343d5878..3eef5b544ff 100644 --- a/go/vt/vtctl/reparentutil/util_test.go +++ b/go/vt/vtctl/reparentutil/util_test.go @@ -1765,21 +1765,52 @@ func TestWaitForCatchUp(t *testing.T) { } func TestRestrictValidCandidates(t *testing.T) { + gtidSet1, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-6") + gtidSet2, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5") + gtidSet3, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-3") + gtidSet4, _ := replication.ParseMysql56GTIDSet("3e11fa47-71ca-11e1-9e33-c80aa9429562:1-2") tests := []struct { name string + ersOptions EmergencyReparentOptions validCandidates map[string]*RelayLogPositions tabletMap map[string]*topo.TabletInfo result map[string]*RelayLogPositions }{ { - name: "remove invalid tablets", + name: "remove invalid tablets with WaitForRelayLogsMode ALL", + ersOptions: EmergencyReparentOptions{ + WaitForRelayLogsMode: replicationdatapb.WaitForRelayLogsMode_ALL, + WaitForRelayLogsTabletCount: 0, + }, validCandidates: map[string]*RelayLogPositions{ - "zone1-0000000100": {}, - "zone1-0000000101": {}, - "zone1-0000000102": {}, - "zone1-0000000103": {}, - "zone1-0000000104": {}, - "zone1-0000000105": {}, + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, + "zone1-0000000101": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000102": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000103": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000104": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000105": { + Combined: replication.Position{GTIDSet: gtidSet4}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000106": { + Combined: replication.Position{GTIDSet: gtidSet2}, // == to zone1-0000000101 + Executed: replication.Position{GTIDSet: gtidSet4}, // == to zone1-0000000101 + 1 + }, }, tabletMap: map[string]*topo.TabletInfo{ "zone1-0000000100": { @@ -1828,28 +1859,275 @@ func TestRestrictValidCandidates(t *testing.T) { }, }, "zone1-0000000105": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 105, + }, + Type: topodatapb.TabletType_BACKUP, + }, + }, + "zone1-0000000106": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 106, + }, + Type: topodatapb.TabletType_REPLICA, + }, + }, + }, + result: map[string]*RelayLogPositions{ + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, + "zone1-0000000101": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000104": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000106": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + }, + }, + { + name: "remove invalid tablets with WaitForRelayLogsMode MAJORITY", + ersOptions: EmergencyReparentOptions{ + WaitForRelayLogsMode: replicationdatapb.WaitForRelayLogsMode_MAJORITY, + WaitForRelayLogsTabletCount: 0, + }, + validCandidates: map[string]*RelayLogPositions{ + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, + "zone1-0000000101": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000102": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000103": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000104": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000105": { + Combined: replication.Position{GTIDSet: gtidSet4}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000106": { + Combined: replication.Position{GTIDSet: gtidSet2}, // == to zone1-0000000101 + Executed: replication.Position{GTIDSet: gtidSet4}, // == to zone1-0000000101 + 1 + }, + }, + tabletMap: map[string]*topo.TabletInfo{ + "zone1-0000000100": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 100, + }, + Type: topodatapb.TabletType_PRIMARY, + }, + }, + "zone1-0000000101": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 101, + }, + Type: topodatapb.TabletType_RDONLY, + }, + }, + "zone1-0000000102": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 102, + }, + Type: topodatapb.TabletType_RESTORE, + }, + }, + "zone1-0000000103": { Tablet: &topodatapb.Tablet{ Alias: &topodatapb.TabletAlias{ Cell: "zone1", Uid: 103, }, + Type: topodatapb.TabletType_DRAINED, + }, + }, + "zone1-0000000104": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 104, + }, + Type: topodatapb.TabletType_SPARE, + }, + }, + "zone1-0000000105": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 105, + }, Type: topodatapb.TabletType_BACKUP, }, }, + "zone1-0000000106": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 106, + }, + Type: topodatapb.TabletType_REPLICA, + }, + }, }, result: map[string]*RelayLogPositions{ - "zone1-0000000100": {}, - "zone1-0000000101": {}, - "zone1-0000000104": {}, + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, + "zone1-0000000101": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000106": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + }, + }, + { + name: "remove invalid tablets with WaitForRelayLogsMode COUNT", + ersOptions: EmergencyReparentOptions{ + WaitForRelayLogsMode: replicationdatapb.WaitForRelayLogsMode_COUNT, + WaitForRelayLogsTabletCount: 1, + }, + validCandidates: map[string]*RelayLogPositions{ + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, + "zone1-0000000101": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000102": { + Combined: replication.Position{GTIDSet: gtidSet2}, + Executed: replication.Position{GTIDSet: gtidSet3}, + }, + "zone1-0000000103": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000104": { + Combined: replication.Position{GTIDSet: gtidSet3}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000105": { + Combined: replication.Position{GTIDSet: gtidSet4}, + Executed: replication.Position{GTIDSet: gtidSet4}, + }, + "zone1-0000000106": { + Combined: replication.Position{GTIDSet: gtidSet2}, // == to zone1-0000000101 + Executed: replication.Position{GTIDSet: gtidSet4}, // == to zone1-0000000101 + 1 + }, + }, + tabletMap: map[string]*topo.TabletInfo{ + "zone1-0000000100": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 100, + }, + Type: topodatapb.TabletType_PRIMARY, + }, + }, + "zone1-0000000101": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 101, + }, + Type: topodatapb.TabletType_RDONLY, + }, + }, + "zone1-0000000102": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 102, + }, + Type: topodatapb.TabletType_RESTORE, + }, + }, + "zone1-0000000103": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 103, + }, + Type: topodatapb.TabletType_DRAINED, + }, + }, + "zone1-0000000104": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 104, + }, + Type: topodatapb.TabletType_SPARE, + }, + }, + "zone1-0000000105": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 105, + }, + Type: topodatapb.TabletType_BACKUP, + }, + }, + "zone1-0000000106": { + Tablet: &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "zone1", + Uid: 106, + }, + Type: topodatapb.TabletType_REPLICA, + }, + }, + }, + result: map[string]*RelayLogPositions{ + "zone1-0000000100": { + Combined: replication.Position{GTIDSet: gtidSet1}, + Executed: replication.Position{GTIDSet: gtidSet2}, + }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - res, err := restrictValidCandidates(test.validCandidates, test.tabletMap) + logger := logutil.NewMemoryLogger() + res, err := restrictValidCandidates(test.validCandidates, test.tabletMap, test.ersOptions, logger) assert.NoError(t, err) - assert.Equal(t, res, test.result) + assert.EqualValues(t, test.result, res) }) } } @@ -2117,3 +2395,18 @@ func TestGetBackupCandidates(t *testing.T) { }) } } + +func TestGetValidCandidatesMajorityCount(t *testing.T) { + buildCandidatesFunc := func(length int) map[string]*RelayLogPositions { + candidates := make(map[string]*RelayLogPositions, length) + for i := 1; i <= length; i++ { + candidates[fmt.Sprintf("zone1-%d", i)] = &RelayLogPositions{} + } + return candidates + } + require.Equal(t, 1, getValidCandidatesMajorityCount(buildCandidatesFunc(1))) + require.Equal(t, 2, getValidCandidatesMajorityCount(buildCandidatesFunc(2))) + require.Equal(t, 2, getValidCandidatesMajorityCount(buildCandidatesFunc(3))) + require.Equal(t, 3, getValidCandidatesMajorityCount(buildCandidatesFunc(5))) + require.Equal(t, 5, getValidCandidatesMajorityCount(buildCandidatesFunc(9))) +} diff --git a/go/vt/vtorc/config/config.go b/go/vt/vtorc/config/config.go index 7ba72ef1c20..1cbcee4939d 100644 --- a/go/vt/vtorc/config/config.go +++ b/go/vt/vtorc/config/config.go @@ -17,11 +17,17 @@ package config import ( + "fmt" + "os" + "slices" + "strings" "time" "github.com/spf13/pflag" + "github.com/spf13/viper" "vitess.io/vitess/go/viperutil" + replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" vtorcdatapb "vitess.io/vitess/go/vt/proto/vtorcdata" "vitess.io/vitess/go/vt/servenv" ) @@ -231,6 +237,44 @@ var ( Dynamic: true, }, ) + + waitForRelayLogsMode = viperutil.Configure( + "wait-for-relaylogs-mode", + viperutil.Options[replicationdatapb.WaitForRelayLogsMode]{ + FlagName: "wait-for-relaylogs-mode", + Default: replicationdatapb.WaitForRelayLogsMode_ALL, + Dynamic: true, + GetFunc: func(v *viper.Viper) func(key string) replicationdatapb.WaitForRelayLogsMode { + return func(key string) replicationdatapb.WaitForRelayLogsMode { + modeName := v.GetString(key) + modeCode, ok := replicationdatapb.WaitForRelayLogsMode_value[strings.ToUpper(modeName)] + if !ok { + var allModes []string + for k := range replicationdatapb.WaitForRelayLogsMode_value { + allModes = append(allModes, k) + } + slices.Sort(allModes) + + fmt.Printf("Invalid option: %v\n", modeName) + fmt.Printf("Usage: --wait-for-relaylogs-mode {%s}\n", strings.Join(allModes, " | ")) + + os.Exit(1) + return -1 + } + return replicationdatapb.WaitForRelayLogsMode(modeCode) + } + }, + }, + ) + + waitForRelayLogsTabletCount = viperutil.Configure( + "wait-for-relaylogs-tablet-count", + viperutil.Options[int64]{ + FlagName: "wait-for-relaylogs-tablet-count", + Default: 0, + Dynamic: true, + }, + ) ) func init() { @@ -261,6 +305,10 @@ func registerFlags(fs *pflag.FlagSet) { fs.Bool("change-tablets-with-errant-gtid-to-drained", convertTabletsWithErrantGTIDs.Default(), "Whether VTOrc should be changing the type of tablets with errant GTIDs to DRAINED") fs.Bool("enable-primary-disk-stalled-recovery", enablePrimaryDiskStalledRecovery.Default(), "Whether VTOrc should detect a stalled disk on the primary and failover") + waitForRelayLogsModeDefaultStr := replicationdatapb.WaitForRelayLogsMode_name[int32(waitForRelayLogsMode.Default())] + fs.String("wait-for-relaylogs-mode", waitForRelayLogsModeDefaultStr, "Specifies the number of tablets to wait for relaylog applying during an EmergencyReparentShard action. ALL: wait for all tablets, MAJORITY: wait for a majority of tablets, COUNT: wait for an exact number of tablets (using --wait-for-relaylogs-tablet-count flag)") + fs.Int64("wait-for-relaylogs-tablet-count", waitForRelayLogsTabletCount.Default(), "Specifies the exact number of tablets to wait for relaylogs during EmergencyReparentShard actions. This setting must be > 0 when --wait-for-relaylogs-mode=COUNT is set") + viperutil.BindFlags(fs, cell, instancePollTime, @@ -283,9 +331,19 @@ func registerFlags(fs *pflag.FlagSet) { allowRecovery, convertTabletsWithErrantGTIDs, enablePrimaryDiskStalledRecovery, + waitForRelayLogsMode, + waitForRelayLogsTabletCount, ) } +// Validate returns an error if the current configuration is invalid. +func Validate() error { + if GetWaitForRelayLogsMode() == replicationdatapb.WaitForRelayLogsMode_COUNT && GetWaitForRelayLogsTabletCount() <= 0 { + return fmt.Errorf("--wait-for-relaylogs-tablet-count must be > 0 when --wait-for-relaylogs-mode is COUNT") + } + return nil +} + // GetCell is a getter function. func GetCell() string { return cell.Get() @@ -431,6 +489,17 @@ func GetStalledDiskPrimaryRecovery() bool { return enablePrimaryDiskStalledRecovery.Get() } +// GetWaitForRelayLogsMode returns the replicationdatapb.WaitForRelayLogMode that should be used during EmergencyReparentShard actions. +func GetWaitForRelayLogsMode() replicationdatapb.WaitForRelayLogsMode { + return waitForRelayLogsMode.Get() +} + +// GetWaitForRelayLogsTabletCount returns the number of tablets to wait for applying relay logs during EmergencyReparentShard actions. +// This setting is only relevant when the wait for relaylogs mode is replicationdata.WaitForRelayLogMode_COUNT. +func GetWaitForRelayLogsTabletCount() int64 { + return waitForRelayLogsTabletCount.Get() +} + // MarkConfigurationLoaded is called once configuration has first been loaded. // Listeners on ConfigurationLoaded will get a notification func MarkConfigurationLoaded() { diff --git a/go/vt/vtorc/logic/topology_recovery.go b/go/vt/vtorc/logic/topology_recovery.go index 979fffb6807..7b603bf0ef9 100644 --- a/go/vt/vtorc/logic/topology_recovery.go +++ b/go/vt/vtorc/logic/topology_recovery.go @@ -342,10 +342,12 @@ func runEmergencyReparentOp(ctx context.Context, analysisEntry *inst.DetectionAn tablet.Keyspace, tablet.Shard, reparentutil.EmergencyReparentOptions{ - IgnoreReplicas: nil, - WaitReplicasTimeout: config.GetWaitReplicasTimeout(), - PreventCrossCellPromotion: config.GetPreventCrossCellFailover(), - WaitAllTablets: waitForAllTablets, + IgnoreReplicas: nil, + WaitReplicasTimeout: config.GetWaitReplicasTimeout(), + PreventCrossCellPromotion: config.GetPreventCrossCellFailover(), + WaitForRelayLogsMode: config.GetWaitForRelayLogsMode(), + WaitForRelayLogsTabletCount: config.GetWaitForRelayLogsTabletCount(), + WaitAllTablets: waitForAllTablets, }, ) if err != nil { diff --git a/proto/replicationdata.proto b/proto/replicationdata.proto index ce2b75653fc..d3150cc0ad7 100644 --- a/proto/replicationdata.proto +++ b/proto/replicationdata.proto @@ -115,3 +115,12 @@ message FullStatus { bool semi_sync_blocked = 24; topodata.TabletType tablet_type = 25; } + +// WaitForRelayLogsMode represents what approach to use for deciding the number +// of tablets to for the wait-for-relaylogs phase of EmergencyReparentShard. +enum WaitForRelayLogsMode { + DEFAULT = 0; + ALL = 1; + MAJORITY = 2; + COUNT = 3; +} diff --git a/proto/vtctldata.proto b/proto/vtctldata.proto index c506a5ea569..fde2e247785 100644 --- a/proto/vtctldata.proto +++ b/proto/vtctldata.proto @@ -756,6 +756,11 @@ message EmergencyReparentShardRequest { // ExpectedPrimary is the optional alias we expect to be the current primary in order for // the reparent operation to succeed. topodata.TabletAlias expected_primary = 8; + // WaitForRelayLogsMode is the mode to use during the wait for relay logs phase. + replicationdata.WaitForRelayLogsMode wait_for_relay_logs_mode = 9; + // WaitForRelayLogsTabletCount is the number of most-advanced tablets to use during the + // wait for relay logs phase. This is only relevant when using COUNT mode. + int64 wait_for_relay_logs_tablet_count = 10; } message EmergencyReparentShardResponse { diff --git a/web/vtadmin/src/proto/vtadmin.d.ts b/web/vtadmin/src/proto/vtadmin.d.ts index 3d7db5f3430..b2793542c94 100644 --- a/web/vtadmin/src/proto/vtadmin.d.ts +++ b/web/vtadmin/src/proto/vtadmin.d.ts @@ -50835,6 +50835,14 @@ export namespace replicationdata { */ public static getTypeUrl(typeUrlPrefix?: string): string; } + + /** WaitForRelayLogsMode enum. */ + enum WaitForRelayLogsMode { + DEFAULT = 0, + ALL = 1, + MAJORITY = 2, + COUNT = 3 + } } /** Namespace vschema. */ @@ -59984,6 +59992,12 @@ export namespace vtctldata { /** EmergencyReparentShardRequest expected_primary */ expected_primary?: (topodata.ITabletAlias|null); + + /** EmergencyReparentShardRequest wait_for_relay_logs_mode */ + wait_for_relay_logs_mode?: (replicationdata.WaitForRelayLogsMode|null); + + /** EmergencyReparentShardRequest wait_for_relay_logs_tablet_count */ + wait_for_relay_logs_tablet_count?: (number|Long|null); } /** Represents an EmergencyReparentShardRequest. */ @@ -60019,6 +60033,12 @@ export namespace vtctldata { /** EmergencyReparentShardRequest expected_primary. */ public expected_primary?: (topodata.ITabletAlias|null); + /** EmergencyReparentShardRequest wait_for_relay_logs_mode. */ + public wait_for_relay_logs_mode: replicationdata.WaitForRelayLogsMode; + + /** EmergencyReparentShardRequest wait_for_relay_logs_tablet_count. */ + public wait_for_relay_logs_tablet_count: (number|Long); + /** * Creates a new EmergencyReparentShardRequest instance using the specified properties. * @param [properties] Properties to set diff --git a/web/vtadmin/src/proto/vtadmin.js b/web/vtadmin/src/proto/vtadmin.js index df1cdc0f375..b6157f23fda 100644 --- a/web/vtadmin/src/proto/vtadmin.js +++ b/web/vtadmin/src/proto/vtadmin.js @@ -124066,6 +124066,24 @@ export const replicationdata = $root.replicationdata = (() => { return FullStatus; })(); + /** + * WaitForRelayLogsMode enum. + * @name replicationdata.WaitForRelayLogsMode + * @enum {number} + * @property {number} DEFAULT=0 DEFAULT value + * @property {number} ALL=1 ALL value + * @property {number} MAJORITY=2 MAJORITY value + * @property {number} COUNT=3 COUNT value + */ + replicationdata.WaitForRelayLogsMode = (function() { + const valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "DEFAULT"] = 0; + values[valuesById[1] = "ALL"] = 1; + values[valuesById[2] = "MAJORITY"] = 2; + values[valuesById[3] = "COUNT"] = 3; + return values; + })(); + return replicationdata; })(); @@ -148140,6 +148158,8 @@ export const vtctldata = $root.vtctldata = (() => { * @property {boolean|null} [prevent_cross_cell_promotion] EmergencyReparentShardRequest prevent_cross_cell_promotion * @property {boolean|null} [wait_for_all_tablets] EmergencyReparentShardRequest wait_for_all_tablets * @property {topodata.ITabletAlias|null} [expected_primary] EmergencyReparentShardRequest expected_primary + * @property {replicationdata.WaitForRelayLogsMode|null} [wait_for_relay_logs_mode] EmergencyReparentShardRequest wait_for_relay_logs_mode + * @property {number|Long|null} [wait_for_relay_logs_tablet_count] EmergencyReparentShardRequest wait_for_relay_logs_tablet_count */ /** @@ -148222,6 +148242,22 @@ export const vtctldata = $root.vtctldata = (() => { */ EmergencyReparentShardRequest.prototype.expected_primary = null; + /** + * EmergencyReparentShardRequest wait_for_relay_logs_mode. + * @member {replicationdata.WaitForRelayLogsMode} wait_for_relay_logs_mode + * @memberof vtctldata.EmergencyReparentShardRequest + * @instance + */ + EmergencyReparentShardRequest.prototype.wait_for_relay_logs_mode = 0; + + /** + * EmergencyReparentShardRequest wait_for_relay_logs_tablet_count. + * @member {number|Long} wait_for_relay_logs_tablet_count + * @memberof vtctldata.EmergencyReparentShardRequest + * @instance + */ + EmergencyReparentShardRequest.prototype.wait_for_relay_logs_tablet_count = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + /** * Creates a new EmergencyReparentShardRequest instance using the specified properties. * @function create @@ -148263,6 +148299,10 @@ export const vtctldata = $root.vtctldata = (() => { writer.uint32(/* id 7, wireType 0 =*/56).bool(message.wait_for_all_tablets); if (message.expected_primary != null && Object.hasOwnProperty.call(message, "expected_primary")) $root.topodata.TabletAlias.encode(message.expected_primary, writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim(); + if (message.wait_for_relay_logs_mode != null && Object.hasOwnProperty.call(message, "wait_for_relay_logs_mode")) + writer.uint32(/* id 9, wireType 0 =*/72).int32(message.wait_for_relay_logs_mode); + if (message.wait_for_relay_logs_tablet_count != null && Object.hasOwnProperty.call(message, "wait_for_relay_logs_tablet_count")) + writer.uint32(/* id 10, wireType 0 =*/80).int64(message.wait_for_relay_logs_tablet_count); return writer; }; @@ -148331,6 +148371,14 @@ export const vtctldata = $root.vtctldata = (() => { message.expected_primary = $root.topodata.TabletAlias.decode(reader, reader.uint32()); break; } + case 9: { + message.wait_for_relay_logs_mode = reader.int32(); + break; + } + case 10: { + message.wait_for_relay_logs_tablet_count = reader.int64(); + break; + } default: reader.skipType(tag & 7); break; @@ -148402,6 +148450,19 @@ export const vtctldata = $root.vtctldata = (() => { if (error) return "expected_primary." + error; } + if (message.wait_for_relay_logs_mode != null && message.hasOwnProperty("wait_for_relay_logs_mode")) + switch (message.wait_for_relay_logs_mode) { + default: + return "wait_for_relay_logs_mode: enum value expected"; + case 0: + case 1: + case 2: + case 3: + break; + } + if (message.wait_for_relay_logs_tablet_count != null && message.hasOwnProperty("wait_for_relay_logs_tablet_count")) + if (!$util.isInteger(message.wait_for_relay_logs_tablet_count) && !(message.wait_for_relay_logs_tablet_count && $util.isInteger(message.wait_for_relay_logs_tablet_count.low) && $util.isInteger(message.wait_for_relay_logs_tablet_count.high))) + return "wait_for_relay_logs_tablet_count: integer|Long expected"; return null; }; @@ -148450,6 +148511,39 @@ export const vtctldata = $root.vtctldata = (() => { throw TypeError(".vtctldata.EmergencyReparentShardRequest.expected_primary: object expected"); message.expected_primary = $root.topodata.TabletAlias.fromObject(object.expected_primary); } + switch (object.wait_for_relay_logs_mode) { + default: + if (typeof object.wait_for_relay_logs_mode === "number") { + message.wait_for_relay_logs_mode = object.wait_for_relay_logs_mode; + break; + } + break; + case "DEFAULT": + case 0: + message.wait_for_relay_logs_mode = 0; + break; + case "ALL": + case 1: + message.wait_for_relay_logs_mode = 1; + break; + case "MAJORITY": + case 2: + message.wait_for_relay_logs_mode = 2; + break; + case "COUNT": + case 3: + message.wait_for_relay_logs_mode = 3; + break; + } + if (object.wait_for_relay_logs_tablet_count != null) + if ($util.Long) + (message.wait_for_relay_logs_tablet_count = $util.Long.fromValue(object.wait_for_relay_logs_tablet_count)).unsigned = false; + else if (typeof object.wait_for_relay_logs_tablet_count === "string") + message.wait_for_relay_logs_tablet_count = parseInt(object.wait_for_relay_logs_tablet_count, 10); + else if (typeof object.wait_for_relay_logs_tablet_count === "number") + message.wait_for_relay_logs_tablet_count = object.wait_for_relay_logs_tablet_count; + else if (typeof object.wait_for_relay_logs_tablet_count === "object") + message.wait_for_relay_logs_tablet_count = new $util.LongBits(object.wait_for_relay_logs_tablet_count.low >>> 0, object.wait_for_relay_logs_tablet_count.high >>> 0).toNumber(); return message; }; @@ -148476,6 +148570,12 @@ export const vtctldata = $root.vtctldata = (() => { object.prevent_cross_cell_promotion = false; object.wait_for_all_tablets = false; object.expected_primary = null; + object.wait_for_relay_logs_mode = options.enums === String ? "DEFAULT" : 0; + if ($util.Long) { + let long = new $util.Long(0, 0, false); + object.wait_for_relay_logs_tablet_count = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.wait_for_relay_logs_tablet_count = options.longs === String ? "0" : 0; } if (message.keyspace != null && message.hasOwnProperty("keyspace")) object.keyspace = message.keyspace; @@ -148496,6 +148596,13 @@ export const vtctldata = $root.vtctldata = (() => { object.wait_for_all_tablets = message.wait_for_all_tablets; if (message.expected_primary != null && message.hasOwnProperty("expected_primary")) object.expected_primary = $root.topodata.TabletAlias.toObject(message.expected_primary, options); + if (message.wait_for_relay_logs_mode != null && message.hasOwnProperty("wait_for_relay_logs_mode")) + object.wait_for_relay_logs_mode = options.enums === String ? $root.replicationdata.WaitForRelayLogsMode[message.wait_for_relay_logs_mode] === undefined ? message.wait_for_relay_logs_mode : $root.replicationdata.WaitForRelayLogsMode[message.wait_for_relay_logs_mode] : message.wait_for_relay_logs_mode; + if (message.wait_for_relay_logs_tablet_count != null && message.hasOwnProperty("wait_for_relay_logs_tablet_count")) + if (typeof message.wait_for_relay_logs_tablet_count === "number") + object.wait_for_relay_logs_tablet_count = options.longs === String ? String(message.wait_for_relay_logs_tablet_count) : message.wait_for_relay_logs_tablet_count; + else + object.wait_for_relay_logs_tablet_count = options.longs === String ? $util.Long.prototype.toString.call(message.wait_for_relay_logs_tablet_count) : options.longs === Number ? new $util.LongBits(message.wait_for_relay_logs_tablet_count.low >>> 0, message.wait_for_relay_logs_tablet_count.high >>> 0).toNumber() : message.wait_for_relay_logs_tablet_count; return object; };