Skip to content
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

*: Move tikv gc configuration to sysvars #21988

Merged
merged 22 commits into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
87c72ea
*: Move tikv gc configuration to sysvars
morgo Dec 24, 2020
9c4e9cc
fix make check errors
morgo Dec 24, 2020
55dc0c6
fix remaining tests
morgo Dec 24, 2020
34395c8
Merge branch 'master' into fix-gc-lifetime
morgo Dec 24, 2020
757c201
Merge remote-tracking branch 'upstream/master' into fix-gc-lifetime
morgo Dec 25, 2020
3944be0
read/write from mysql.tidb values if they exist.
morgo Dec 25, 2020
4aea44a
Merge branch 'fix-gc-lifetime' of github.com:morgo/tidb into fix-gc-l…
morgo Dec 25, 2020
1d931bc
Fix handling for auto value
morgo Dec 25, 2020
a454ad1
Add tests for new behavior
morgo Dec 25, 2020
6e3b461
Address reviewer feedback
morgo Jan 4, 2021
4fcc43d
Merge remote-tracking branch 'upstream/master' into fix-gc-lifetime
morgo Jan 4, 2021
90993cd
Address reviewer feedback
morgo Jan 4, 2021
8a73198
restore original store/tikv/gcworker
morgo Jan 4, 2021
2d45af3
Add tests for TypeDuration, min for TiKVGCRunInterval
morgo Jan 4, 2021
510ae7a
Merge remote-tracking branch 'upstream/master' into fix-gc-lifetime
morgo Jan 4, 2021
96cc636
Rename variables tikv_ -> tidb_
morgo Jan 5, 2021
e1ec48b
Update sessionctx/variable/sysvar.go
morgo Jan 5, 2021
cf5585c
Rename tikv functions
morgo Jan 5, 2021
f550923
Merge branch 'fix-gc-lifetime' of github.com:morgo/tidb into fix-gc-l…
morgo Jan 5, 2021
b89cb9e
Address reviewer feedback
morgo Jan 6, 2021
9bbf7fe
Remove GC Mode since it is no longer effective
morgo Jan 6, 2021
bb8cba4
Merge branch 'master' into fix-gc-lifetime
ti-srebot Jan 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions ddl/serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,9 +650,8 @@ func (s *testSerialSuite) TestRecoverTableByJobID(c *C) {
tk.MustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop))

// if GC enable is not exists in mysql.tidb
_, err = tk.Exec(fmt.Sprintf("recover table by job %d", jobID))
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[ddl:-1]can not get 'tikv_gc_enable'")
tk.MustExec(fmt.Sprintf("recover table by job %d", jobID))
tk.MustExec("DROP TABLE t_recover")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this behavior changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was caused by the changes in util/gcutil/gcutil.go. It now reads the sysvars to get the state of if GC is running, which check the system tables but use the default if there are no values.


err = gcutil.EnableGC(tk.Se)
c.Assert(err, IsNil)
Expand Down
7 changes: 3 additions & 4 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5376,10 +5376,9 @@ func (s *testRecoverTable) TestRecoverTable(c *C) {
// set GC safe point
tk.MustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop))

// if GC enable is not exists in mysql.tidb
_, err = tk.Exec("recover table t_recover")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[ddl:-1]can not get 'tikv_gc_enable'")
// Should recover, and we can drop it straight away.
tk.MustExec("recover table t_recover")
tk.MustExec("drop table t_recover")

err = gcutil.EnableGC(tk.Se)
c.Assert(err, IsNil)
Expand Down
4 changes: 4 additions & 0 deletions executor/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ func (s *testSerialSuite1) TestSetVar(c *C) {
tk.MustQuery("select @@global.tidb_enable_extended_stats").Check(testkit.Rows("1"))
tk.MustExec("SET GLOBAL tidb_enable_extended_stats = off")
tk.MustQuery("select @@global.tidb_enable_extended_stats").Check(testkit.Rows("0"))

// Test issue #22145
tk.MustExec(`set global sync_relay_log = "'"`)

}

