Skip to content

Commit 397b0f2

Browse files
authored
*: add sql variable @@tidb_accelerate_user_creation_update (#58512)
ref #55563
1 parent e7d7cdc commit 397b0f2

File tree

7 files changed

+77
-9
lines changed

7 files changed

+77
-9
lines changed

pkg/domain/domain.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,6 +1945,8 @@ func (do *Domain) LoadPrivilegeLoop(sctx sessionctx.Context) error {
19451945

19461946
func privReloadEvent(h *privileges.Handle, event *PrivilegeEvent) (err error) {
19471947
switch {
1948+
case !vardef.AccelerateUserCreationUpdate.Load():
1949+
err = h.UpdateAll()
19481950
case event.All:
19491951
err = h.UpdateAllActive()
19501952
default:
@@ -2940,10 +2942,7 @@ func (do *Domain) notifyUpdatePrivilege(event PrivilegeEvent) error {
29402942
return nil
29412943
}
29422944

2943-
if event.All {
2944-
return do.PrivilegeHandle().UpdateAll()
2945-
}
2946-
return do.PrivilegeHandle().Update(event.UserList)
2945+
return privReloadEvent(do.PrivilegeHandle(), &event)
29472946
}
29482947

29492948
// NotifyUpdateSysVarCache updates the sysvar cache key in etcd, which other TiDB

pkg/privilege/privileges/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ go_test(
6060
shard_count = 50,
6161
deps = [
6262
"//pkg/config",
63+
"//pkg/domain",
6364
"//pkg/errno",
6465
"//pkg/kv",
6566
"//pkg/parser/auth",

pkg/privilege/privileges/cache.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,10 @@ func (p *MySQLPrivilege) LoadDBTable(ctx sqlexec.RestrictedSQLExecutor) error {
835835
if err != nil {
836836
return err
837837
}
838+
p.db.Ascend(func(itm itemDB) bool {
839+
slices.SortFunc(itm.data, compareDBRecord)
840+
return true
841+
})
838842
return nil
839843
}
840844

@@ -2013,8 +2017,8 @@ type Handle struct {
20132017
// Only load the active user's data to save memory
20142018
// username => struct{}
20152019
activeUsers sync.Map
2016-
2017-
globalVars variable.GlobalVarAccessor
2020+
fullData atomic.Bool
2021+
globalVars variable.GlobalVarAccessor
20182022
}
20192023

20202024
// NewHandle returns a Handle.
@@ -2033,6 +2037,10 @@ func (h *Handle) ensureActiveUser(ctx context.Context, user string) error {
20332037
visited := p.(*bool)
20342038
*visited = true
20352039
}
2040+
if h.fullData.Load() {
2041+
// All users data are in-memory, nothing to do
2042+
return nil
2043+
}
20362044

20372045
_, exist := h.activeUsers.Load(user)
20382046
if exist {
@@ -2067,7 +2075,7 @@ func (h *Handle) Get() *MySQLPrivilege {
20672075
return h.priv.Load()
20682076
}
20692077

2070-
// UpdateAll loads all the active users' privilege info from kv storage.
2078+
// UpdateAll loads all the users' privilege info from kv storage.
20712079
func (h *Handle) UpdateAll() error {
20722080
logutil.BgLogger().Warn("update all called")
20732081
priv := newMySQLPrivilege()
@@ -2076,11 +2084,13 @@ func (h *Handle) UpdateAll() error {
20762084
return errors.Trace(err)
20772085
}
20782086
h.priv.Store(priv)
2087+
h.fullData.Store(true)
20792088
return nil
20802089
}
20812090

20822091
// UpdateAllActive loads all the active users' privilege info from kv storage.
20832092
func (h *Handle) UpdateAllActive() error {
2093+
h.fullData.Store(false)
20842094
userList := make([]string, 0, 20)
20852095
h.activeUsers.Range(func(key, _ any) bool {
20862096
userList = append(userList, key.(string))
@@ -2103,6 +2113,7 @@ func (h *Handle) UpdateAllActive() error {
21032113

21042114
// Update loads the privilege info from kv storage for the list of users.
21052115
func (h *Handle) Update(userList []string) error {
2116+
h.fullData.Store(false)
21062117
if len(userList) > 100 {
21072118
logutil.BgLogger().Warn("update user list is long", zap.Int("len", len(userList)))
21082119
}

pkg/privilege/privileges/privileges_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"time"
3131

3232
"github.com/pingcap/tidb/pkg/config"
33+
"github.com/pingcap/tidb/pkg/domain"
3334
"github.com/pingcap/tidb/pkg/errno"
3435
"github.com/pingcap/tidb/pkg/kv"
3536
"github.com/pingcap/tidb/pkg/parser/auth"
@@ -2134,6 +2135,7 @@ func TestEnsureActiveUserCoverage(t *testing.T) {
21342135
{"set password for test = 'test2'", false},
21352136
{"show create user test", false},
21362137
{"create user test1", false},
2138+
{"grant select on test.* to test1", false},
21372139
{"show grants", true},
21382140
{"show grants for 'test'@'%'", true},
21392141
}
@@ -2151,3 +2153,43 @@ func TestEnsureActiveUserCoverage(t *testing.T) {
21512153
require.Equal(t, c.visited, visited, comment)
21522154
}
21532155
}
2156+
2157+
func TestSQLVariableAccelerateUserCreationUpdate(t *testing.T) {
2158+
store := createStoreAndPrepareDB(t)
2159+
tk := testkit.NewTestKit(t, store)
2160+
dom := domain.GetDomain(tk.Session())
2161+
// 1. check the default variable value
2162+
tk.MustQuery("select @@global.tidb_accelerate_user_creation_update").Check(testkit.Rows("0"))
2163+
// trigger priv reload
2164+
tk.MustExec("create user aaa")
2165+
handle := dom.PrivilegeHandle()
2166+
handle.CheckFullData(t, true)
2167+
priv := handle.Get()
2168+
require.False(t, priv.RequestVerification(nil, "bbb", "%", "test", "", "", mysql.SelectPriv))
2169+
2170+
// 2. change the variable and check
2171+
tk.MustExec("set @@global.tidb_accelerate_user_creation_update = on")
2172+
tk.MustQuery("select @@global.tidb_accelerate_user_creation_update").Check(testkit.Rows("1"))
2173+
require.True(t, vardef.AccelerateUserCreationUpdate.Load())
2174+
tk.MustExec("create user bbb")
2175+
handle.CheckFullData(t, false)
2176+
// trigger priv reload, but data for bbb is not really loaded
2177+
tk.MustExec("grant select on test.* to bbb")
2178+
priv = handle.Get()
2179+
// data for bbb is not loaded, because that user is not active
2180+
// So this is **counterintuitive**, but it's still the expected behavior.
2181+
require.False(t, priv.RequestVerification(nil, "bbb", "%", "test", "", "", mysql.SelectPriv))
2182+
tk1 := testkit.NewTestKit(t, store)
2183+
// if user bbb login, everything works as expected
2184+
require.NoError(t, tk1.Session().Auth(&auth.UserIdentity{Username: "bbb", Hostname: "localhost"}, nil, nil, nil))
2185+
priv = handle.Get()
2186+
require.True(t, priv.RequestVerification(nil, "bbb", "%", "test", "", "", mysql.SelectPriv))
2187+
2188+
// 3. change the variable and check again
2189+
tk.MustExec("set @@global.tidb_accelerate_user_creation_update = off")
2190+
tk.MustQuery("select @@global.tidb_accelerate_user_creation_update").Check(testkit.Rows("0"))
2191+
tk.MustExec("drop user aaa")
2192+
handle.CheckFullData(t, true)
2193+
priv = handle.Get()
2194+
require.True(t, priv.RequestVerification(nil, "bbb", "%", "test", "", "", mysql.SelectPriv))
2195+
}

pkg/privilege/privileges/tidb_auth_token_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,4 +486,8 @@ func (p *MySQLPrivilege) RoleGraph() map[string]roleGraphEdgesTable {
486486
return p.roleGraph
487487
}
488488

489+
func (h *Handle) CheckFullData(t *testing.T, value bool) {
490+
require.True(t, h.fullData.Load() == value)
491+
}
492+
489493
var NewMySQLPrivilege = newMySQLPrivilege

pkg/sessionctx/vardef/tidb_vars.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,9 @@ const (
983983
// TiDBEnableSharedLockPromotion indicates whether the `select for share` statement would be executed
984984
// as `select for update` statements which do acquire pessimistic locks.
985985
TiDBEnableSharedLockPromotion = "tidb_enable_shared_lock_promotion"
986+
987+
// TiDBAccelerateUserCreationUpdate decides whether tidb will load & update the whole user's data in-memory.
988+
TiDBAccelerateUserCreationUpdate = "tidb_accelerate_user_creation_update"
986989
)
987990

988991
// TiDB vars that have only global scope
@@ -1568,6 +1571,7 @@ const (
15681571
DefTiDBEnableSharedLockPromotion = false
15691572
DefTiDBTSOClientRPCMode = TSOClientRPCModeDefault
15701573
DefTiDBCircuitBreakerPDMetaErrorRatePct = 0
1574+
DefTiDBAccelerateUserCreationUpdate = false
15711575
)
15721576

15731577
// Process global variables.
@@ -1690,8 +1694,9 @@ var (
16901694
IgnoreInlistPlanDigest = atomic.NewBool(DefTiDBIgnoreInlistPlanDigest)
16911695
TxnEntrySizeLimit = atomic.NewUint64(DefTiDBTxnEntrySizeLimit)
16921696

1693-
SchemaCacheSize = atomic.NewUint64(DefTiDBSchemaCacheSize)
1694-
SchemaCacheSizeOriginText = atomic.NewString(strconv.Itoa(DefTiDBSchemaCacheSize))
1697+
SchemaCacheSize = atomic.NewUint64(DefTiDBSchemaCacheSize)
1698+
SchemaCacheSizeOriginText = atomic.NewString(strconv.Itoa(DefTiDBSchemaCacheSize))
1699+
AccelerateUserCreationUpdate = atomic.NewBool(DefTiDBAccelerateUserCreationUpdate)
16951700
)
16961701

16971702
func serverMemoryLimitDefaultValue() string {

pkg/sessionctx/variable/sysvar.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3435,6 +3435,12 @@ var defaultSysVars = []*SysVar{
34353435
return nil
34363436
},
34373437
},
3438+
{Scope: vardef.ScopeGlobal, Name: vardef.TiDBAccelerateUserCreationUpdate, Value: BoolToOnOff(vardef.DefTiDBAccelerateUserCreationUpdate), Type: vardef.TypeBool,
3439+
SetGlobal: func(_ context.Context, s *SessionVars, val string) error {
3440+
vardef.AccelerateUserCreationUpdate.Store(TiDBOptOn(val))
3441+
return nil
3442+
},
3443+
},
34383444
}
34393445

34403446
// GlobalSystemVariableInitialValue gets the default value for a system variable including ones that are dynamically set (e.g. based on the store)

0 commit comments

Comments
 (0)