Skip to content

Commit

Permalink
txn: distinguish write conflict reasons (#37735)
Browse files Browse the repository at this point in the history
close #37734
  • Loading branch information
ekexium committed Sep 14, 2022
1 parent 5a8e1b2 commit 884898b
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 55 deletions.
8 changes: 4 additions & 4 deletions DEPS.bzl
Expand Up @@ -2796,8 +2796,8 @@ def go_deps():
name = "com_github_pingcap_kvproto",
build_file_proto_mode = "disable_global",
importpath = "github.com/pingcap/kvproto",
sum = "h1:5q7Ns0R7q6Uj+fpa3lDTijrcqgId4lNdGa2AG7izB5c=",
version = "v0.0.0-20220906053631-2e37953b2b43",
sum = "h1:HfAWnlVF7P1nNJvXP4ew1Lcnng/BnAVQ40AsUHKR5EA=",
version = "v0.0.0-20220908075542-7c004f4daf21",
)
go_repository(
name = "com_github_pingcap_log",
Expand Down Expand Up @@ -3400,8 +3400,8 @@ def go_deps():
name = "com_github_tikv_client_go_v2",
build_file_proto_mode = "disable_global",
importpath = "github.com/tikv/client-go/v2",
sum = "h1:wjRWmUl4QmJF7V0aUskjT8EjjpfWxi5o9SQR5S1nNWA=",
version = "v2.0.1-0.20220906094532-f867f498456f",
sum = "h1:p8XInTnkUlLabBT7bDS3aZCeemO6tJ/7b5mHN8WbSIE=",
version = "v2.0.1-0.20220913051514-ffaaf7131a8d",
)
go_repository(
name = "com_github_tikv_pd_client",
Expand Down
2 changes: 1 addition & 1 deletion errno/errname.go
Expand Up @@ -1097,7 +1097,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrResolveLockTimeout: mysql.Message("Resolve lock timeout", nil),
ErrRegionUnavailable: mysql.Message("Region is unavailable", nil),
ErrGCTooEarly: mysql.Message("GC life time is shorter than transaction duration, transaction starts at %v, GC safe point is %v", nil),
ErrWriteConflict: mysql.Message("Write conflict, txnStartTS=%d, conflictStartTS=%d, conflictCommitTS=%d, key=%s", []int{3}),
ErrWriteConflict: mysql.Message("Write conflict, txnStartTS=%d, conflictStartTS=%d, conflictCommitTS=%d, key=%s, reason=%s", []int{3}),
ErrTiKVStoreLimit: mysql.Message("Store token is up to the limit, store id = %d", nil),
ErrPrometheusAddrIsNotSet: mysql.Message("Prometheus address is not set in PD and etcd", nil),
ErrTiKVStaleCommand: mysql.Message("TiKV server reports stale command", nil),
Expand Down
2 changes: 1 addition & 1 deletion errors.toml
Expand Up @@ -1688,7 +1688,7 @@ not implemented

["kv:9007"]
error = '''
Write conflict, txnStartTS=%d, conflictStartTS=%d, conflictCommitTS=%d, key=%s [try again later]
Write conflict, txnStartTS=%d, conflictStartTS=%d, conflictCommitTS=%d, key=%s, reason=%s [try again later]
'''

["meta:1007"]
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -63,7 +63,7 @@ require (
github.com/pingcap/errors v0.11.5-0.20211224045212-9687c2b0f87c
github.com/pingcap/failpoint v0.0.0-20220423142525-ae43b7f4e5c3
github.com/pingcap/fn v0.0.0-20200306044125-d5540d389059
github.com/pingcap/kvproto v0.0.0-20220906053631-2e37953b2b43
github.com/pingcap/kvproto v0.0.0-20220908075542-7c004f4daf21
github.com/pingcap/log v1.1.0
github.com/pingcap/sysutil v0.0.0-20220114020952-ea68d2dbf5b4
github.com/pingcap/tidb/parser v0.0.0-20211011031125-9b13dc409c5e
Expand All @@ -81,7 +81,7 @@ require (
github.com/stretchr/testify v1.8.0
github.com/tdakkota/asciicheck v0.1.1
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2
github.com/tikv/client-go/v2 v2.0.1-0.20220906094532-f867f498456f
github.com/tikv/client-go/v2 v2.0.1-0.20220913051514-ffaaf7131a8d
github.com/tikv/pd/client v0.0.0-20220725055910-7187a7ab72db
github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144
github.com/twmb/murmur3 v1.1.3
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Expand Up @@ -758,8 +758,8 @@ github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989 h1:surzm05a8C9dN
github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
github.com/pingcap/kvproto v0.0.0-20191211054548-3c6b38ea5107/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w=
github.com/pingcap/kvproto v0.0.0-20220510035547-0e2f26c0a46a/go.mod h1:OYtxs0786qojVTmkVeufx93xe+jUgm56GUYRIKnmaGI=
github.com/pingcap/kvproto v0.0.0-20220906053631-2e37953b2b43 h1:5q7Ns0R7q6Uj+fpa3lDTijrcqgId4lNdGa2AG7izB5c=
github.com/pingcap/kvproto v0.0.0-20220906053631-2e37953b2b43/go.mod h1:OYtxs0786qojVTmkVeufx93xe+jUgm56GUYRIKnmaGI=
github.com/pingcap/kvproto v0.0.0-20220908075542-7c004f4daf21 h1:HfAWnlVF7P1nNJvXP4ew1Lcnng/BnAVQ40AsUHKR5EA=
github.com/pingcap/kvproto v0.0.0-20220908075542-7c004f4daf21/go.mod h1:OYtxs0786qojVTmkVeufx93xe+jUgm56GUYRIKnmaGI=
github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=
Expand Down Expand Up @@ -912,8 +912,8 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2 h1:mbAskLJ0oJfDRtkanvQPiooDH8HvJ2FBh+iKT/OmiQQ=
github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2/go.mod h1:2PfKggNGDuadAa0LElHrByyrz4JPZ9fFx6Gs7nx7ZZU=
github.com/tikv/client-go/v2 v2.0.1-0.20220906094532-f867f498456f h1:wjRWmUl4QmJF7V0aUskjT8EjjpfWxi5o9SQR5S1nNWA=
github.com/tikv/client-go/v2 v2.0.1-0.20220906094532-f867f498456f/go.mod h1:tkKDJ88lryb16v7FfCh8pvvfwwCkh4aGeSOqHviPaaE=
github.com/tikv/client-go/v2 v2.0.1-0.20220913051514-ffaaf7131a8d h1:p8XInTnkUlLabBT7bDS3aZCeemO6tJ/7b5mHN8WbSIE=
github.com/tikv/client-go/v2 v2.0.1-0.20220913051514-ffaaf7131a8d/go.mod h1:6pedLz7wiINLHXwCT1+yMZmzuG42+ubtBkkfcwoukIo=
github.com/tikv/pd/client v0.0.0-20220725055910-7187a7ab72db h1:r1eMh9Rny3hfWuBuxOnbsCRrR4FhthiNxLQ5rAUtaww=
github.com/tikv/pd/client v0.0.0-20220725055910-7187a7ab72db/go.mod h1:ew8kS0yIcEaSetuuywkTLIUBR+sz3J5XvAYRae11qwc=
github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro=
Expand Down
6 changes: 4 additions & 2 deletions store/driver/txn/driver_test.go
Expand Up @@ -36,12 +36,13 @@ func TestWriteConflictPrettyFormat(t *testing.T) {
ConflictCommitTs: 399402937719455773,
Key: []byte{116, 128, 0, 0, 0, 0, 0, 1, 155, 95, 105, 128, 0, 0, 0, 0, 0, 0, 1, 1, 82, 87, 48, 49, 0, 0, 0, 0, 251, 1, 55, 54, 56, 50, 50, 49, 49, 48, 255, 57, 0, 0, 0, 0, 0, 0, 0, 248, 1, 0, 0, 0, 0, 0, 0, 0, 0, 247},
Primary: []byte{116, 128, 0, 0, 0, 0, 0, 1, 155, 95, 105, 128, 0, 0, 0, 0, 0, 0, 1, 1, 82, 87, 48, 49, 0, 0, 0, 0, 251, 1, 55, 54, 56, 50, 50, 49, 49, 48, 255, 57, 0, 0, 0, 0, 0, 0, 0, 248, 1, 0, 0, 0, 0, 0, 0, 0, 0, 247},
Reason: kvrpcpb.WriteConflict_Unknown,
}

expectedStr := "[kv:9007]Write conflict, " +
"txnStartTS=399402937522847774, conflictStartTS=399402937719455772, conflictCommitTS=399402937719455773, " +
"key={tableID=411, indexID=1, indexValues={RW01, 768221109, , }} " +
"primary={tableID=411, indexID=1, indexValues={RW01, 768221109, , }} " +
"primary={tableID=411, indexID=1, indexValues={RW01, 768221109, , }}, reason=Unknown " +
kv.TxnRetryableMark
require.EqualError(t, newWriteConflictError(conflict), expectedStr)

Expand All @@ -51,11 +52,12 @@ func TestWriteConflictPrettyFormat(t *testing.T) {
ConflictCommitTs: 399402937719455773,
Key: []byte{0x6d, 0x44, 0x42, 0x3a, 0x35, 0x36, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x54, 0x49, 0x44, 0x3a, 0x31, 0x30, 0x38, 0x0, 0xfe},
Primary: []byte{0x6d, 0x44, 0x42, 0x3a, 0x35, 0x36, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x54, 0x49, 0x44, 0x3a, 0x31, 0x30, 0x38, 0x0, 0xfe},
Reason: kvrpcpb.WriteConflict_Optimistic,
}
expectedStr = "[kv:9007]Write conflict, " +
"txnStartTS=399402937522847774, conflictStartTS=399402937719455772, conflictCommitTS=399402937719455773, " +
"key={metaKey=true, key=DB:56, field=TID:108} " +
"primary={metaKey=true, key=DB:56, field=TID:108} " +
"primary={metaKey=true, key=DB:56, field=TID:108}, reason=Optimistic " +
kv.TxnRetryableMark
require.EqualError(t, newWriteConflictError(conflict), expectedStr)
}
2 changes: 1 addition & 1 deletion store/driver/txn/error.go
Expand Up @@ -162,7 +162,7 @@ func newWriteConflictError(conflict *kvrpcpb.WriteConflict) error {
prettyWriteKey(&buf, conflict.Key)
buf.WriteString(" primary=")
prettyWriteKey(&buf, conflict.Primary)
return kv.ErrWriteConflict.FastGenByArgs(conflict.StartTs, conflict.ConflictTs, conflict.ConflictCommitTs, buf.String())
return kv.ErrWriteConflict.FastGenByArgs(conflict.StartTs, conflict.ConflictTs, conflict.ConflictCommitTs, buf.String(), conflict.Reason.String())
}

func prettyWriteKey(buf *bytes.Buffer, key []byte) {
Expand Down
1 change: 1 addition & 0 deletions store/mockstore/unistore/tikv/dbreader/db_reader.go
Expand Up @@ -332,6 +332,7 @@ func (r *DBReader) CheckWriteItemForRcCheckTSRead(readTS uint64, item *badger.It
StartTS: readTS,
ConflictTS: userMeta.StartTS(),
ConflictCommitTS: userMeta.CommitTS(),
Reason: kvrpcpb.WriteConflict_RcCheckTs,
}
}
return nil
Expand Down
1 change: 1 addition & 0 deletions store/mockstore/unistore/tikv/kverrors/errors.go
Expand Up @@ -106,6 +106,7 @@ type ErrConflict struct {
ConflictTS uint64
ConflictCommitTS uint64
Key []byte
Reason kvrpcpb.WriteConflict_Reason
}

func (*ErrConflict) Error() string {
Expand Down
4 changes: 4 additions & 0 deletions store/mockstore/unistore/tikv/mvcc.go
Expand Up @@ -580,6 +580,7 @@ func (store *MVCCStore) buildPessimisticLock(m *kvrpcpb.Mutation, item *badger.I
ConflictTS: userMeta.StartTS(),
ConflictCommitTS: userMeta.CommitTS(),
Key: item.KeyCopy(nil),
Reason: kvrpcpb.WriteConflict_PessimisticRetry,
}
}
}
Expand Down Expand Up @@ -668,6 +669,7 @@ func (store *MVCCStore) prewriteOptimistic(reqCtx *requestCtx, mutations []*kvrp
ConflictTS: userMeta.StartTS(),
ConflictCommitTS: userMeta.CommitTS(),
Key: item.KeyCopy(nil),
Reason: kvrpcpb.WriteConflict_Optimistic,
}
}
}
Expand Down Expand Up @@ -729,6 +731,7 @@ func (store *MVCCStore) prewritePessimistic(reqCtx *requestCtx, mutations []*kvr
ConflictTS: userMeta.StartTS(),
ConflictCommitTS: userMeta.CommitTS(),
Key: item.KeyCopy(nil),
Reason: kvrpcpb.WriteConflict_LazyUniquenessCheck,
}
}
}
Expand Down Expand Up @@ -1200,6 +1203,7 @@ func checkLockForRcCheckTS(lock mvcc.Lock, key []byte, startTS uint64, resolved
StartTS: startTS,
ConflictTS: lock.StartTS,
Key: safeCopy(key),
Reason: kvrpcpb.WriteConflict_RcCheckTs,
}
}

