forked from pingcap/tidb
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfailpoint.go
181 lines (154 loc) · 5.69 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// 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"
// TsoWaitCount doesn't include begin and commit
var TsoWaitCount stringutil.StringerStr = "tsoWaitCount"
// TsoUseConstantCount is the key for constant tso counter
var TsoUseConstantCount stringutil.StringerStr = "tsoUseConstantCount"
// CallOnStmtRetryCount is the key for recording calling OnStmtRetry at RC isolation level
var CallOnStmtRetryCount stringutil.StringerStr = "callOnStmtRetryCount"
// 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.SessionExtendedInfoSchema)
if !ok {
panic("Expected to be a SessionExtendedInfoSchema")
}
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)
}
// TsoWaitCountInc is used only for test
// When it is called, there is a waiting tso operation
func TsoWaitCountInc(sctx sessionctx.Context) {
count, ok := sctx.Value(TsoWaitCount).(uint64)
if !ok {
count = 0
}
count++
sctx.SetValue(TsoWaitCount, count)
}
// TsoUseConstantCountInc is used to test constant tso count
func TsoUseConstantCountInc(sctx sessionctx.Context) {
count, ok := sctx.Value(TsoUseConstantCount).(uint64)
if !ok {
count = 0
}
count++
sctx.SetValue(TsoUseConstantCount, count)
}
// OnStmtRetryCountInc is used only for test.
// When it is called, there is calling `(p *PessimisticRCTxnContextProvider) OnStmtRetry`.
func OnStmtRetryCountInc(sctx sessionctx.Context) {
count, ok := sctx.Value(CallOnStmtRetryCount).(int)
if !ok {
count = 0
}
count++
sctx.SetValue(CallOnStmtRetryCount, 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")
}
}
}