func (s *testSuite5) TestTruncateIncorrectIntSessionVar(c *C) {
Expand Down
135 changes: 132 additions & 3 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,29 @@ var (
sessionExecuteCompileDurationGeneral = metrics.SessionExecuteCompileDuration.WithLabelValues(metrics.LblGeneral)
sessionExecuteParseDurationInternal = metrics.SessionExecuteParseDuration.WithLabelValues(metrics.LblInternal)
sessionExecuteParseDurationGeneral = metrics.SessionExecuteParseDuration.WithLabelValues(metrics.LblGeneral)

tiKVGCAutoConcurrency = "tikv_gc_auto_concurrency"
)

var gcVariableComments = map[string]string{
variable.TiDBGCRunInterval: "GC run interval, at least 10m, in Go format.",
variable.TiDBGCLifetime: "All versions within life time will not be collected by GC, at least 10m, in Go format.",
variable.TiDBGCConcurrency: "How many goroutines used to do GC parallel, [1, 128], default 2",
variable.TiDBGCEnable: "Current GC enable status",
variable.TiDBGCMode: "Mode of GC, \"central\" or \"distributed\"",
tiKVGCAutoConcurrency: "Let TiDB pick the concurrency automatically. If set false, tikv_gc_concurrency will be used",
variable.TiDBGCScanLockMode: "Mode of scanning locks, \"physical\" or \"legacy\"",
}

var gcVariableMap = map[string]string{
variable.TiDBGCRunInterval: "tikv_gc_run_interval",
variable.TiDBGCLifetime: "tikv_gc_life_time",
variable.TiDBGCConcurrency: "tikv_gc_concurrency",
variable.TiDBGCEnable: "tikv_gc_enable",
variable.TiDBGCMode: "tikv_gc_mode",
variable.TiDBGCScanLockMode: "tikv_gc_scan_lock_mode",
}

// Session context, it is consistent with the lifecycle of a client connection.
type Session interface {
sessionctx.Context
Expand Down Expand Up @@ -1002,7 +1023,9 @@ func (s *session) GetAllSysVars() (map[string]string, error) {
ret := make(map[string]string, len(rows))
for _, r := range rows {
k, v := r.GetString(0), r.GetString(1)
ret[k] = v
if v, err = s.checkForTiDBTableValue(k, v); err != nil {
ret[k] = v
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decides not to introduce the concept of TiKV global sysvar, the function's name seems better to be updated as well.
By the way, the function tries to get GC related variables, and pass the value v through if k is one of those variables, is that right? I'm afraid this makes the usages of this function kind of difficult to understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It passes every variable through the function, but for non-tikv vars, it is effectively a noop.

The functions don't need to be exported, so I should fix that. I have also renamed them to s.checkForTiDBTableValue(k, v) and setTiDBTableValue. Does this make it clearer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer they are invoked only when the variable is a GC configuration item, which I think has better readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I've made this change. PTAL :-)

}
return ret, nil
}
Expand All @@ -1029,7 +1052,8 @@ func (s *session) GetGlobalSysVar(name string) (string, error) {
}
return "", err
}
return sysVar, nil
// Update mysql.tidb values if required
return s.checkForTiDBTableValue(name, sysVar)
}

// SetGlobalSysVar implements GlobalVarAccessor.SetGlobalSysVar interface.
Expand All @@ -1056,13 +1080,118 @@ func (s *session) SetGlobalSysVar(name, value string) error {
return err
}
name = strings.ToLower(name)
// update mysql.tidb if required.
if err = s.setTiDBTableValue(name, sVal); err != nil {
return err
}
variable.CheckDeprecationSetSystemVar(s.sessionVars, name)
sql := fmt.Sprintf(`REPLACE %s.%s VALUES ('%s', '%s');`,
mysql.SystemDB, mysql.GlobalVariablesTable, name, sVal)
mysql.SystemDB, mysql.GlobalVariablesTable, name, escapeUserString(sVal))
_, _, err = s.ExecRestrictedSQL(sql)
return err
}

