Skip to content

Commit 2fc9a78

Browse files
committed
runaway: only check statements with a non-empty plan digest
Signed-off-by: nolouch <[email protected]>
1 parent 14e99ea commit 2fc9a78

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
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 PLAN 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: 36 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,11 @@ 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 query.
96+
if len(planDigest) == 0 {
97+
logutil.BgLogger().Warn("cannot setup up runaway checker, there is no plan digest", zap.Error(err))
98+
return nil
99+
}
95100
rm.ActiveLock.RLock()
96101
defer rm.ActiveLock.RUnlock()
97102
if group.RunawaySettings == nil && rm.ActiveGroup[resourceGroupName] == 0 {
@@ -129,7 +134,7 @@ func (r *Checker) BeforeExecutor() (string, error) {
129134
switchGroupName = r.settings.SwitchGroupName
130135
}
131136
// Mark it if this is the first time being watched.
132-
r.markRunawayByWatch(action, switchGroupName, exceedCause)
137+
r.markRunawayByQueryWatchRule(action, switchGroupName, exceedCause)
133138
// Take action if needed.
134139
switch action {
135140
case rmpb.RunawayAction_Kill:
@@ -157,16 +162,16 @@ func (r *Checker) BeforeCopRequest(req *tikvrpc.Request) error {
157162
return nil
158163
}
159164
// If the group settings are not available, and it's not marked by watch, skip this part.
160-
if r.settings == nil && !r.markedByWatch {
165+
if r.settings == nil && !r.markedByQueryWatchRule {
161166
return nil
162167
}
163168
// If it's marked by watch and the action is cooldown, override the priority,
164-
if r.markedByWatch && r.watchAction == rmpb.RunawayAction_CoolDown {
169+
if r.markedByQueryWatchRule && r.watchAction == rmpb.RunawayAction_CoolDown {
165170
req.ResourceControlContext.OverridePriority = 1 // set priority to lowest
166171
}
167172
// If group settings are available and the query is not marked by a rule,
168173
// verify if it matches any rules in the settings.
169-
if r.settings != nil && !r.markedByRule.Load() {
174+
if r.settings != nil && !r.markedByIdentifyInRunawaySettings.Load() {
170175
now := time.Now()
171176
// only check time and need to ensure deadline existed.
172177
exceedCause := r.exceedsThresholds(now, nil, 0)
@@ -181,7 +186,7 @@ func (r *Checker) BeforeCopRequest(req *tikvrpc.Request) error {
181186
return nil
182187
}
183188
// execution time exceeds the threshold, mark the query as runaway
184-
r.markRunawayByIdentify(&now, exceedCause)
189+
r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause)
185190
// Take action if needed.
186191
switch r.settings.Action {
187192
case rmpb.RunawayAction_Kill:
@@ -205,10 +210,10 @@ func (r *Checker) CheckAction() rmpb.RunawayAction {
205210
if r == nil {
206211
return rmpb.RunawayAction_NoneAction
207212
}
208-
if r.markedByWatch {
213+
if r.markedByQueryWatchRule {
209214
return r.watchAction
210215
}
211-
if r.markedByRule.Load() {
216+
if r.markedByIdentifyInRunawaySettings.Load() {
212217
return r.settings.Action
213218
}
214219
return rmpb.RunawayAction_NoneAction
@@ -217,17 +222,17 @@ func (r *Checker) CheckAction() rmpb.RunawayAction {
217222
// CheckRuleKillAction checks whether the query should be killed according to the group settings.
218223
func (r *Checker) CheckRuleKillAction() (string, bool) {
219224
// 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 {
225+
if r == nil || r.settings == nil && !r.markedByQueryWatchRule {
221226
return "", false
222227
}
223228
// 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() {
229+
if r.settings != nil && !r.markedByIdentifyInRunawaySettings.Load() {
225230
now := time.Now()
226231
exceedCause := r.exceedsThresholds(now, nil, 0)
227232
if exceedCause == "" {
228233
return "", false
229234
}
230-
r.markRunawayByIdentify(&now, exceedCause)
235+
r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause)
231236
return exceedCause, r.settings.Action == rmpb.RunawayAction_Kill
232237
}
233238
return "", false
@@ -243,19 +248,19 @@ func (r *Checker) markQuarantine(now *time.Time, exceedCause string) {
243248
r.settings.Action, r.settings.SwitchGroupName, ttl, now, exceedCause)
244249
}
245250

246-
func (r *Checker) markRunawayByIdentify(now *time.Time, exceedCause string) bool {
247-
swapped := r.markedByRule.CompareAndSwap(false, true)
251+
func (r *Checker) markRunawayByIdentifyInRunawaySettings(now *time.Time, exceedCause string) bool {
252+
swapped := r.markedByIdentifyInRunawaySettings.CompareAndSwap(false, true)
248253
if swapped {
249254
r.markRunaway("identify", r.settings.Action, r.settings.SwitchGroupName, now, exceedCause)
250-
if !r.markedByWatch {
255+
if !r.markedByQueryWatchRule {
251256
r.markQuarantine(now, exceedCause)
252257
}
253258
}
254259
return swapped
255260
}
256261

257-
func (r *Checker) markRunawayByWatch(action rmpb.RunawayAction, switchGroupName, exceedCause string) {
258-
r.markedByWatch = true
262+
func (r *Checker) markRunawayByQueryWatchRule(action rmpb.RunawayAction, switchGroupName, exceedCause string) {
263+
r.markedByQueryWatchRule = true
259264
r.watchAction = action
260265
now := time.Now()
261266
r.markRunaway("watch", action, switchGroupName, &now, exceedCause)
@@ -326,15 +331,15 @@ func (r *Checker) CheckThresholds(ruDetail *util.RUDetails, processKeys int64, e
326331
// add the processed keys to the total processed keys.
327332
r.totalProcessedKeys += processKeys
328333
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) {
334+
if !r.markedByIdentifyInRunawaySettings.Load() {
335+
if exceedCause != "" && r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause) {
336+
if r.markRunawayByIdentifyInRunawaySettings(&now, exceedCause) {
332337
return exeerrors.ErrResourceGroupQueryRunawayInterrupted.FastGenByArgs(exceedCause)
333338
}
334339
}
335340
}
336341
// Due to concurrency, check again.
337-
if r.markedByRule.Load() {
342+
if r.markedByIdentifyInRunawaySettings.Load() {
338343
return exeerrors.ErrResourceGroupQueryRunawayInterrupted.FastGenByArgs(exceedCause)
339344
}
340345

0 commit comments

Comments
 (0)