-
Notifications
You must be signed in to change notification settings - Fork 50
api: add ineligibleTables/eligible tables info when creating/updating changefeed #3932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
39711f3
a79c49a
3bd3af6
031a56a
e957e9e
89b94e9
66f7f99
d9ca704
fa0ecf7
65c607b
2fc7602
215fe05
6e0ab6a
50ee5ec
247cdfd
331dc37
514c94b
f4cfe09
539b057
07347d1
16be53d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -221,7 +221,7 @@ func (h *OpenAPIV2) CreateChangefeed(c *gin.Context) { | |
| return | ||
| } | ||
|
|
||
| ineligibleTables, _, err := getVerifiedTables(ctx, replicaCfg, kvStorage, cfg.StartTs, scheme, topic, protocol) | ||
| ineligibleTables, eligibleTables, allTables, err := getVerifiedTables(ctx, replicaCfg, kvStorage, cfg.StartTs, scheme, topic, protocol) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
|
|
@@ -284,7 +284,11 @@ func (h *OpenAPIV2) CreateChangefeed(c *gin.Context) { | |
| log.Info("Create changefeed successfully!", | ||
| zap.String("id", info.ChangefeedID.Name()), | ||
| zap.String("state", string(info.State)), | ||
| zap.String("changefeedInfo", info.String())) | ||
| zap.String("changefeedInfo", info.String()), | ||
| zap.Int("eligibleTablesLength", len(eligibleTables)), | ||
| zap.Int("ineligibleTablesLength", len(ineligibleTables)), | ||
| zap.Int("allTablesLength", len(allTables)), | ||
| ) | ||
|
|
||
| c.JSON(getStatus(c), CfInfoToAPIModel( | ||
| info, | ||
|
|
@@ -352,7 +356,46 @@ func (h *OpenAPIV2) ListChangeFeeds(c *gin.Context) { | |
| c.JSON(http.StatusOK, toListResponse(c, commonInfos)) | ||
| } | ||
|
|
||
| // VerifyTable verify table, return ineligibleTables and EligibleTables. | ||
| // GetAllTables return ineligibleTables and EligibleTables. | ||
| func (h *OpenAPIV2) GetAllTables(c *gin.Context) { | ||
| ctx := c.Request.Context() | ||
| cfg := &ChangefeedConfig{ReplicaConfig: GetDefaultReplicaConfig()} | ||
|
|
||
| if err := c.BindJSON(&cfg); err != nil { | ||
| _ = c.Error(errors.WrapError(errors.ErrAPIInvalidParam, err)) | ||
| return | ||
| } | ||
|
|
||
| // fill replicaConfig | ||
| replicaCfg := cfg.ReplicaConfig.ToInternalReplicaConfig() | ||
|
|
||
| keyspaceManager := appcontext.GetService[keyspace.Manager](appcontext.KeyspaceManager) | ||
| keyspaceName := GetKeyspaceValueWithDefault(c) | ||
| kvStorage, err := keyspaceManager.GetStorage(ctx, keyspaceName) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
|
|
||
| f, err := filter.NewFilter(replicaCfg.Filter, "", util.GetOrZero(replicaCfg.CaseSensitive), util.GetOrZero(replicaCfg.ForceReplicate)) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
| _, ineligibleTables, eligibleTables, allTables, err := schemastore. | ||
| VerifyTables(f, kvStorage, cfg.StartTs) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
| tables := &Tables{ | ||
| IneligibleTables: toAPIModelFunc(ineligibleTables), | ||
| EligibleTables: toAPIModelFunc(eligibleTables), | ||
| AllTables: toAPIModelFunc(allTables), | ||
| } | ||
| c.JSON(http.StatusOK, tables) | ||
| } | ||
|
|
||
| func (h *OpenAPIV2) VerifyTable(c *gin.Context) { | ||
| ctx := c.Request.Context() | ||
| cfg := &ChangefeedConfig{ReplicaConfig: GetDefaultReplicaConfig()} | ||
|
|
@@ -395,7 +438,7 @@ func (h *OpenAPIV2) VerifyTable(c *gin.Context) { | |
| _ = c.Error(err) | ||
| return | ||
| } | ||
| ineligibleTables, eligibleTables, err := getVerifiedTables(ctx, replicaCfg, kvStorage, cfg.StartTs, scheme, topic, protocol) | ||
| ineligibleTables, eligibleTables, allTables, err := getVerifiedTables(ctx, replicaCfg, kvStorage, cfg.StartTs, scheme, topic, protocol) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
|
|
@@ -405,18 +448,10 @@ func (h *OpenAPIV2) VerifyTable(c *gin.Context) { | |
| zap.Bool("ignoreIneligibleTable", util.GetOrZero(cfg.ReplicaConfig.IgnoreIneligibleTable)), | ||
| ) | ||
|
|
||
| toAPIModelFunc := func(tbls []string) []TableName { | ||
| var apiModels []TableName | ||
| for _, tbl := range tbls { | ||
| apiModels = append(apiModels, TableName{ | ||
| Table: tbl, | ||
| }) | ||
| } | ||
| return apiModels | ||
| } | ||
| tables := &Tables{ | ||
| IneligibleTables: toAPIModelFunc(ineligibleTables), | ||
| EligibleTables: toAPIModelFunc(eligibleTables), | ||
| AllTables: toAPIModelFunc(allTables), | ||
| } | ||
| c.JSON(http.StatusOK, tables) | ||
| } | ||
|
|
@@ -466,6 +501,19 @@ func shouldShowRunningError(state config.FeedState) bool { | |
| } | ||
| } | ||
|
|
||
| func toAPIModelFunc(tbls []common.TableName) []TableName { | ||
| var apiModels []TableName | ||
| for _, tbl := range tbls { | ||
| apiModels = append(apiModels, TableName{ | ||
| Schema: tbl.Schema, | ||
| Table: tbl.Table, | ||
| TableID: tbl.TableID, | ||
| IsPartition: tbl.IsPartition, | ||
| }) | ||
| } | ||
| return apiModels | ||
| } | ||
|
|
||
| func CfInfoToAPIModel( | ||
| info *config.ChangeFeedInfo, | ||
| status *config.ChangeFeedStatus, | ||
|
|
@@ -666,8 +714,10 @@ func (h *OpenAPIV2) ResumeChangefeed(c *gin.Context) { | |
|
|
||
| // If there is no overrideCheckpointTs, then check whether the currentCheckpointTs is smaller than gc safepoint or not. | ||
| newCheckpointTs := status.CheckpointTs | ||
| overwriteCheckpointTs := false | ||
| if cfg.OverwriteCheckpointTs != 0 { | ||
| newCheckpointTs = cfg.OverwriteCheckpointTs | ||
| overwriteCheckpointTs = true | ||
| } | ||
|
|
||
| keyspaceMeta := middleware.GetKeyspaceFromContext(c) | ||
|
|
@@ -709,13 +759,57 @@ func (h *OpenAPIV2) ResumeChangefeed(c *gin.Context) { | |
| } | ||
| }() | ||
|
|
||
| err = co.ResumeChangefeed(ctx, cfInfo.ChangefeedID, newCheckpointTs, cfg.OverwriteCheckpointTs != 0) | ||
| var ( | ||
| eligibleTables []common.TableName | ||
| ineligibleTables []common.TableName | ||
| allTables []common.TableName | ||
| ) | ||
| if overwriteCheckpointTs { | ||
| sinkURIParsed, err := url.Parse(cfInfo.SinkURI) | ||
| if err != nil { | ||
| _ = c.Error(errors.WrapError(errors.ErrSinkURIInvalid, err, cfInfo.SinkURI)) | ||
| return | ||
| } | ||
| scheme := sinkURIParsed.Scheme | ||
| topic := "" | ||
| if config.IsMQScheme(scheme) { | ||
| topic, err = helper.GetTopic(sinkURIParsed) | ||
| if err != nil { | ||
| _ = c.Error(errors.WrapError(errors.ErrSinkURIInvalid, err, cfInfo.SinkURI)) | ||
| return | ||
| } | ||
| } | ||
| protocol, _ := config.ParseSinkProtocolFromString(util.GetOrZero(cfInfo.Config.Sink.Protocol)) | ||
|
|
||
| keyspaceManager := appcontext.GetService[keyspace.Manager](appcontext.KeyspaceManager) | ||
| kvStorage, err := keyspaceManager.GetStorage(ctx, keyspaceName) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
| ineligibleTables, eligibleTables, allTables, err = getVerifiedTables(ctx, cfInfo.Config, kvStorage, newCheckpointTs, scheme, topic, protocol) | ||
| if err != nil { | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
| } | ||
|
Comment on lines
+767
to
+795
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| err = co.ResumeChangefeed(ctx, cfInfo.ChangefeedID, newCheckpointTs, overwriteCheckpointTs) | ||
| if err != nil { | ||
| needRemoveGCSafePoint = true | ||
| _ = c.Error(err) | ||
| return | ||
| } | ||
| c.Errors = nil | ||
| log.Info("Resume changefeed successfully!", | ||
| zap.String("id", cfInfo.ChangefeedID.Name()), | ||
| zap.String("state", string(cfInfo.State)), | ||
| zap.String("changefeedInfo", cfInfo.String()), | ||
| zap.Bool("overwriteCheckpointTs", overwriteCheckpointTs), | ||
| zap.Int("eligibleTablesLength", len(eligibleTables)), | ||
| zap.Int("ineligibleTablesLength", len(ineligibleTables)), | ||
| zap.Int("allTablesLength", len(allTables)), | ||
| ) | ||
| c.JSON(getStatus(c), &EmptyResponse{}) | ||
| } | ||
|
|
||
|
|
@@ -813,6 +907,11 @@ func (h *OpenAPIV2) UpdateChangefeed(c *gin.Context) { | |
| return | ||
| } | ||
|
|
||
| var ( | ||
| ineligibleTables []common.TableName | ||
| eligibleTables []common.TableName | ||
| allTables []common.TableName | ||
| ) | ||
| if configUpdated || sinkURIUpdated { | ||
| // verify replicaConfig | ||
| sinkURIParsed, err := url.Parse(oldCfInfo.SinkURI) | ||
|
|
@@ -846,7 +945,7 @@ func (h *OpenAPIV2) UpdateChangefeed(c *gin.Context) { | |
| } | ||
|
|
||
| // use checkpointTs get snapshot from kv storage | ||
| ineligibleTables, _, err := getVerifiedTables(ctx, oldCfInfo.Config, kvStorage, status.CheckpointTs, scheme, topic, protocol) | ||
| ineligibleTables, eligibleTables, allTables, err = getVerifiedTables(ctx, oldCfInfo.Config, kvStorage, status.CheckpointTs, scheme, topic, protocol) | ||
| if err != nil { | ||
| _ = c.Error(errors.ErrChangefeedUpdateRefused.GenWithStackByCause(err)) | ||
| return | ||
|
|
@@ -871,6 +970,17 @@ func (h *OpenAPIV2) UpdateChangefeed(c *gin.Context) { | |
| return | ||
| } | ||
|
|
||
| log.Info("Update changefeed successfully!", | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also add cost time in this log.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| zap.String("id", oldCfInfo.ChangefeedID.Name()), | ||
| zap.String("state", string(oldCfInfo.State)), | ||
| zap.String("changefeedInfo", oldCfInfo.String()), | ||
| zap.Bool("configUpdated", configUpdated), | ||
| zap.Bool("sinkURIUpdated", sinkURIUpdated), | ||
| zap.Int("eligibleTablesLength", len(eligibleTables)), | ||
| zap.Int("ineligibleTablesLength", len(ineligibleTables)), | ||
| zap.Int("allTables", len(allTables)), | ||
| ) | ||
|
|
||
| c.JSON(getStatus(c), CfInfoToAPIModel(oldCfInfo, status, nil)) | ||
| } | ||
|
|
||
|
|
@@ -1493,51 +1603,51 @@ func getVerifiedTables( | |
| replicaConfig *config.ReplicaConfig, | ||
| storage tidbkv.Storage, startTs uint64, | ||
| scheme string, topic string, protocol config.Protocol, | ||
| ) ([]string, []string, error) { | ||
| ) ([]common.TableName, []common.TableName, []common.TableName, error) { | ||
| f, err := filter.NewFilter(replicaConfig.Filter, "", util.GetOrZero(replicaConfig.CaseSensitive), util.GetOrZero(replicaConfig.ForceReplicate)) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
| tableInfos, ineligibleTables, eligibleTables, err := schemastore. | ||
| tableInfos, ineligibleTables, eligibleTables, allTables, err := schemastore. | ||
| VerifyTables(f, storage, startTs) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
| log.Info("verifyTables completed", | ||
| zap.Int("tableCount", len(tableInfos)), | ||
| zap.Uint64("startTs", startTs)) | ||
|
|
||
| err = f.Verify(tableInfos) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
| if !config.IsMQScheme(scheme) { | ||
| return ineligibleTables, eligibleTables, nil | ||
| return ineligibleTables, eligibleTables, allTables, nil | ||
| } | ||
|
|
||
| eventRouter, err := eventrouter.NewEventRouter(replicaConfig.Sink, topic, config.IsPulsarScheme(scheme), protocol == config.ProtocolAvro) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
| err = eventRouter.VerifyTables(tableInfos) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
|
|
||
| selectors, err := columnselector.New(replicaConfig.Sink) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
| err = selectors.VerifyTables(tableInfos, eventRouter) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| return nil, nil, nil, err | ||
| } | ||
|
|
||
| if ctx.Err() != nil { | ||
| return nil, nil, errors.Trace(ctx.Err()) | ||
| return nil, nil, nil, errors.Trace(ctx.Err()) | ||
| } | ||
|
|
||
| return ineligibleTables, eligibleTables, nil | ||
| return ineligibleTables, eligibleTables, allTables, nil | ||
| } | ||
|
|
||
| func GetKeyspaceValueWithDefault(c *gin.Context) string { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.