-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
Copy pathfailpoint.go
140 lines (119 loc) · 4.5 KB
/
failpoint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2021 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sessiontxn
import (
"fmt"
"time"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/util/stringutil"
)
// AssertRecordsKey is used to save failPoint invoke records
// Only for test
var AssertRecordsKey stringutil.StringerStr = "assertTxnManagerRecords"
// AssertTxnInfoSchemaKey is used to set the expected infoschema that should be check in failPoint
// Only for test
var AssertTxnInfoSchemaKey stringutil.StringerStr = "assertTxnInfoSchemaKey"
// AssertTxnInfoSchemaAfterRetryKey is used to set the expected infoschema that should be check in failPoint after retry
// Only for test
var AssertTxnInfoSchemaAfterRetryKey stringutil.StringerStr = "assertTxnInfoSchemaAfterRetryKey"
// BreakPointBeforeExecutorFirstRun is the key for the stop point where session stops before executor's first run
// Only for test
var BreakPointBeforeExecutorFirstRun = "beforeExecutorFirstRun"
// BreakPointOnStmtRetryAfterLockError s the key for the stop point where session stops after OnStmtRetry when lock error happens
// Only for test
var BreakPointOnStmtRetryAfterLockError = "lockErrorAndThenOnStmtRetryCalled"
// TsoRequestCount is the key for recording tso request counts in some places
var TsoRequestCount stringutil.StringerStr = "tsoRequestCount"
// AssertLockErr is used to record the lock errors we encountered
// Only for test
var AssertLockErr stringutil.StringerStr = "assertLockError"
// RecordAssert is used only for test
func RecordAssert(sctx sessionctx.Context, name string, value interface{}) {
records, ok := sctx.Value(AssertRecordsKey).(map[string]interface{})
if !ok {
records = make(map[string]interface{})
sctx.SetValue(AssertRecordsKey, records)
}
records[name] = value
}
// AssertTxnManagerInfoSchema is used only for test
func AssertTxnManagerInfoSchema(sctx sessionctx.Context, is interface{}) {
assertVersion := func(expected interface{}) {
if expected == nil {
return
}
expectVer := expected.(infoschema.InfoSchema).SchemaMetaVersion()
gotVer := GetTxnManager(sctx).GetTxnInfoSchema().SchemaMetaVersion()
if gotVer != expectVer {
panic(fmt.Sprintf("Txn schema version not match, expect:%d, got:%d", expectVer, gotVer))
}
}
if localTables := sctx.GetSessionVars().LocalTemporaryTables; localTables != nil {
got, ok := GetTxnManager(sctx).GetTxnInfoSchema().(*infoschema.TemporaryTableAttachedInfoSchema)
if !ok {
panic("Expected to be a TemporaryTableAttachedInfoSchema")
}
if got.LocalTemporaryTables != localTables {
panic("Local tables should be the same with the one in session")
}
}
assertVersion(is)
assertVersion(sctx.Value(AssertTxnInfoSchemaKey))
}
// AssertTxnManagerReadTS is used only for test
func AssertTxnManagerReadTS(sctx sessionctx.Context, expected uint64) {
actual, err := GetTxnManager(sctx).GetStmtReadTS()
if err != nil {
panic(err)
}
if actual != expected {
panic(fmt.Sprintf("Txn read ts not match, expect:%d, got:%d", expected, actual))
}
}
// AddAssertEntranceForLockError is used only for test
func AddAssertEntranceForLockError(sctx sessionctx.Context, name string) {
records, ok := sctx.Value(AssertLockErr).(map[string]int)
if !ok {
records = make(map[string]int)
sctx.SetValue(AssertLockErr, records)
}
if v, ok := records[name]; ok {
records[name] = v + 1
} else {
records[name] = 1
}
}
// TsoRequestCountInc is used only for test
// When it is called, there is a tso cmd request.
func TsoRequestCountInc(sctx sessionctx.Context) {
count, ok := sctx.Value(TsoRequestCount).(uint64)
if !ok {
count = 0
}
count++
sctx.SetValue(TsoRequestCount, count)
}
// ExecTestHook is used only for test. It consumes hookKey in session wait do what it gets from it.
func ExecTestHook(sctx sessionctx.Context, hookKey fmt.Stringer) {
c := sctx.Value(hookKey)
if ch, ok := c.(chan func()); ok {
select {
case fn := <-ch:
fn()
case <-time.After(time.Second * 10):
panic("timeout waiting for chan")
}
}
}