Skip to content

Commit 9ef5b59

Browse files
authored
runaway: only check statements with a non-empty plan digest (#57582)
close #56897
1 parent 8d8cfbb commit 9ef5b59

File tree

3 files changed

+55
-32
lines changed

3 files changed

+55
-32
lines changed

pkg/executor/internal/querywatch/query_watch_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,22 @@ func TestQueryWatch(t *testing.T) {
168168
time.Sleep(1 * time.Second)
169169
tk.MustGetErrCode("select * from test.t1", mysql.ErrResourceGroupQueryRunawayQuarantine)
170170
}
171+
172+
func TestQueryWatchIssue56897(t *testing.T) {
173+
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/resourcegroup/runaway/FastRunawayGC", `return(true)`))
174+
defer func() {
175+
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/pkg/resourcegroup/runaway/FastRunawayGC"))
176+
}()
177+
store, dom := testkit.CreateMockStoreAndDomain(t)
178+
tk := testkit.NewTestKit(t, store)
179+
tk.MustExec("use test")
180+
require.Eventually(t, func() bool {
181+
return dom.RunawayManager().IsSyncerInitialized()
182+
}, 20*time.Second, 300*time.Millisecond)
183+
tk.MustQuery("QUERY WATCH ADD ACTION KILL SQL TEXT SIMILAR TO 'use test';").Check((testkit.Rows("1")))
184+
time.Sleep(1 * time.Second)
185+
_, err := tk.Exec("use test")
186+
require.Nil(t, err)
187+
_, err = tk.Exec("use mysql")
188+
require.Nil(t, err)
189+
}

pkg/resourcegroup/runaway/checker.go

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ type Checker struct {
4949
// From the group runaway settings, which will be applied when a query lacks a specified watch rule.
5050
settings *rmpb.RunawaySettings
5151

52-
// markedByRule is set to true when the query matches the group runaway settings.
53-
markedByRule atomic.Bool
54-
// markedByWatch is set to true when the query matches the specified watch rules.
55-
markedByWatch bool
52+
// markedByIdentifyInRunawaySettings is set to true when the query matches the group runaway settings.
53+
markedByIdentifyInRunawaySettings atomic.Bool
54+
// markedByQueryWatchRule is set to true when the query matches the specified watch rules.
55+
markedByQueryWatchRule bool
5656
// watchAction is the specified watch action for the runaway query.
5757
// If it's not given, the action defined in `settings` will be used.
5858
watchAction rmpb.RunawayAction
@@ -65,14 +65,14 @@ func NewChecker(
6565
originalSQL, sqlDigest, planDigest string, startTime time.Time,
6666
) *Checker {
6767
c := &Checker{
68-
manager: manager,
69-
resourceGroupName: resourceGroupName,
70-
originalSQL: originalSQL,
71-
sqlDigest: sqlDigest,
72-
planDigest: planDigest,
73-
settings: settings,
74-
markedByRule: atomic.Bool{},
75-
markedByWatch: false,
68+
manager: manager,
69+
resourceGroupName: resourceGroupName,
70+
originalSQL: originalSQL,
71+
sqlDigest: sqlDigest,
72+
planDigest: planDigest,
73+
settings: settings,
74+
markedByIdentifyInRunawaySettings: atomic.Bool{},
75+
markedByQueryWatchRule: false,
7676
}
7777
if settings != nil {
7878
// avoid setting deadline if the threshold is 0
@@ -92,6 +92,10 @@ func (rm *Manager) DeriveChecker(resourceGroupName, originalSQL, sqlDigest, plan
9292
logutil.BgLogger().Warn("cannot setup up runaway checker", zap.Error(err))
9393
return nil
9494
}
95+
// Only check the normal statement.
96+
if len(planDigest) == 0 {
97+
return nil
98+
}
9599
rm.ActiveLock.RLock()
96100
defer rm.ActiveLock.RUnlock()
97101
if group.RunawaySettings == nil && rm.ActiveGroup[resourceGroupName] == 0 {
@@ -129,7 +133,7 @@ func (r *Checker) BeforeExecutor() (string, error) {
129133
switchGroupName = r.settings.SwitchGroupName
130134
}
131135
// Mark it if this is the first time being watched.
132-
r.markRunawayByWatch(action, switchGroupName, exceedCause)
136+
r.markRunawayByQueryWatchRule(action, switchGroupName, exceedCause)
133137
// Take action if needed.
134138
switch action {
135139
case rmpb.RunawayAction_Kill:
@@ -157,16 +161,16 @@ func (r *Checker) BeforeCopRequest(req *tikvrpc.Request) error {
157161
return nil
158162
}
159163
// If the group settings are not available, and it's not marked by watch, skip this part.
160-
if r.settings == nil && !r.markedByWatch {
164+
if r.settings == nil && !r.markedByQueryWatchRule {
161165
return nil
162166
}
163167
// If it's marked by watch and the action is cooldown, override the priority,
164-
if r.markedByWatch && r.watchAction == rmpb.RunawayAction_CoolDown {
168+
if r.markedByQueryWatchRule && r.watchAction == rmpb.RunawayAction_CoolDown {
165169
req.ResourceControlContext.OverridePriority = 1 // set priority to lowest
166170
}
167171
// If group settings are available and the query is not marked by a rule,
168172
// verify if it matches any rules in the settings.
169-
if r.settings != nil && !r.markedByRule.Load() {
173+
if r.settings != nil && !r.markedByIdentifyInRunawaySettings.Load() {
170174
now := time.Now()
171175
// only check time and need to ensure deadline existed.
172176
exceedCause := r.exceedsThresholds(now, nil, 0)
@@ -181,7 +185,7 @@ func (r *Checker) BeforeCopRequest(req *tikvrpc.Request) error {
181185
return nil
182186
}
183187
// execution time exceeds the threshold, mark the query as runaway
184-
r.markRunawayByIdentify(&now, exceedCause)
188+
r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause)
185189
// Take action if needed.
186190
switch r.settings.Action {
187191
case rmpb.RunawayAction_Kill:
@@ -205,10 +209,10 @@ func (r *Checker) CheckAction() rmpb.RunawayAction {
205209
if r == nil {
206210
return rmpb.RunawayAction_NoneAction
207211
}
208-
if r.markedByWatch {
212+
if r.markedByQueryWatchRule {
209213
return r.watchAction
210214
}
211-
if r.markedByRule.Load() {
215+
if r.markedByIdentifyInRunawaySettings.Load() {
212216
return r.settings.Action
213217
}
214218
return rmpb.RunawayAction_NoneAction
@@ -217,17 +221,17 @@ func (r *Checker) CheckAction() rmpb.RunawayAction {
217221
// CheckRuleKillAction checks whether the query should be killed according to the group settings.
218222
func (r *Checker) CheckRuleKillAction() (string, bool) {
219223
// If the group settings are not available, and it's not marked by watch, skip this part.
220-
if r == nil || r.settings == nil && !r.markedByWatch {
224+
if r == nil || r.settings == nil && !r.markedByQueryWatchRule {
221225
return "", false
222226
}
223227
// If the group settings are available, and it's not marked by rule, check the execution time.
224-
if r.settings != nil && !r.markedByRule.Load() {
228+
if r.settings != nil && !r.markedByIdentifyInRunawaySettings.Load() {
225229
now := time.Now()
226230
exceedCause := r.exceedsThresholds(now, nil, 0)
227231
if exceedCause == "" {
228232
return "", false
229233
}
230-
r.markRunawayByIdentify(&now, exceedCause)
234+
r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause)
231235
return exceedCause, r.settings.Action == rmpb.RunawayAction_Kill
232236
}
233237
return "", false
@@ -243,19 +247,19 @@ func (r *Checker) markQuarantine(now *time.Time, exceedCause string) {
243247
r.settings.Action, r.settings.SwitchGroupName, ttl, now, exceedCause)
244248
}
245249

246-
func (r *Checker) markRunawayByIdentify(now *time.Time, exceedCause string) bool {
247-
swapped := r.markedByRule.CompareAndSwap(false, true)
250+
func (r *Checker) markRunawayByIdentifyInRunawaySettings(now *time.Time, exceedCause string) bool {
251+
swapped := r.markedByIdentifyInRunawaySettings.CompareAndSwap(false, true)
248252
if swapped {
249253
r.markRunaway("identify", r.settings.Action, r.settings.SwitchGroupName, now, exceedCause)
250-
if !r.markedByWatch {
254+
if !r.markedByQueryWatchRule {
251255
r.markQuarantine(now, exceedCause)
252256
}
253257
}
254258
return swapped
255259
}
256260

257-
func (r *Checker) markRunawayByWatch(action rmpb.RunawayAction, switchGroupName, exceedCause string) {
258-
r.markedByWatch = true
261+
func (r *Checker) markRunawayByQueryWatchRule(action rmpb.RunawayAction, switchGroupName, exceedCause string) {
262+
r.markedByQueryWatchRule = true
259263
r.watchAction = action
260264
now := time.Now()
261265
r.markRunaway("watch", action, switchGroupName, &now, exceedCause)
@@ -326,15 +330,15 @@ func (r *Checker) CheckThresholds(ruDetail *util.RUDetails, processKeys int64, e
326330
// add the processed keys to the total processed keys.
327331
r.totalProcessedKeys += processKeys
328332
exceedCause := r.exceedsThresholds(checkTime, ruDetail, r.totalProcessedKeys)
329-
if !r.markedByRule.Load() {
330-
if exceedCause != "" && r.markRunawayByIdentify(&now, exceedCause) {
331-
if r.markRunawayByIdentify(&now, exceedCause) {
333+
if !r.markedByIdentifyInRunawaySettings.Load() {
334+
if exceedCause != "" && r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause) {
335+
if r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause) {
332336
return exeerrors.ErrResourceGroupQueryRunawayInterrupted.FastGenByArgs(exceedCause)
333337
}
334338
}
335339
}
336340
// Due to concurrency, check again.
337-
if r.markedByRule.Load() {
341+
if r.markedByIdentifyInRunawaySettings.Load() {
338342
return exeerrors.ErrResourceGroupQueryRunawayInterrupted.FastGenByArgs(exceedCause)
339343
}
340344

pkg/store/copr/copr_test/coprocessor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func TestBuildCopIteratorWithRunawayChecker(t *testing.T) {
265265

266266
sql := "select * from t"
267267
group1 := "rg1"
268-
checker := manager.DeriveChecker(group1, sql, "", "", time.Now())
268+
checker := manager.DeriveChecker(group1, sql, "test", "test", time.Now())
269269
manager.AddWatch(&runaway.QuarantineRecord{
270270
ID: 1,
271271
ResourceGroupName: group1,

0 commit comments

Comments
 (0)