Expand Down
1 change: 1 addition & 0 deletions store/mockstore/unistore/tikv/server.go
Expand Up @@ -1036,6 +1036,7 @@ func convertToKeyError(err error) *kvrpcpb.KeyError {
ConflictTs: x.ConflictTS,
ConflictCommitTs: x.ConflictCommitTS,
Key: x.Key,
Reason: x.Reason,
},
}
case *kverrors.ErrDeadlock:
Expand Down
93 changes: 53 additions & 40 deletions tests/realtikvtest/pessimistictest/pessimistic_test.go
Expand Up @@ -3155,8 +3155,7 @@ func TestLazyUniquenessCheckForSimpleInserts(t *testing.T) {
tk2.MustExec("insert into t values (1, 1)")
tk2.MustExec("commit")
_, err := tk.Exec("commit")
require.NotNil(t, err)
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")
tk.MustQuery("select * from t").Check(testkit.Rows("1 1"))
tk.MustExec("admin check table t")

Expand All @@ -3168,8 +3167,7 @@ func TestLazyUniquenessCheckForSimpleInserts(t *testing.T) {
tk2.MustExec("insert into t2 values (2, 0)")
tk2.MustExec("commit")
_, err = tk.Exec("commit")
require.NotNil(t, err)
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")
tk.MustQuery("select * from t2").Check(testkit.Rows("2 0"))
tk.MustExec("admin check table t2")
}
Expand Down Expand Up @@ -3205,22 +3203,8 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("commit")
tk.MustExec("admin check table t")

// case: constraint check failure
tk.MustExec("create table t2 (id int primary key, uk int, unique key i1(uk))")
tk.MustExec("insert into t2 values (1, 1)")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t2 values (2, 1), (3, 3)")
// NOTE: this read breaks constraint, but we are not able to return an error here.
// We can only guarantee the txn should not commit
tk.MustQuery("select * from t2 use index(primary) for update").Check(testkit.Rows("1 1", "2 1", "3 3"))
err := tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "Duplicate entry '1' for key 'i1'")
tk.MustQuery("select * from t2 use index(primary)").Check(testkit.Rows("1 1"))
tk.MustExec("admin check table t2")

