diff --git a/domain/BUILD.bazel b/domain/BUILD.bazel index 306623c339690..f09b57c648f58 100644 --- a/domain/BUILD.bazel +++ b/domain/BUILD.bazel @@ -134,13 +134,16 @@ go_test( "//parser/ast", "//parser/auth", "//parser/model", + "//parser/mysql", "//parser/terror", "//server", "//session", + "//sessionctx/stmtctx", "//sessionctx/variable", "//store/mockstore", "//testkit", "//testkit/testsetup", + "//types", "//util", "//util/mock", "//util/replayer", diff --git a/domain/domain.go b/domain/domain.go index b170dc0b063af..2ec661aa47847 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -153,14 +153,20 @@ type Domain struct { memoryUsageAlarmHandle *memoryusagealarm.Handle serverMemoryLimitHandle *servermemorylimit.Handle // TODO: use Run for each process in future pr - wg *util.WaitGroupEnhancedWrapper - statsUpdating atomicutil.Int32 - cancel context.CancelFunc - indexUsageSyncLease time.Duration - dumpFileGcChecker *dumpFileGcChecker - planReplayerHandle *planReplayerHandle - extractTaskHandle *ExtractHandle - expiredTimeStamp4PC types.Time + wg *util.WaitGroupEnhancedWrapper + statsUpdating atomicutil.Int32 + cancel context.CancelFunc + indexUsageSyncLease time.Duration + dumpFileGcChecker *dumpFileGcChecker + planReplayerHandle *planReplayerHandle + extractTaskHandle *ExtractHandle + expiredTimeStamp4PC struct { + // let `expiredTimeStamp4PC` use its own lock to avoid any block across domain.Reload() + // and compiler.Compile(), see issue https://github.com/pingcap/tidb/issues/45400 + sync.RWMutex + expiredTimeStamp types.Time + } + logBackupAdvancer *daemon.OwnerDaemon historicalStatsWorker *HistoricalStatsWorker ttlJobManager atomic.Pointer[ttlworker.JobManager] @@ -482,18 +488,18 @@ func (do *Domain) GetSnapshotMeta(startTS uint64) (*meta.Meta, error) { // ExpiredTimeStamp4PC gets expiredTimeStamp4PC from domain. func (do *Domain) ExpiredTimeStamp4PC() types.Time { - do.m.Lock() - defer do.m.Unlock() + do.expiredTimeStamp4PC.RLock() + defer do.expiredTimeStamp4PC.RUnlock() - return do.expiredTimeStamp4PC + return do.expiredTimeStamp4PC.expiredTimeStamp } // SetExpiredTimeStamp4PC sets the expiredTimeStamp4PC from domain. func (do *Domain) SetExpiredTimeStamp4PC(time types.Time) { - do.m.Lock() - defer do.m.Unlock() + do.expiredTimeStamp4PC.Lock() + defer do.expiredTimeStamp4PC.Unlock() - do.expiredTimeStamp4PC = time + do.expiredTimeStamp4PC.expiredTimeStamp = time } // DDL gets DDL from domain. @@ -1043,7 +1049,6 @@ func NewDomain(store kv.Storage, ddlLease time.Duration, statsLease time.Duratio slowQuery: newTopNSlowQueries(config.GetGlobalConfig().InMemSlowQueryTopNNum, time.Hour*24*7, config.GetGlobalConfig().InMemSlowQueryRecentNum), indexUsageSyncLease: idxUsageSyncLease, dumpFileGcChecker: &dumpFileGcChecker{gcLease: dumpFileGcLease, paths: []string{replayer.GetPlanReplayerDirName(), GetOptimizerTraceDirName(), GetExtractTaskDirName()}}, - expiredTimeStamp4PC: types.NewTime(types.ZeroCoreTime, mysql.TypeTimestamp, types.DefaultFsp), mdlCheckTableInfo: &mdlCheckTableInfo{ mu: sync.Mutex{}, jobsVerMap: make(map[int64]int64), @@ -1059,6 +1064,7 @@ func NewDomain(store kv.Storage, ddlLease time.Duration, statsLease time.Duratio do.serverMemoryLimitHandle = servermemorylimit.NewServerMemoryLimitHandle(do.exit) do.sysProcesses = SysProcesses{mu: &sync.RWMutex{}, procMap: make(map[uint64]sessionctx.Context)} do.initDomainSysVars() + do.expiredTimeStamp4PC.expiredTimeStamp = types.NewTime(types.ZeroCoreTime, mysql.TypeTimestamp, types.DefaultFsp) return do } diff --git a/domain/domain_test.go b/domain/domain_test.go index bd9287fe730ec..5ae256a277fb4 100644 --- a/domain/domain_test.go +++ b/domain/domain_test.go @@ -34,8 +34,11 @@ import ( "github.com/pingcap/tidb/metrics" "github.com/pingcap/tidb/parser/ast" "github.com/pingcap/tidb/parser/model" + "github.com/pingcap/tidb/parser/mysql" + "github.com/pingcap/tidb/sessionctx/stmtctx" "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/store/mockstore" + "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/mock" dto "github.com/prometheus/client_model/go" "github.com/stretchr/testify/require" @@ -187,6 +190,17 @@ func TestStatWorkRecoverFromPanic(t *testing.T) { scope := dom.GetScope("status") require.Equal(t, variable.DefaultStatusVarScopeFlag, scope) + // default expiredTimeStamp4PC = "0000-00-00 00:00:00" + ts := types.NewTime(types.ZeroCoreTime, mysql.TypeTimestamp, types.DefaultFsp) + expiredTimeStamp := dom.ExpiredTimeStamp4PC() + require.Equal(t, expiredTimeStamp, ts) + + // set expiredTimeStamp4PC to "2023-08-02 12:15:00" + ts, _ = types.ParseTimestamp(&stmtctx.StatementContext{TimeZone: time.UTC}, "2023-08-02 12:15:00") + dom.SetExpiredTimeStamp4PC(ts) + expiredTimeStamp = dom.ExpiredTimeStamp4PC() + require.Equal(t, expiredTimeStamp, ts) + err = store.Close() require.NoError(t, err)