// escape user supplied string for internal SQL. Not safe for all cases, since it doesn't
// handle quote-type, sql-mode, character set breakout.
func escapeUserString(str string) string {
return strings.ReplaceAll(str, `'`, `\'`)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still doesn't looks safe enough 😕 I think we need better way to do this in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree. I searched and couldn't find anything reliable that could be imported in util or in a library. See golang/go#18478 for example.


// setTiDBTableValue handles tikv_* sysvars which need to update mysql.tidb
// for backwards compatibility. Validation has already been performed.
func (s *session) setTiDBTableValue(name, val string) error {
switch name {
case variable.TiDBGCConcurrency:
autoConcurrency := "false"
if val == "-1" {
autoConcurrency = "true"
}
sql := fmt.Sprintf(`INSERT INTO mysql.tidb (variable_name, variable_value, comment) VALUES ('%[1]s', '%[2]s', '%[3]s')
ON DUPLICATE KEY UPDATE variable_value = '%[2]s'`, tiKVGCAutoConcurrency, autoConcurrency, gcVariableComments[name])
MyonKeminta marked this conversation as resolved.
Show resolved Hide resolved
_, _, err := s.ExecRestrictedSQL(sql)
if err != nil {
return err
}
fallthrough
case variable.TiDBGCEnable, variable.TiDBGCRunInterval, variable.TiDBGCLifetime, variable.TiDBGCMode, variable.TiDBGCScanLockMode:
val = onOffToTrueFalse(val)
sql := fmt.Sprintf(`INSERT INTO mysql.tidb (variable_name, variable_value, comment) VALUES ('%[1]s', '%[2]s', '%[3]s')
ON DUPLICATE KEY UPDATE variable_value = '%[2]s'`, gcVariableMap[name], escapeUserString(val), gcVariableComments[name])
_, _, err := s.ExecRestrictedSQL(sql)
return err
}
return nil // not a TiKV sysVar
}

// In mysql.tidb the convention has been to store the string value "true"/"false",
// but sysvars use the convention ON/OFF.
func trueFalseToOnOff(str string) string {
if strings.EqualFold("true", str) {
return variable.BoolOn
} else if strings.EqualFold("false", str) {
return variable.BoolOff
}
return str
}

// In mysql.tidb the convention has been to store the string value "true"/"false",
// but sysvars use the convention ON/OFF.
func onOffToTrueFalse(str string) string {
if strings.EqualFold("ON", str) {
return "true"
} else if strings.EqualFold("OFF", str) {
return "false"
}
return str
}

// checkForTiDBTableValue handles tikv_* sysvars which need
// to read from mysql.tidb for backwards compatibility.
func (s *session) checkForTiDBTableValue(name, val string) (string, error) {
switch name {
case variable.TiDBGCConcurrency:
// Check if autoconcurrency is set
sql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM mysql.tidb WHERE VARIABLE_NAME='%s';`, tiKVGCAutoConcurrency)
autoConcurrencyVal, err := s.getExecRet(s, sql)
if err == nil && strings.EqualFold(autoConcurrencyVal, "true") {
return "-1", nil // convention for "AUTO"
}
fallthrough
case variable.TiDBGCEnable, variable.TiDBGCRunInterval, variable.TiDBGCLifetime,
variable.TiDBGCMode, variable.TiDBGCScanLockMode:
sql := fmt.Sprintf(`SELECT VARIABLE_VALUE FROM mysql.tidb WHERE VARIABLE_NAME='%s';`, gcVariableMap[name])
tblValue, err := s.getExecRet(s, sql)
if err != nil {
return val, nil // mysql.tidb value does not exist.
}
// Run validation on the tblValue. This will return an error if it can't be validated,
// but will also make it more consistent: disTribuTeD -> DISTRIBUTED etc
tblValue = trueFalseToOnOff(tblValue)
validatedVal, err := variable.ValidateSetSystemVar(s.sessionVars, name, tblValue, variable.ScopeGlobal)
if err != nil {
logutil.Logger(context.Background()).Warn("restoring sysvar value since validating mysql.tidb value failed",
zap.Error(err),
zap.String("name", name),
zap.String("tblName", gcVariableMap[name]),
zap.String("tblValue", tblValue),
zap.String("restoredValue", val))
sql := fmt.Sprintf(`REPLACE INTO mysql.tidb (variable_name, variable_value, comment)
VALUES ('%s', '%s', '%s')`, gcVariableMap[name], escapeUserString(val), gcVariableComments[name])
_, _, err = s.ExecRestrictedSQL(sql)
return val, err
}
if validatedVal != val {
// The sysvar value is out of sync.
sql := fmt.Sprintf(`REPLACE %s.%s VALUES ('%s', '%s');`,
mysql.SystemDB, mysql.GlobalVariablesTable, gcVariableMap[name], escapeUserString(validatedVal))
_, _, err = s.ExecRestrictedSQL(sql)
return validatedVal, err
}
return validatedVal, nil
}
return val, nil // not a TiKV sysVar
}

func (s *session) ensureFullGlobalStats() error {
rows, _, err := s.ExecRestrictedSQL(`select count(1) from information_schema.tables t where t.create_options = 'partitioned'
and not exists (select 1 from mysql.stats_meta m where m.table_id = t.tidb_table_id)`)
Expand Down
43 changes: 43 additions & 0 deletions session/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3866,6 +3866,49 @@ func (s *testSessionSerialSuite) TestIssue21943(c *C) {
c.Assert(err.Error(), Equals, "[variable:1238]Variable 'last_plan_from_cache' is a read only variable")
}

func (s *testSessionSerialSuite) TestTiKVSystemVars(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)

result := tk.MustQuery("SHOW GLOBAL VARIABLES LIKE 'tidb_gc_enable'") // default is on from the sysvar
result.Check(testkit.Rows("tidb_gc_enable ON"))
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_enable'")
result.Check(testkit.Rows()) // but no value in the table (yet) because the value has not been set and the GC has never been run

// update will set a value in the table
tk.MustExec("SET GLOBAL tidb_gc_enable = 1")
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_enable'")
result.Check(testkit.Rows("true"))

tk.MustExec("UPDATE mysql.tidb SET variable_value = 'false' WHERE variable_name='tikv_gc_enable'")
result = tk.MustQuery("SELECT @@tidb_gc_enable;")
result.Check(testkit.Rows("0")) // reads from mysql.tidb value and changes to false

tk.MustExec("SET GLOBAL tidb_gc_concurrency = -1") // sets auto concurrency and concurrency
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_auto_concurrency'")
result.Check(testkit.Rows("true"))
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_concurrency'")
result.Check(testkit.Rows("-1"))

tk.MustExec("SET GLOBAL tidb_gc_concurrency = 5") // sets auto concurrency and concurrency
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_auto_concurrency'")
result.Check(testkit.Rows("false"))
result = tk.MustQuery("SELECT variable_value FROM mysql.tidb WHERE variable_name = 'tikv_gc_concurrency'")
result.Check(testkit.Rows("5"))

tk.MustExec("UPDATE mysql.tidb SET variable_value = 'true' WHERE variable_name='tikv_gc_auto_concurrency'")
result = tk.MustQuery("SELECT @@tidb_gc_concurrency;")
result.Check(testkit.Rows("-1")) // because auto_concurrency is turned on it takes precedence

morgo marked this conversation as resolved.
Show resolved Hide resolved
_, err := tk.Exec("SET GLOBAL tidb_gc_run_interval = '9m'") // too small
c.Assert(err.Error(), Equals, "[variable:1232]Incorrect argument type to variable 'tidb_gc_run_interval'")

tk.MustExec("SET GLOBAL tidb_gc_run_interval = '700000000000ns'") // specified in ns, also valid

_, err = tk.Exec("SET GLOBAL tidb_gc_run_interval = '11mins'")
c.Assert(err.Error(), Equals, "[variable:1232]Incorrect argument type to variable 'tidb_gc_run_interval'") // wrong format

}

func (s *testSessionSerialSuite) TestProcessInfoIssue22068(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
Expand Down
28 changes: 28 additions & 0 deletions sessionctx/variable/sysvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ const (
TypeUnsigned TypeFlag = 5
// TypeTime for time of day (a TiDB extension)
TypeTime TypeFlag = 6
// TypeDuration for a golang duration (a TiDB extension)
TypeDuration TypeFlag = 7

// BoolOff is the canonical string representation of a boolean false.
BoolOff = "OFF"
Expand Down Expand Up @@ -136,6 +138,8 @@ func (sv *SysVar) ValidateFromType(vars *SessionVars, value string, scope ScopeF
return sv.checkEnumSystemVar(value, vars)
case TypeTime:
return sv.checkTimeSystemVar(value, vars)
case TypeDuration:
return sv.checkDurationSystemVar(value, vars)
}
return value, nil // typeString
}
Expand All @@ -160,6 +164,22 @@ func (sv *SysVar) checkTimeSystemVar(value string, vars *SessionVars) (string, e
return t.Format(FullDayTimeFormat), nil
}

func (sv *SysVar) checkDurationSystemVar(value string, vars *SessionVars) (string, error) {
d, err := time.ParseDuration(value)
if err != nil {
return value, ErrWrongTypeForVar.GenWithStackByArgs(sv.Name)
}
// Check for min/max violations
if int64(d) < sv.MinValue {
return value, ErrWrongTypeForVar.GenWithStackByArgs(sv.Name)
}
if uint64(d) > sv.MaxValue {
return value, ErrWrongTypeForVar.GenWithStackByArgs(sv.Name)
}
// return a string representation of the duration
return d.String(), nil
}

func (sv *SysVar) checkUInt64SystemVar(value string, vars *SessionVars) (string, error) {
if sv.AllowAutoValue && value == "-1" {
return value, nil
Expand Down Expand Up @@ -1194,6 +1214,14 @@ var defaultSysVars = []*SysVar{
{Scope: ScopeGlobal | ScopeSession, Name: TiDBAnalyzeVersion, Value: strconv.Itoa(DefTiDBAnalyzeVersion), Type: TypeInt, MinValue: 1, MaxValue: 2},
{Scope: ScopeGlobal | ScopeSession, Name: TiDBEnableIndexMergeJoin, Value: BoolToOnOff(DefTiDBEnableIndexMergeJoin), Type: TypeBool},
{Scope: ScopeGlobal | ScopeSession, Name: TiDBTrackAggregateMemoryUsage, Value: BoolToOnOff(DefTiDBTrackAggregateMemoryUsage), Type: TypeBool},

/* tikv gc metrics */
{Scope: ScopeGlobal, Name: TiDBGCEnable, Value: BoolOn, Type: TypeBool},
{Scope: ScopeGlobal, Name: TiDBGCRunInterval, Value: "10m0s", Type: TypeDuration, MinValue: int64(time.Minute * 10), MaxValue: math.MaxInt64},
{Scope: ScopeGlobal, Name: TiDBGCLifetime, Value: "10m0s", Type: TypeDuration, MinValue: int64(time.Minute * 10), MaxValue: math.MaxInt64},
{Scope: ScopeGlobal, Name: TiDBGCConcurrency, Value: "-1", Type: TypeInt, MinValue: 1, MaxValue: 128, AllowAutoValue: true},
{Scope: ScopeGlobal, Name: TiDBGCMode, Value: "DISTRIBUTED", Type: TypeEnum, PossibleValues: []string{"DISTRIBUTED", "CENTRAL"}},
{Scope: ScopeGlobal, Name: TiDBGCScanLockMode, Value: "PHYSICAL", Type: TypeEnum, PossibleValues: []string{"PHYSICAL", "LEGACY"}},
}

// SynonymsSysVariables is synonyms of system variables.
Expand Down
17 changes: 17 additions & 0 deletions sessionctx/variable/tidb_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,23 @@ const (
TiDBTrackAggregateMemoryUsage = "tidb_track_aggregate_memory_usage"
)

// TiDB vars that have only global scope

const (
// TiDBGCEnable description
TiDBGCEnable = "tidb_gc_enable"
// TiDBGCRunInterval description
TiDBGCRunInterval = "tidb_gc_run_interval"
// TiDBGCLifetime description
TiDBGCLifetime = "tidb_gc_life_time"
// TiDBGCConcurrency description
TiDBGCConcurrency = "tidb_gc_concurrency"
// TiDBGCMode description
TiDBGCMode = "tidb_gc_mode"
// TiDBGCScanLockMode description
TiDBGCScanLockMode = "tidb_gc_scan_lock_mode"
)

// Default TiDB system variable values.
const (
DefHostname = "localhost"
Expand Down
19 changes: 4 additions & 15 deletions util/gcutil/gcutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,25 @@ import (

const (
selectVariableValueSQL = `SELECT HIGH_PRIORITY variable_value FROM mysql.tidb WHERE variable_name='%s'`
insertVariableValueSQL = `INSERT HIGH_PRIORITY INTO mysql.tidb VALUES ('%[1]s', '%[2]s', '%[3]s')
ON DUPLICATE KEY
UPDATE variable_value = '%[2]s', comment = '%[3]s'`
)

// CheckGCEnable is use to check whether GC is enable.
func CheckGCEnable(ctx sessionctx.Context) (enable bool, err error) {
sql := fmt.Sprintf(selectVariableValueSQL, "tikv_gc_enable")
rows, _, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(sql)
val, err := ctx.GetSessionVars().GlobalVarsAccessor.GetGlobalSysVar(variable.TiDBGCEnable)
if err != nil {
return false, errors.Trace(err)
}
if len(rows) != 1 {
return false, errors.New("can not get 'tikv_gc_enable'")
}
return rows[0].GetString(0) == "true", nil
return variable.TiDBOptOn(val), nil
}

// DisableGC will disable GC enable variable.
func DisableGC(ctx sessionctx.Context) error {
sql := fmt.Sprintf(insertVariableValueSQL, "tikv_gc_enable", "false", "Current GC enable status")
_, _, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(sql)
return errors.Trace(err)
return ctx.GetSessionVars().GlobalVarsAccessor.SetGlobalSysVar(variable.TiDBGCEnable, variable.BoolOff)
}

// EnableGC will enable GC enable variable.
func EnableGC(ctx sessionctx.Context) error {
sql := fmt.Sprintf(insertVariableValueSQL, "tikv_gc_enable", "true", "Current GC enable status")
_, _, err := ctx.(sqlexec.RestrictedSQLExecutor).ExecRestrictedSQL(sql)
return errors.Trace(err)
return ctx.GetSessionVars().GlobalVarsAccessor.SetGlobalSysVar(variable.TiDBGCEnable, variable.BoolOn)
}

// ValidateSnapshot checks that the newly set snapshot time is after GC safe point time.
Expand Down