// case: a modification of a lazy-checked key will compensate the lock
tk.MustExec("truncate table t2")
tk.MustExec("create table t2 (id int primary key, uk int, unique key i1(uk))")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t2 values (1, 1)") // skip lock
tk.MustExec("update t2 set uk = uk + 1") // compensate the lock
Expand All @@ -3232,19 +3216,19 @@ func TestLazyUniquenessCheck(t *testing.T) {
}()
time.Sleep(500 * time.Millisecond)
tk.MustExec("commit")
err = <-ch
err := <-ch
require.NoError(t, err)
tk.MustQuery("select * from t2").Check(testkit.Rows("1 12"))
tk.MustExec("admin check table t")

// case: conflict check failure
// case: conflict check failure, it doesn't commit in the optimistic way though there is no lock acquired in the txn
tk.MustExec("create table t3 (id int primary key, sk int, key i1(sk))")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t3 values (1, 1)")
tk2.MustExec("insert into t3 values (1, 2)")
err = tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")
require.ErrorContains(t, err, "reason=LazyUniquenessCheck")

// case: DML returns error => abort txn
tk.MustExec("create table t4 (id int primary key, v int, key i1(v))")
Expand All @@ -3253,8 +3237,7 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("insert into t4 values (1, 2), (2, 2)")
tk.MustQuery("select * from t4 order by id").Check(testkit.Rows("1 2", "2 2"))
err = tk.ExecToErr("delete from t4 where id = 1")
require.Error(t, err)
require.Contains(t, err.Error(), "transaction aborted because lazy uniqueness check is enabled and an error occurred: [kv:1062]Duplicate entry '1' for key 'PRIMARY'")
require.ErrorContains(t, err, "transaction aborted because lazy uniqueness check is enabled and an error occurred: [kv:1062]Duplicate entry '1' for key 'PRIMARY'")
tk.MustExec("commit")
tk.MustExec("admin check table t4")
tk.MustQuery("select * from t4 order by id").Check(testkit.Rows("1 1"))
Expand All @@ -3267,16 +3250,15 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk2.MustExec("delete from t5 where uk = 2")
tk.MustExec("select * from t5 for update")
err = tk.ExecToErr("commit")
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")

