-
Notifications
You must be signed in to change notification settings - Fork 6.2k
external workload: wire GCV2 coordination #69521
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
15c9eb7
8fa56b2
4e58167
b08d1c3
caa2a95
780583e
afdb3e2
a544f8f
51df1b2
da94530
268aac7
75ede41
7570947
d76cf6b
d260bb8
23f740c
8fc1a4c
8593452
2babebc
5aa3390
f60833f
890ad29
b677f79
ab0e556
848d589
24c71de
2e3d8d3
c9f91f8
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 |
|---|---|---|
|
|
@@ -98,6 +98,7 @@ import ( | |
| "github.com/tikv/client-go/v2/tikv" | ||
| "github.com/tikv/client-go/v2/tikvrpc" | ||
| "github.com/tikv/client-go/v2/txnkv/transaction" | ||
| pd "github.com/tikv/pd/client" | ||
| "go.uber.org/automaxprocs/maxprocs" | ||
| "go.uber.org/zap" | ||
| ) | ||
|
|
@@ -321,33 +322,81 @@ func initDeployMode(cfg *config.Config) error { | |
| } | ||
|
|
||
| func initExternalWorkloadManager(ctx context.Context, storage kv.Storage) extworkload.Manager { | ||
| if !deploymode.IsStarter() { | ||
| return nil | ||
| } | ||
| cfg := config.GetGlobalConfig().ExternalWorkload | ||
| if !cfg.Enable { | ||
| return nil | ||
| } | ||
| // Manager init is non-fatal; TiDB can continue without external workload coordination. | ||
| // Non-GCV2 roles can continue without coordination, but a dedicated GCV2 | ||
| // worker must not run without the controller. | ||
| meta := storage.GetCodec().GetKeyspaceMeta() | ||
| if meta == nil { | ||
| if cfg.Role == config.RoleGCV2Worker { | ||
| logutil.BgLogger().Fatal("external workload GCV2 role requires keyspace meta") | ||
| } | ||
| logutil.BgLogger().Warn("external workload controller enabled but keyspace meta is unavailable; TiDB will continue without external workload coordination") | ||
| return nil | ||
| } | ||
| if cfg.Role == config.RoleGCV2Worker && !pd.IsKeyspaceUsingKeyspaceLevelGC(meta) { | ||
| logutil.BgLogger().Fatal("external workload GCV2 role requires keyspace-level GC") | ||
| } | ||
| mgr, err := extworkload.NewManager(ctx, meta, cfg) | ||
| if err != nil { | ||
| if cfg.Role == config.RoleGCV2Worker { | ||
| logutil.BgLogger().Fatal("failed to initialize external workload manager for GCV2 role", zap.Error(err)) | ||
| } | ||
| logutil.BgLogger().Warn("failed to initialize external workload manager; TiDB will continue without external workload coordination", zap.Error(err)) | ||
| return nil | ||
| } | ||
| extworkload.SetManagerForStore(storage, mgr) | ||
| return mgr | ||
| } | ||
|
|
||
| func closeExternalWorkloadManager(mgr extworkload.Manager) { | ||
| func closeExternalWorkloadManager(storage kv.Storage, mgr extworkload.Manager) { | ||
| if mgr == nil { | ||
| return | ||
| } | ||
| extworkload.SetManagerForStore(storage, nil) | ||
| if err := mgr.Close(); err != nil { | ||
| logutil.BgLogger().Warn("failed to close external workload manager", zap.Error(err)) | ||
| } | ||
| } | ||
|
|
||
| func loadExternalWorkloadGCLifeTime(ctx context.Context, storage kv.Storage) (time.Duration, error) { | ||
| se, err := session.CreateSession(storage) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
| defer se.Close() | ||
| gcLifeTimeVal, err := variable.GetSysVar(vardef.TiDBGCLifetime).GetGlobalFromHook(ctx, se.GetSessionVars()) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
| gcLifeTime, err := time.ParseDuration(gcLifeTimeVal) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
| return gcLifeTime, nil | ||
| } | ||
|
|
||
| func initializeExternalWorkloadGCV2(ctx context.Context, storage kv.Storage, mgr extworkload.Manager) { | ||
|
Comment on lines
+367
to
+384
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe move those logic away into
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion. I kept this startup orchestration in |
||
| if !extworkload.IsMaster(mgr) || !pd.IsKeyspaceUsingKeyspaceLevelGC(mgr.Meta()) { | ||
| return | ||
| } | ||
| gcLifeTime, err := loadExternalWorkloadGCLifeTime(ctx, storage) | ||
| if err != nil { | ||
| logutil.BgLogger().Warn("failed to load GC life time for external workload GCV2 task; TiDB will continue without external workload coordination", zap.Error(err)) | ||
| closeExternalWorkloadManager(storage, mgr) | ||
| return | ||
| } | ||
| if err := mgr.InitializeGCV2(ctx, gcLifeTime); err != nil { | ||
| logutil.BgLogger().Warn("failed to initialize external workload GCV2 task; TiDB will continue without external workload coordination", zap.Error(err)) | ||
| closeExternalWorkloadManager(storage, mgr) | ||
| } | ||
| } | ||
|
|
||
| func main() { | ||
| fset := initFlagSet() | ||
| if args := fset.Args(); len(args) != 0 { | ||
|
|
@@ -480,9 +529,8 @@ func main() { | |
| storage, dom, err := createStoreDDLOwnerMgrAndDomain(keyspaceName) | ||
| terror.MustNil(err) | ||
| repository.SetupRepository(dom) | ||
| if deploymode.IsStarter() { | ||
| externalWorkloadManager := initExternalWorkloadManager(context.Background(), storage) | ||
| defer closeExternalWorkloadManager(externalWorkloadManager) | ||
| if externalWorkloadManager := extworkload.GetManagerFromStore(storage); externalWorkloadManager != nil { | ||
| defer closeExternalWorkloadManager(storage, externalWorkloadManager) | ||
| } | ||
| svr := createServer(storage, dom) | ||
| if standbyController != nil { | ||
|
|
@@ -631,6 +679,7 @@ func createStoreDDLOwnerMgrAndDomain(keyspaceName string) (kv.Storage, *domain.D | |
| } | ||
| } | ||
| } | ||
| externalWorkloadManager := initExternalWorkloadManager(context.Background(), storage) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| copr.GlobalMPPFailedStoreProber.Run() | ||
| mppcoordmanager.InstanceMPPCoordinatorManager.Run() | ||
| // Bootstrap a session to load information schema. | ||
|
|
@@ -642,6 +691,7 @@ func createStoreDDLOwnerMgrAndDomain(keyspaceName string) (kv.Storage, *domain.D | |
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
| initializeExternalWorkloadGCV2(context.Background(), storage, externalWorkloadManager) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| return storage, dom, nil | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
The client exposes
ErrControllerPausedas a distinct temporary scheduler outcome, but dedicated GCV2 initialization treats everyNewManagererror as fatal. A normal PAUSED response from the startup Ping is therefore indistinguishable from a permanent configuration or connectivity failure.Scope
cmd/tidb-server/main.go:348
Risk if unchanged
A deliberately paused GCV2 pool can make every dedicated worker exit non-zero and be restarted repeatedly by its supervisor, creating unnecessary controller and startup load instead of remaining predictably paused.
Evidence
dialClientreturns the annotated Ping error while preserving the typed PAUSED cause, and the dedicated-role branch immediately callsFatalfor any manager-construction error. No caller matchesErrControllerPaused, even though its contract explicitly permits callers to do so.Change request
Please handle
ErrControllerPausedaccording to an explicit pause contract, such as a clean bounded wait/retry or clean exit, and reserveFatalfor permanent invalid state. Add a startup test for a PAUSED Ping response.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I checked the current controller implementation: startup
Pingalways returns success andPingRequestcarries no worker role or paused scheduling state. Pause is enforced by the controller poller, soErrControllerPausedcannot currently be returned fromNewManageron this path. The dedicated role therefore still fails closed for actual configuration, connectivity, or initialization errors; no change was made here.