// case: delete your own insert that should've returned error
tk.MustExec("truncate table t5")
tk.MustExec("insert into t5 values (1, 1)")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t5 values (2, 1)")
err = tk.ExecToErr("delete from t5")
require.Error(t, err)
require.Contains(t, err.Error(), "transaction aborted because lazy uniqueness check is enabled and an error occurred: [kv:1062]Duplicate entry '1' for key 'i1'")
require.ErrorContains(t, err, "transaction aborted because lazy uniqueness check is enabled and an error occurred: [kv:1062]Duplicate entry '1' for key 'i1'")
require.False(t, tk.Session().GetSessionVars().InTxn())

// case: update unique key, but conflict exists before the txn
Expand All @@ -3285,8 +3267,7 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("begin pessimistic")
tk.MustExec("update t5 set uk = 3 where id = 1")
err = tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "Duplicate entry '3' for key 'i1'")
require.ErrorContains(t, err, "Duplicate entry '3' for key 'i1'")
tk.MustExec("admin check table t5")

// case: update unique key, but conflict with concurrent write
Expand All @@ -3296,8 +3277,7 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("update t5 set uk = 3 where id = 1")
tk2.MustExec("insert into t5 values (2, 3)")
err = tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")
tk.MustExec("admin check table t5")

// case: insert on duplicate update unique key, but conflict exists before the txn
Expand All @@ -3306,8 +3286,7 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t5 values (3, 1) on duplicate key update uk = 3")
err = tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "Duplicate entry '3' for key 'i1'")
require.ErrorContains(t, err, "Duplicate entry '3' for key 'i1'")
tk.MustExec("admin check table t5")

// case: insert on duplicate update unique key, but conflict with concurrent write
Expand All @@ -3317,12 +3296,12 @@ func TestLazyUniquenessCheck(t *testing.T) {
tk.MustExec("insert into t5 values (3, 1) on duplicate key update uk = 3")
tk2.MustExec("insert into t5 values (2, 3)")
err = tk.ExecToErr("commit")
require.Error(t, err)
require.Contains(t, err.Error(), "[kv:9007]Write conflict")
require.ErrorContains(t, err, "[kv:9007]Write conflict")
tk.MustExec("admin check table t5")
}

func TestLazyUniquenessCheckForInsertIgnore(t *testing.T) {
// lazy uniqueness check doesn't affect INSERT IGNORE
store := realtikvtest.CreateMockStoreAndSetup(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
Expand Down Expand Up @@ -3364,8 +3343,8 @@ func TestLazyUniquenessCheckWithStatementRetry(t *testing.T) {
tk.MustExec("insert into t5 values (3, 3)") // skip handle=3, uk=3
tk2.MustExec("insert into t5 values (2, 3)")
err := tk.ExecToErr("update t5 set id = 10 where uk = 3") // write conflict -> unset PresumeKNE -> retry
require.Error(t, err)
require.Contains(t, err.Error(), "Duplicate entry '3' for key 'i1'")
require.ErrorContains(t, err, "transaction aborted because lazy uniqueness")
require.ErrorContains(t, err, "Duplicate entry '3' for key 'i1'")
require.False(t, tk.Session().GetSessionVars().InTxn())
tk.MustExec("admin check table t5")

Expand All @@ -3376,8 +3355,42 @@ func TestLazyUniquenessCheckWithStatementRetry(t *testing.T) {
tk.MustExec("insert into t5 values (3, 3)") // skip handle=3, uk=3
tk2.MustExec("insert into t5 values (2, 3)")
err = tk.ExecToErr("update t5 set id = id + 10") // write conflict -> unset PresumeKNE -> retry
require.Error(t, err)
require.Contains(t, err.Error(), "Duplicate entry '3' for key 'i1'")
require.ErrorContains(t, err, "Duplicate entry '3' for key 'i1'")
require.False(t, tk.Session().GetSessionVars().InTxn())
tk.MustExec("admin check table t5")
}

func TestLazyUniquenessCheckWithInconsistentReadResult(t *testing.T) {
// If any read breaks constraint, we guarantee the txn cannot commit
store := realtikvtest.CreateMockStoreAndSetup(t)
tk := testkit.NewTestKit(t, store)
tk2 := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk2.MustExec("use test")
tk.MustExec("set @@tidb_constraint_check_in_place_pessimistic=0")
// TiKV will perform a constraint check before reporting assertion failure.
// And constraint violation precedes assertion failure.
if !*realtikvtest.WithRealTiKV {
tk.MustExec("set @@tidb_txn_assertion_level=off")
}

// case: conflict data has been there before current txn
tk.MustExec("create table t2 (id int primary key, uk int, unique key i1(uk))")
tk.MustExec("insert into t2 values (1, 1)")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t2 values (2, 1), (3, 3)")
tk.MustQuery("select * from t2 use index(primary) for update").Check(testkit.Rows("1 1", "2 1", "3 3"))
err := tk.ExecToErr("commit")
require.ErrorContains(t, err, "Duplicate entry '1' for key 'i1'")
tk.MustQuery("select * from t2 use index(primary)").Check(testkit.Rows("1 1"))
tk.MustExec("admin check table t2")

// case: conflict data is written concurrently
tk.MustExec("truncate table t2")
tk.MustExec("begin pessimistic")
tk.MustExec("insert into t2 values (1, 1)")
tk2.MustExec("insert into t2 values (2, 1)")
tk.MustQuery("select * from t2 use index(primary) for update").Check(testkit.Rows("1 1", "2 1"))
err = tk.ExecToErr("commit")
require.ErrorContains(t, err, "reason=LazyUniquenessCheck")
}

0 comments on commit 884898b

Please sign in to comment.