diff --git a/DEPS.bzl b/DEPS.bzl index 03659942af736..386080fb06dbf 100644 --- a/DEPS.bzl +++ b/DEPS.bzl @@ -3777,8 +3777,9 @@ def go_deps(): name = "com_github_pingcap_kvproto", build_file_proto_mode = "disable_global", importpath = "github.com/pingcap/kvproto", - sum = "h1:qW0gHsqY3X3qmyiEfESqpYSF3Vu7agUiAyBnPWQXtm8=", - version = "v0.0.0-20260721064811-683dad8fa368", + replace = "github.com/wfxr/kvproto", + sum = "h1:wQuil8SCJhSp+LJqqiMgPjzBZgzobJCIQFp52UIYq6Y=", + version = "v0.0.0-20260806092442-d04fa0402753", ) go_repository( name = "com_github_pingcap_log", @@ -4492,8 +4493,9 @@ def go_deps(): build_tags = ["nextgen", "intest"], build_file_proto_mode = "disable_global", importpath = "github.com/tikv/client-go/v2", - sum = "h1:20uV3D/EvkPVkDvSGWcOg2+jZOKaCYpIoIkwSb7amJM=", - version = "v2.0.8-0.20260803074519-341d4692ec57", + replace = "github.com/wfxr/client-go/v2", + sum = "h1:mqjqOtWPO+TVbH8lxEghT2DBcoZqR5vsQQLVwUKJgYo=", + version = "v2.0.8-0.20260812071238-dcfbdfcfb5af", ) go_repository( name = "com_github_tikv_pd_client", diff --git a/go.mod b/go.mod index 9adf4518a9e6a..df6ae848d1944 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ require ( github.com/pingcap/errors v0.11.5-0.20260508054701-306e305bcf41 github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 github.com/pingcap/fn v1.0.0 - github.com/pingcap/kvproto v0.0.0-20260721064811-683dad8fa368 + github.com/pingcap/kvproto v0.0.0-20260806092442-d04fa0402753 github.com/pingcap/log v1.1.1-0.20250917021125-19901e015dc9 github.com/pingcap/metering_sdk v0.0.0-20260324055927-14fead745f1d github.com/pingcap/sysutil v1.0.1-0.20240311050922-ae81ee01f3a5 @@ -121,7 +121,7 @@ require ( github.com/stathat/consistent v1.0.0 github.com/stretchr/testify v1.11.1 github.com/tiancaiamao/appdash v0.0.0-20181126055449-889f96f722a2 - github.com/tikv/client-go/v2 v2.0.8-0.20260803074519-341d4692ec57 + github.com/tikv/client-go/v2 v2.0.8-0.20260812071238-dcfbdfcfb5af github.com/tikv/pd/client v0.0.0-20260720043438-0b37df9a48ed github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 github.com/twmb/murmur3 v1.1.6 @@ -363,7 +363,9 @@ require ( replace ( cloud.google.com/go/storage => cloud.google.com/go/storage v1.39.1 github.com/go-ldap/ldap/v3 => github.com/YangKeao/ldap/v3 v3.4.5-0.20230421065457-369a3bab1117 + github.com/pingcap/kvproto => github.com/wfxr/kvproto v0.0.0-20260806092442-d04fa0402753 github.com/pingcap/tidb/pkg/parser => ./pkg/parser + github.com/tikv/client-go/v2 => github.com/wfxr/client-go/v2 v2.0.8-0.20260812071238-dcfbdfcfb5af // TODO: `sourcegraph.com/sourcegraph/appdash` has been archived, and the original host has been removed. // Please remove these dependencies. sourcegraph.com/sourcegraph/appdash => github.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 diff --git a/go.sum b/go.sum index 2f5bf4d6911b8..2e62c7c88acba 100644 --- a/go.sum +++ b/go.sum @@ -1731,7 +1731,6 @@ github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v0.0.0-20180717141946-636bf0302bc9/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -1761,7 +1760,6 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -2172,9 +2170,6 @@ github.com/pingcap/fn v1.0.0 h1:CyA6AxcOZkQh52wIqYlAmaVmF6EvrcqFywP463pjA8g= github.com/pingcap/fn v1.0.0/go.mod h1:u9WZ1ZiOD1RpNhcI42RucFh/lBuzTu6rw88a+oF2Z24= github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989 h1:surzm05a8C9dN8dIUmo4Be2+pMRb6f55i+UIYrluu2E= 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-20260721064811-683dad8fa368 h1:qW0gHsqY3X3qmyiEfESqpYSF3Vu7agUiAyBnPWQXtm8= -github.com/pingcap/kvproto v0.0.0-20260721064811-683dad8fa368/go.mod h1:z6+aAHB7dBkA+LyinEX+48/ImRJ3jag0Hg0c7wkhEvE= github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM= github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= github.com/pingcap/log v1.1.1-0.20250917021125-19901e015dc9 h1:qG9BSvlWFEE5otQGamuWedx9LRm0nrHvsQRQiW8SxEs= @@ -2357,8 +2352,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/tikv/client-go/v2 v2.0.8-0.20260803074519-341d4692ec57 h1:20uV3D/EvkPVkDvSGWcOg2+jZOKaCYpIoIkwSb7amJM= -github.com/tikv/client-go/v2 v2.0.8-0.20260803074519-341d4692ec57/go.mod h1:kNePJmoqcbd+eTTzZmzZy40rX8LjI6qFYCzdV66cu18= github.com/tikv/pd/client v0.0.0-20260720043438-0b37df9a48ed h1:BiPn4oLXVqB9ptPNmyo3rh/2IH1dTouXrrnneH86Z3M= github.com/tikv/pd/client v0.0.0-20260720043438-0b37df9a48ed/go.mod h1:3/Bu91CJONgkDA+Y0v/cnbROSJnu5tQ09vv7JGybUBA= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= @@ -2385,6 +2378,10 @@ github.com/vbauerster/mpb/v7 v7.5.3 h1:BkGfmb6nMrrBQDFECR/Q7RkKCw7ylMetCb4079CGs github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9AhY/PnuOE= github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f h1:9DDCDwOyEy/gId+IEMrFHLuQ5R/WV0KNxWLler8X2OY= github.com/wangjohn/quickselect v0.0.0-20161129230411-ed8402a42d5f/go.mod h1:8sdOQnirw1PrcnTJYkmW1iOHtUmblMmGdUOHyWYycLI= +github.com/wfxr/client-go/v2 v2.0.8-0.20260812071238-dcfbdfcfb5af h1:mqjqOtWPO+TVbH8lxEghT2DBcoZqR5vsQQLVwUKJgYo= +github.com/wfxr/client-go/v2 v2.0.8-0.20260812071238-dcfbdfcfb5af/go.mod h1:NzPB1DJT9cf9e/tAD4F89q6NB/lfpmPINvn8gDvzLus= +github.com/wfxr/kvproto v0.0.0-20260806092442-d04fa0402753 h1:wQuil8SCJhSp+LJqqiMgPjzBZgzobJCIQFp52UIYq6Y= +github.com/wfxr/kvproto v0.0.0-20260806092442-d04fa0402753/go.mod h1:z6+aAHB7dBkA+LyinEX+48/ImRJ3jag0Hg0c7wkhEvE= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -2551,6 +2548,16 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2618,11 +2625,19 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -2689,6 +2704,17 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2751,6 +2777,12 @@ golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2853,9 +2885,26 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= +golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw= +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= +golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2878,6 +2927,15 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2903,6 +2961,16 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2979,6 +3047,15 @@ golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= @@ -3085,7 +3162,6 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -3301,7 +3377,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v0.0.0-20180607172857-7a6a684ca69e/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= diff --git a/pkg/errno/errcode.go b/pkg/errno/errcode.go index d8d3e0e895a93..b83a1d3fd47f1 100644 --- a/pkg/errno/errcode.go +++ b/pkg/errno/errcode.go @@ -1197,5 +1197,6 @@ const ( ErrTiFlashServerTimeout = 9012 ErrTiFlashServerBusy = 9013 ErrTiFlashBackfillIndex = 9014 + ErrSharedLockLost = 9015 ErrUserPrefixMismatch = 20003 ) diff --git a/pkg/errno/errname.go b/pkg/errno/errname.go index 9d0023b98cc22..4a0526849df70 100644 --- a/pkg/errno/errname.go +++ b/pkg/errno/errname.go @@ -1184,8 +1184,12 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{ ErrTiFlashServerTimeout: mysql.Message("TiFlash server timeout", nil), ErrTiFlashServerBusy: mysql.Message("TiFlash server is busy", nil), ErrTiFlashBackfillIndex: mysql.Message("TiFlash backfill index failed: %s", nil), - ErrResolveLockTimeout: mysql.Message("Resolve lock timeout", nil), - ErrRegionUnavailable: mysql.Message("Region is unavailable", nil), + ErrSharedLockLost: mysql.Message( + "Shared lock was lost during lock upgrade; transaction cannot continue, txnStartTS=%d, key=%s", + []int{1}, + ), + ErrResolveLockTimeout: mysql.Message("Resolve lock timeout", nil), + ErrRegionUnavailable: mysql.Message("Region is unavailable", nil), // In most cases, the error `ErrTxnAbortedByGC` is caused by the transaction runs too long, instead of improper GC // life time configuration. This means the description of this error is not accurate. // However, as this error message is already widely acknowledged and might have become part of our diagnosing diff --git a/pkg/executor/select.go b/pkg/executor/select.go index 1b74343457f72..f458ed5d94bb5 100644 --- a/pkg/executor/select.go +++ b/pkg/executor/select.go @@ -345,6 +345,7 @@ func newLockCtx(sctx sessionctx.Context, lockWaitTime int64, numKeys int, inShar lockCtx.Killed = &seVars.SQLKiller.Signal lockCtx.LockExpired = &seVars.TxnCtx.LockExpire lockCtx.InShareMode = inSharedMode + lockCtx.AllowSharedLockUpgrade = seVars.EnableSharedLockUpgrade // Set max_execution_time deadline for SELECT statements maxExectionTime := seVars.GetMaxExecutionTime() diff --git a/pkg/executor/select_test.go b/pkg/executor/select_test.go index 2889e28fc5879..ff6249a25a7ce 100644 --- a/pkg/executor/select_test.go +++ b/pkg/executor/select_test.go @@ -12,26 +12,86 @@ // See the License for the specific language governing permissions and // limitations under the License. -package executor_test +package executor import ( + "context" "fmt" "testing" "github.com/pingcap/tidb/pkg/domain" - "github.com/pingcap/tidb/pkg/executor" + "github.com/pingcap/tidb/pkg/infoschema" + "github.com/pingcap/tidb/pkg/kv" "github.com/pingcap/tidb/pkg/parser/ast" "github.com/pingcap/tidb/pkg/parser/mysql" + "github.com/pingcap/tidb/pkg/sessionctx" + "github.com/pingcap/tidb/pkg/sessiontxn" "github.com/pingcap/tidb/pkg/util/mock" "github.com/stretchr/testify/require" ) +type stubTxnManager struct { + forUpdateTS uint64 +} + +func (m stubTxnManager) AdviseWarmup() error { return nil } + +func (m stubTxnManager) AdviseOptimizeWithPlan(any) error { return nil } + +func (m stubTxnManager) GetTxnInfoSchema() infoschema.InfoSchema { return nil } + +func (m stubTxnManager) GetTxnScope() string { return "" } + +func (m stubTxnManager) GetReadReplicaScope() string { return "" } + +func (m stubTxnManager) GetStmtReadTS() (uint64, error) { return 0, nil } + +func (m stubTxnManager) GetStmtForUpdateTS() (uint64, error) { return m.forUpdateTS, nil } + +func (m stubTxnManager) GetContextProvider() sessiontxn.TxnContextProvider { return nil } + +func (m stubTxnManager) GetSnapshotWithStmtReadTS() (kv.Snapshot, error) { return nil, nil } + +func (m stubTxnManager) GetSnapshotWithStmtForUpdateTS() (kv.Snapshot, error) { return nil, nil } + +func (m stubTxnManager) EnterNewTxn(context.Context, *sessiontxn.EnterNewTxnRequest) error { + return nil +} + +func (m stubTxnManager) OnTxnEnd() {} + +func (m stubTxnManager) OnStmtStart(context.Context, ast.StmtNode) error { return nil } + +func (m stubTxnManager) OnPessimisticStmtStart(context.Context) error { return nil } + +func (m stubTxnManager) OnPessimisticStmtEnd(context.Context, bool) error { return nil } + +func (m stubTxnManager) OnStmtErrorForNextAction(context.Context, sessiontxn.StmtErrorHandlePoint, error) (sessiontxn.StmtErrorAction, error) { + return sessiontxn.StmtActionNoIdea, nil +} + +func (m stubTxnManager) OnStmtRetry(context.Context) error { return nil } + +func (m stubTxnManager) OnStmtCommit(context.Context) error { return nil } + +func (m stubTxnManager) OnStmtRollback(context.Context, bool) error { return nil } + +func (m stubTxnManager) OnStmtEnd() {} + +func (m stubTxnManager) OnLocalTemporaryTableCreated() {} + +func (m stubTxnManager) ActivateTxn() (kv.Transaction, error) { return nil, nil } + +func (m stubTxnManager) GetCurrentStmt() ast.StmtNode { return nil } + +func (m stubTxnManager) SetOptionsBeforeCommit(kv.Transaction, func(uint64) bool) error { return nil } + func BenchmarkResetContextOfStmt(b *testing.B) { stmt := &ast.SelectStmt{} ctx := mock.NewContext() ctx.BindDomainAndSchValidator(&domain.Domain{}, nil) for i := 0; i < b.N; i++ { - executor.ResetContextOfStmt(ctx, stmt) + ResetContextOfStmt(ctx, stmt) } } @@ -58,13 +118,32 @@ func TestImportIntoShouldHaveSameFlagsAsInsert(t *testing.T) { mode, err := mysql.GetSQLMode(modeStr) require.NoError(t, err) insertCtx.GetSessionVars().SQLMode = mode - require.NoError(t, executor.ResetContextOfStmt(insertCtx, insertStmt)) + require.NoError(t, ResetContextOfStmt(insertCtx, insertStmt)) importCtx.GetSessionVars().SQLMode = mode - require.NoError(t, executor.ResetContextOfStmt(importCtx, importStmt)) + require.NoError(t, ResetContextOfStmt(importCtx, importStmt)) insertTypeCtx := insertCtx.GetSessionVars().StmtCtx.TypeCtx() importTypeCtx := importCtx.GetSessionVars().StmtCtx.TypeCtx() require.EqualValues(t, insertTypeCtx.Flags(), importTypeCtx.Flags()) }) } + + t.Run("shared lock upgrade gate propagates to lock ctx", func(t *testing.T) { + originalGetTxnManager := sessiontxn.GetTxnManager + sessiontxn.GetTxnManager = func(sctx sessionctx.Context) sessiontxn.TxnManager { + return stubTxnManager{forUpdateTS: 9527} + } + t.Cleanup(func() { + sessiontxn.GetTxnManager = originalGetTxnManager + }) + + sctx := mock.NewContext() + sctx.GetSessionVars().EnableSharedLockUpgrade = true + + lockCtx, err := newLockCtx(sctx, 123, 1, true) + require.NoError(t, err) + require.True(t, lockCtx.InShareMode) + require.True(t, lockCtx.AllowSharedLockUpgrade) + require.Equal(t, uint64(9527), lockCtx.ForUpdateTS) + }) } diff --git a/pkg/kv/error.go b/pkg/kv/error.go index b09326477bee3..ea3e942d07878 100644 --- a/pkg/kv/error.go +++ b/pkg/kv/error.go @@ -70,6 +70,8 @@ var ( mysql.MySQLErrName[mysql.ErrWriteConflictInTiDB].RedactArgPos, ), ) + // ErrSharedLockLost means a shared lock was confirmed lost during upgrade. + ErrSharedLockLost = dbterror.ClassTiKV.NewStd(mysql.ErrSharedLockLost) // ErrLockExpire is the error when the lock is expired. ErrLockExpire = dbterror.ClassTiKV.NewStd(mysql.ErrLockExpire) // ErrAssertionFailed is the error when an assertion fails. diff --git a/pkg/kv/error_test.go b/pkg/kv/error_test.go index 08c2bde9e9c62..221a11b5bb5b3 100644 --- a/pkg/kv/error_test.go +++ b/pkg/kv/error_test.go @@ -33,6 +33,7 @@ func TestError(t *testing.T) { ErrNotImplemented, ErrWriteConflict, ErrWriteConflictInTiDB, + ErrSharedLockLost, } for _, err := range kvErrs { diff --git a/pkg/session/BUILD.bazel b/pkg/session/BUILD.bazel index 3409da45ce352..191bfa7ef7149 100644 --- a/pkg/session/BUILD.bazel +++ b/pkg/session/BUILD.bazel @@ -196,11 +196,13 @@ go_test( "//pkg/parser/auth", "//pkg/parser/format", "//pkg/parser/mysql", + "//pkg/session/metrics", "//pkg/session/sessionapi", "//pkg/sessionctx", "//pkg/sessionctx/stmtctx", "//pkg/sessionctx/vardef", "//pkg/sessionctx/variable", + "//pkg/sessiontxn", "//pkg/statistics", "//pkg/store", "//pkg/store/mockstore", @@ -214,6 +216,7 @@ go_test( "//pkg/util", "//pkg/util/benchdaily", "//pkg/util/chunk", + "//pkg/util/dbterror/exeerrors", "//pkg/util/execdetails", "//pkg/util/logutil", "//pkg/util/memory", diff --git a/pkg/session/tidb.go b/pkg/session/tidb.go index 47c231e6f8c05..6ae7d0a88b56b 100644 --- a/pkg/session/tidb.go +++ b/pkg/session/tidb.go @@ -298,6 +298,16 @@ func shouldCheckConnectionAliveBeforeCommit(sessVars *variable.SessionVars, sql } } +func shouldRollbackTxnOnError(txn kv.Transaction, err error) bool { + if !txn.Valid() { + return false + } + if kv.ErrSharedLockLost.Equal(err) { + return true + } + return txn.IsPessimistic() && exeerrors.ErrDeadlock.Equal(err) +} + func autoCommitAfterStmt(ctx context.Context, se *session, meetsErr error, sql sqlexec.Statement) error { isInternal := false if internal := se.txn.GetOption(kv.RequestSourceInternal); internal != nil && internal.(bool) { @@ -309,8 +319,16 @@ func autoCommitAfterStmt(ctx context.Context, se *session, meetsErr error, sql s logutil.BgLogger().Info("rollbackTxn called due to ddl/autocommit failure") se.RollbackTxn(ctx) recordAbortTxnDuration(sessVars, isInternal) - } else if se.txn.Valid() && se.txn.IsPessimistic() && exeerrors.ErrDeadlock.Equal(meetsErr) { - logutil.BgLogger().Info("rollbackTxn for deadlock", zap.Uint64("txn", se.txn.StartTS())) + } else if shouldRollbackTxnOnError(&se.txn, meetsErr) { + if kv.ErrSharedLockLost.Equal(meetsErr) { + logutil.BgLogger().Info( + "rollbackTxn for shared lock loss", + zap.Uint64("txn", se.txn.StartTS()), + zap.Error(meetsErr), + ) + } else { + logutil.BgLogger().Info("rollbackTxn for deadlock", zap.Uint64("txn", se.txn.StartTS())) + } se.RollbackTxn(ctx) recordAbortTxnDuration(sessVars, isInternal) } diff --git a/pkg/session/tidb_test.go b/pkg/session/tidb_test.go index ea3412448d9f5..746abddf09e40 100644 --- a/pkg/session/tidb_test.go +++ b/pkg/session/tidb_test.go @@ -22,14 +22,108 @@ import ( "github.com/pingcap/tidb/pkg/kv" "github.com/pingcap/tidb/pkg/meta" "github.com/pingcap/tidb/pkg/parser/ast" + session_metrics "github.com/pingcap/tidb/pkg/session/metrics" "github.com/pingcap/tidb/pkg/sessionctx/vardef" + "github.com/pingcap/tidb/pkg/sessiontxn" "github.com/pingcap/tidb/pkg/store/mockstore" "github.com/pingcap/tidb/pkg/util" + "github.com/pingcap/tidb/pkg/util/dbterror/exeerrors" "github.com/pingcap/tidb/pkg/util/execdetails" "github.com/pingcap/tidb/pkg/util/sqlexec" "github.com/stretchr/testify/require" ) +type recordingObserver struct { + count int +} + +func (o *recordingObserver) Observe(float64) { + o.count++ +} + +func TestSharedLockLostRollsBackTransaction(t *testing.T) { + store, dom := CreateStoreAndBootstrap(t) + defer func() { require.NoError(t, store.Close()) }() + defer dom.Close() + + testCases := []struct { + name string + beginSQL string + pessimistic bool + sharedLockLost bool + }{ + { + name: "pessimistic shared lock lost", + beginSQL: "begin pessimistic", + pessimistic: true, + sharedLockLost: true, + }, + { + name: "optimistic shared lock lost mode mismatch", + beginSQL: "begin optimistic", + pessimistic: false, + sharedLockLost: true, + }, + { + name: "pessimistic deadlock unchanged", + beginSQL: "begin pessimistic", + pessimistic: true, + sharedLockLost: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + se, err := createSession(store) + require.NoError(t, err) + defer se.Close() + + MustExec(t, se, testCase.beginSQL) + txnManager := sessiontxn.GetTxnManager(se) + txn, err := txnManager.ActivateTxn() + require.NoError(t, err) + require.True(t, txn.Valid()) + require.Equal(t, testCase.pessimistic, txn.IsPessimistic()) + require.NotNil(t, txnManager.GetContextProvider()) + + recorder := &recordingObserver{} + var restoreObserver func() + if testCase.pessimistic { + originalObserver := session_metrics.TransactionDurationPessimisticAbortGeneral + session_metrics.TransactionDurationPessimisticAbortGeneral = recorder + restoreObserver = func() { + session_metrics.TransactionDurationPessimisticAbortGeneral = originalObserver + } + } else { + originalObserver := session_metrics.TransactionDurationOptimisticAbortGeneral + session_metrics.TransactionDurationOptimisticAbortGeneral = recorder + restoreObserver = func() { + session_metrics.TransactionDurationOptimisticAbortGeneral = originalObserver + } + } + defer restoreObserver() + + var stmtErr error + if testCase.sharedLockLost { + stmtErr = kv.ErrSharedLockLost.GenWithStackByArgs(txn.StartTS(), "6B6579") + } else { + stmtErr = exeerrors.ErrDeadlock + } + got := autoCommitAfterStmt(context.Background(), se, stmtErr, nil) + require.Same(t, stmtErr, got) + if testCase.sharedLockLost { + require.True(t, kv.ErrSharedLockLost.Equal(got)) + } else { + require.True(t, exeerrors.ErrDeadlock.Equal(got)) + } + require.False(t, se.sessionVars.InTxn()) + require.False(t, se.txn.Valid()) + require.Nil(t, txnManager.GetContextProvider()) + require.Equal(t, 1, recorder.count) + }) + } +} + func TestDomapHandleNil(t *testing.T) { // this is required for enterprise plugins // ref: https://github.com/pingcap/tidb/issues/37319 diff --git a/pkg/sessionctx/vardef/tidb_vars.go b/pkg/sessionctx/vardef/tidb_vars.go index a644096aec0c0..7132b750dcf8c 100644 --- a/pkg/sessionctx/vardef/tidb_vars.go +++ b/pkg/sessionctx/vardef/tidb_vars.go @@ -1144,6 +1144,9 @@ const ( // TiDBEnableSharedLockPromotion indicates whether the `select for share` statement would be executed // as `select for update` statements which do acquire pessimistic locks. TiDBEnableSharedLockPromotion = "tidb_enable_shared_lock_promotion" + // TiDBEnableSharedLockUpgrade indicates whether shared locks are allowed to upgrade to exclusive locks + // during pessimistic locking. + TiDBEnableSharedLockUpgrade = "tidb_enable_shared_lock_upgrade" // TiDBAccelerateUserCreationUpdate decides whether tidb will load & update the whole user's data in-memory. TiDBAccelerateUserCreationUpdate = "tidb_accelerate_user_creation_update" @@ -1861,6 +1864,7 @@ const ( DefTiDBEnableLazyCursorFetch = false DefOptEnableProjectionPushDown = true DefTiDBEnableSharedLockPromotion = false + DefTiDBEnableSharedLockUpgrade = false DefTiDBTSOClientRPCMode = TSOClientRPCModeDefault DefTiDBCircuitBreakerPDMetaErrorRateRatio = 0.0 DefTiDBAccelerateUserCreationUpdate = false diff --git a/pkg/sessionctx/variable/session.go b/pkg/sessionctx/variable/session.go index b0aeeaec10cd8..1046f39c91af8 100644 --- a/pkg/sessionctx/variable/session.go +++ b/pkg/sessionctx/variable/session.go @@ -1887,6 +1887,10 @@ type SessionVars struct { // `select for update` statements which do acquire pessimsitic locks. SharedLockPromotion bool + // EnableSharedLockUpgrade indicates whether shared locks may be upgraded to exclusive locks during + // pessimistic locking. + EnableSharedLockUpgrade bool + // ScatterRegion will scatter the regions for DDLs when it is "table" or "global", "" indicates not trigger scatter. ScatterRegion string diff --git a/pkg/sessionctx/variable/sysvar.go b/pkg/sessionctx/variable/sysvar.go index 7b100207dccdc..4c46bce0ba321 100644 --- a/pkg/sessionctx/variable/sysvar.go +++ b/pkg/sessionctx/variable/sysvar.go @@ -3995,6 +3995,19 @@ var defaultSysVars = []*SysVar{ s.SharedLockPromotion = TiDBOptOn(val) return nil }}, + {Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBEnableSharedLockUpgrade, Value: BoolToOnOff(vardef.DefTiDBEnableSharedLockUpgrade), Type: vardef.TypeBool, + Validation: func(_ *SessionVars, normalizedValue string, originalValue string, _ vardef.ScopeFlag) (string, error) { + if TiDBOptOn(normalizedValue) && !kerneltype.IsNextGen() { + return normalizedValue, ErrWrongValueForVar.GenWithStackByArgs( + vardef.TiDBEnableSharedLockUpgrade, + originalValue, + ) + } + return normalizedValue, nil + }, SetSession: func(s *SessionVars, val string) error { + s.EnableSharedLockUpgrade = TiDBOptOn(val) + return nil + }}, {Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBMaxDistTaskNodes, Value: strconv.Itoa(vardef.DefTiDBMaxDistTaskNodes), Type: vardef.TypeInt, MinValue: -1, MaxValue: 128, Validation: func(s *SessionVars, normalizedValue string, originalValue string, scope vardef.ScopeFlag) (string, error) { maxNodes := TidbOptInt(normalizedValue, vardef.DefTiDBMaxDistTaskNodes) diff --git a/pkg/sessionctx/variable/sysvar_test.go b/pkg/sessionctx/variable/sysvar_test.go index a00f8b618eed2..5831df3349acd 100644 --- a/pkg/sessionctx/variable/sysvar_test.go +++ b/pkg/sessionctx/variable/sysvar_test.go @@ -1759,6 +1759,86 @@ func TestTiDBForeignKeyCheckInSharedLockGate(t *testing.T) { require.Equal(t, vardef.On, sessionVal) } +func TestTiDBEnableSharedLockUpgradeGate(t *testing.T) { + ctx := context.Background() + restore := config.RestoreFunc() + t.Cleanup(restore) + config.UpdateGlobal(func(conf *config.Config) { + conf.Experimental.AllowEnableForeignKeyCheckInSharedLock = false + }) + + vars := NewSessionVars(nil) + mock := NewMockGlobalAccessor4Tests() + mock.SessionVars = vars + vars.GlobalVarsAccessor = mock + + if !kerneltype.IsNextGen() { + for _, val := range []string{vardef.On, "1"} { + err := vars.SetSystemVar(vardef.TiDBEnableSharedLockUpgrade, val) + require.Error(t, err, val) + require.True(t, ErrWrongValueForVar.Equal(err), err) + require.Contains(t, err.Error(), "value of '"+val+"'", err) + require.False(t, vars.EnableSharedLockUpgrade) + sessionVal, err := vars.GetSessionOrGlobalSystemVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, + ) + require.NoError(t, err) + require.Equal(t, vardef.Off, sessionVal) + } + require.NoError(t, vars.SetSystemVar( + vardef.TiDBEnableSharedLockUpgrade, vardef.Off, + )) + require.False(t, vars.EnableSharedLockUpgrade) + + for _, val := range []string{vardef.On, "1"} { + err := mock.SetGlobalSysVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, val, + ) + require.Error(t, err, val) + require.True(t, ErrWrongValueForVar.Equal(err), err) + require.Contains(t, err.Error(), "value of '"+val+"'", err) + rawGlobalVal, err := mock.GetGlobalSysVar( + vardef.TiDBEnableSharedLockUpgrade, + ) + require.NoError(t, err) + require.Equal(t, vardef.Off, rawGlobalVal) + } + require.NoError(t, mock.SetGlobalSysVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, vardef.Off, + )) + return + } + + for _, val := range []string{vardef.On, "1"} { + require.NoError(t, vars.SetSystemVar( + vardef.TiDBEnableSharedLockUpgrade, val, + ), val) + require.True(t, vars.EnableSharedLockUpgrade) + sessionVal, err := vars.GetSessionOrGlobalSystemVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, + ) + require.NoError(t, err) + require.Equal(t, vardef.On, sessionVal) + require.NoError(t, vars.SetSystemVar( + vardef.TiDBEnableSharedLockUpgrade, vardef.Off, + )) + } + + for _, val := range []string{vardef.On, "1"} { + require.NoError(t, mock.SetGlobalSysVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, val, + ), val) + globalVal, err := vars.GetGlobalSystemVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, + ) + require.NoError(t, err) + require.Equal(t, vardef.On, globalVal) + require.NoError(t, mock.SetGlobalSysVar( + ctx, vardef.TiDBEnableSharedLockUpgrade, vardef.Off, + )) + } +} + func TestTiDBOptTxnAutoRetry(t *testing.T) { sv := GetSysVar(vardef.TiDBDisableTxnAutoRetry) vars := NewSessionVars(nil) diff --git a/pkg/sessionctx/variable/varsutil_test.go b/pkg/sessionctx/variable/varsutil_test.go index c90854b2f270a..f3deb0f01cd13 100644 --- a/pkg/sessionctx/variable/varsutil_test.go +++ b/pkg/sessionctx/variable/varsutil_test.go @@ -93,6 +93,7 @@ func TestNewSessionVars(t *testing.T) { require.Equal(t, vardef.DefCTEMaxRecursionDepth, vars.CTEMaxRecursionDepth) require.Equal(t, int64(vardef.DefTiDBTmpTableMaxSize), vars.TMPTableSize) require.Equal(t, vardef.DefOptEnableAlternativeLogicalPlans, vars.EnableAlternativeLogicalPlans) + require.Equal(t, vardef.DefTiDBEnableSharedLockUpgrade, vars.EnableSharedLockUpgrade) assertFieldsGreaterThanZero(t, reflect.ValueOf(vars.MemQuota)) assertFieldsGreaterThanZero(t, reflect.ValueOf(vars.BatchSize)) diff --git a/pkg/store/driver/txn/BUILD.bazel b/pkg/store/driver/txn/BUILD.bazel index 67c68366026c6..10ce3238e37f1 100644 --- a/pkg/store/driver/txn/BUILD.bazel +++ b/pkg/store/driver/txn/BUILD.bazel @@ -26,6 +26,7 @@ go_library( "//pkg/util", "//pkg/util/intest", "//pkg/util/logutil", + "//pkg/util/redact", "//pkg/util/tracing", "@com_github_pingcap_errors//:errors", "@com_github_pingcap_failpoint//:failpoint", @@ -55,15 +56,18 @@ go_test( ], embed = [":txn"], flaky = True, - shard_count = 5, + shard_count = 7, deps = [ "//pkg/kv", + "//pkg/parser/terror", "//pkg/testkit/testsetup", + "//pkg/util/dbterror/exeerrors", "//pkg/util/mock", "@com_github_pingcap_errors//:errors", "@com_github_pingcap_kvproto//pkg/kvrpcpb", "@com_github_stretchr_testify//assert", "@com_github_stretchr_testify//require", + "@com_github_tikv_client_go_v2//error", "@org_uber_go_goleak//:goleak", ], ) diff --git a/pkg/store/driver/txn/driver_test.go b/pkg/store/driver/txn/driver_test.go index 815263a6823ce..66989c2fab5de 100644 --- a/pkg/store/driver/txn/driver_test.go +++ b/pkg/store/driver/txn/driver_test.go @@ -14,12 +14,16 @@ package txn import ( + stderrors "errors" "testing" "github.com/pingcap/errors" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/tidb/pkg/kv" + "github.com/pingcap/tidb/pkg/parser/terror" + "github.com/pingcap/tidb/pkg/util/dbterror/exeerrors" "github.com/stretchr/testify/require" + tikverr "github.com/tikv/client-go/v2/error" ) func TestLockNotFoundPrint(t *testing.T) { @@ -30,6 +34,73 @@ func TestLockNotFoundPrint(t *testing.T) { require.Equal(t, expected, key) } +func TestLockUpgradeConflictMapsToNonRetryableDeadlock(t *testing.T) { + err := extractKeyErr(errors.WithStack(&tikverr.ErrLockUpgradeConflict{ + LockUpgradeConflict: &kvrpcpb.LockUpgradeConflict{ + Key: []byte("key"), + StartTs: 101, + OwnerStartTs: 202, + Reason: kvrpcpb.LockUpgradeConflict_SecondUpgrader, + }, + })) + require.Error(t, err) + require.False(t, kv.ErrWriteConflict.Equal(err)) + require.False(t, kv.ErrTxnRetryable.Equal(err)) + + var deadlock *tikverr.ErrDeadlock + require.ErrorAs(t, err, &deadlock) + require.False(t, deadlock.IsRetryable) + require.Equal(t, uint64(202), deadlock.LockTs) + require.Equal(t, []byte("key"), deadlock.LockKey) +} + +func TestSharedLockLostErrorMapping(t *testing.T) { + originalMode := errors.RedactLogEnabled.Load() + t.Cleanup(func() { errors.RedactLogEnabled.Store(originalMode) }) + + newClientErr := func() error { + return errors.WithStack(&tikverr.ErrSharedLockLost{ + SharedLockLost: &kvrpcpb.SharedLockLost{ + Key: []byte("key"), + StartTs: 101, + }, + }) + } + + errors.RedactLogEnabled.Store(errors.RedactLogDisable) + err := extractKeyErr(newClientErr()) + require.EqualError( + t, + err, + "[tikv:9015]Shared lock was lost during lock upgrade; transaction cannot continue, txnStartTS=101, key=6B6579", + ) + require.True(t, kv.ErrSharedLockLost.Equal(err)) + require.False(t, kv.ErrTxnRetryable.Equal(err)) + require.False(t, kv.ErrWriteConflict.Equal(err)) + require.False(t, kv.IsTxnRetryableError(err)) + require.False(t, terror.ErrResultUndetermined.Equal(err)) + var deadlock *tikverr.ErrDeadlock + require.False(t, stderrors.As(err, &deadlock)) + require.False(t, exeerrors.ErrDeadlock.Equal(err)) + + emptyErr := extractKeyErr(errors.WithStack(&tikverr.ErrSharedLockLost{})) + require.EqualError( + t, + emptyErr, + "[tikv:9015]Shared lock was lost during lock upgrade; transaction cannot continue, txnStartTS=0, key=", + ) + require.True(t, kv.ErrSharedLockLost.Equal(emptyErr)) + + errors.RedactLogEnabled.Store(errors.RedactLogEnable) + redactedErr := extractKeyErr(newClientErr()) + require.EqualError( + t, + redactedErr, + "[tikv:9015]Shared lock was lost during lock upgrade; transaction cannot continue, txnStartTS=101, key=?", + ) + require.True(t, kv.ErrSharedLockLost.Equal(redactedErr)) +} + func TestWriteConflictPrettyFormat(t *testing.T) { conflict := &kvrpcpb.WriteConflict{ StartTs: 399402937522847774, diff --git a/pkg/store/driver/txn/error.go b/pkg/store/driver/txn/error.go index 2ec051cb40157..7c8e8ea2b80e5 100644 --- a/pkg/store/driver/txn/error.go +++ b/pkg/store/driver/txn/error.go @@ -35,6 +35,7 @@ import ( "github.com/pingcap/tidb/pkg/types" "github.com/pingcap/tidb/pkg/util" "github.com/pingcap/tidb/pkg/util/logutil" + "github.com/pingcap/tidb/pkg/util/redact" tikverr "github.com/tikv/client-go/v2/error" "go.uber.org/zap" ) @@ -156,9 +157,21 @@ func extractKeyErr(err error) error { if err == nil { return nil } + if e, ok := errors.Cause(err).(*tikverr.ErrSharedLockLost); ok { + return kv.ErrSharedLockLost.GenWithStackByArgs(e.GetStartTs(), redact.Key(e.GetKey())) + } if e, ok := errors.Cause(err).(*tikverr.ErrWriteConflict); ok { return newWriteConflictError(e.WriteConflict) } + if e, ok := errors.Cause(err).(*tikverr.ErrLockUpgradeConflict); ok { + return errors.WithStack(&tikverr.ErrDeadlock{ + Deadlock: &kvrpcpb.Deadlock{ + LockTs: e.OwnerStartTs, + LockKey: e.Key, + }, + IsRetryable: false, + }) + } if e, ok := errors.Cause(err).(*tikverr.ErrRetryable); ok { notFoundDetail := prettyLockNotFoundKey(e.Retryable) return kv.ErrTxnRetryable.GenWithStackByArgs(e.Retryable + " " + notFoundDetail) diff --git a/tests/realtikvtest/txntest/shared_lock_test.go b/tests/realtikvtest/txntest/shared_lock_test.go index b841694be6d37..088637a342d22 100644 --- a/tests/realtikvtest/txntest/shared_lock_test.go +++ b/tests/realtikvtest/txntest/shared_lock_test.go @@ -20,6 +20,9 @@ import ( "time" "github.com/pingcap/tidb/pkg/config" + "github.com/pingcap/tidb/pkg/config/kerneltype" + "github.com/pingcap/tidb/pkg/errno" + "github.com/pingcap/tidb/pkg/session/txninfo" "github.com/pingcap/tidb/pkg/testkit" "github.com/pingcap/tidb/pkg/testkit/testfailpoint" "github.com/pingcap/tidb/tests/realtikvtest" @@ -42,6 +45,31 @@ func allowForeignKeyCheckInSharedLockForTest(t *testing.T) { }) } +func prepareSharedLockUpgradeTables(tk *testkit.TestKit, fkOptions string) { + tk.MustExec("drop table if exists child, parent") + tk.MustExec("create table parent (id int primary key, v int)") + childTableSQL := "create table child (id int primary key, pid int, foreign key (pid) references parent(id)" + if fkOptions != "" { + childTableSQL += " " + fkOptions + } + childTableSQL += ")" + tk.MustExec(childTableSQL) + tk.MustExec("insert into parent values (1, 0), (2, 0)") +} + +func enableSharedLockUpgrade(tks ...*testkit.TestKit) { + for _, tk := range tks { + tk.MustExec("set @@tidb_enable_shared_lock_upgrade = ON") + } +} + +func requireTxnLockAcquiring(t *testing.T, waitingTk *testkit.TestKit) { + require.Eventuallyf(t, func() bool { + info := waitingTk.Session().TxnInfo() + return info != nil && info.State == txninfo.TxnLockAcquiring && info.BlockStartTime.Valid + }, 10*time.Second, 100*time.Millisecond, "expected session %d to be waiting on lock acquisition", waitingTk.Session().GetSessionVars().ConnectionID) +} + func TestForeignKeySharedLockOptimisticReverseReferenceOrder(t *testing.T) { if !*realtikvtest.WithRealTiKV { t.Skip("requires real TiKV") @@ -227,6 +255,80 @@ func TestSharedLockBlockExclusiveLock(t *testing.T) { tk1.MustExec("commit") tk1.MustExec("admin check table parent") tk1.MustExec("admin check table child") + + t.Run("shared_lock_upgrade_waits_for_last_holder", func(t *testing.T) { + if !kerneltype.IsNextGen() { + t.Skip("shared lock upgrade rollout acceptance is only required on next-gen") + } + + tk1 := testkit.NewTestKit(t, store) + tk2 := testkit.NewTestKit(t, store) + tk1.MustExec("use test") + tk2.MustExec("use test") + tk1.MustExec("set @@tidb_foreign_key_check_in_shared_lock = ON") + tk2.MustExec("set @@tidb_foreign_key_check_in_shared_lock = ON") + enableSharedLockUpgrade(tk1, tk2) + prepareSharedLockUpgradeTables(tk1, "") + + tk1.MustExec("begin pessimistic") + tk2.MustExec("begin pessimistic") + tk1.MustExec("insert into child values(1, 1)") + tk2.MustExec("insert into child values(2, 1)") + + upgraderDone := make(chan error, 1) + go func() { + upgraderDone <- tk1.ExecToErr("update parent set v = v + 1 where id = 1") + }() + + requireTxnLockAcquiring(t, tk1) + + tk2.MustExec("commit") + require.NoError(t, <-upgraderDone) + tk1.MustExec("commit") + + tk1.MustQuery("select * from parent order by id").Check(testkit.Rows("1 1", "2 0")) + tk1.MustQuery("select * from child order by id").Check(testkit.Rows("1 1", "2 1")) + tk1.MustExec("admin check table parent") + tk1.MustExec("admin check table child") + }) + + t.Run("second_upgrader_returns_deadlock", func(t *testing.T) { + if !kerneltype.IsNextGen() { + t.Skip("shared lock upgrade rollout acceptance is only required on next-gen") + } + + tk1 := testkit.NewTestKit(t, store) + tk2 := testkit.NewTestKit(t, store) + tk1.MustExec("use test") + tk2.MustExec("use test") + tk1.MustExec("set @@tidb_foreign_key_check_in_shared_lock = ON") + tk2.MustExec("set @@tidb_foreign_key_check_in_shared_lock = ON") + enableSharedLockUpgrade(tk1, tk2) + prepareSharedLockUpgradeTables(tk1, "") + + tk1.MustExec("begin pessimistic") + tk2.MustExec("begin pessimistic") + tk1.MustExec("insert into child values(1, 1)") + tk2.MustExec("insert into child values(2, 1)") + + upgraderDone := make(chan error, 1) + go func() { + upgraderDone <- tk1.ExecToErr("update parent set v = v + 1 where id = 1") + }() + + requireTxnLockAcquiring(t, tk1) + + tk2.MustGetErrCode("update parent set v = v + 2 where id = 1", errno.ErrLockDeadlock) + require.False(t, tk2.Session().GetSessionVars().InTxn()) + require.Nil(t, tk2.Session().TxnInfo()) + require.NoError(t, <-upgraderDone) + tk1.MustExec("commit") + + tk1.MustQuery("select * from parent order by id").Check(testkit.Rows("1 1", "2 0")) + tk1.MustQuery("select * from child order by id").Check(testkit.Rows("1 1")) + tk1.MustExec("admin check table parent") + tk1.MustExec("admin check table child") + }) } func TestSharedLockChildTableConflict(t *testing.T) { @@ -370,6 +472,81 @@ func TestSharedLockCascadeUpdateExplicitPessimisticTxn(t *testing.T) { tk.MustExec("admin check table c") }) } + + t.Run("insert_child_then_update_parent", func(t *testing.T) { + if !kerneltype.IsNextGen() { + t.Skip("shared lock upgrade rollout acceptance is only required on next-gen") + } + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("set @@global.tidb_enable_foreign_key=1") + defer tk.MustExec("set @@global.tidb_enable_foreign_key=default") + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("set @@tidb_foreign_key_check_in_shared_lock=ON") + enableSharedLockUpgrade(tk) + prepareSharedLockUpgradeTables(tk, "") + + tk.MustExec("begin pessimistic") + tk.MustExec("insert into child values (1, 1)") + tk.MustExec("update parent set v = v + 1 where id = 1") + tk.MustExec("commit") + + tk.MustQuery("select * from parent order by id").Check(testkit.Rows("1 1", "2 0")) + tk.MustQuery("select * from child order by id").Check(testkit.Rows("1 1")) + tk.MustExec("admin check table parent") + tk.MustExec("admin check table child") + }) + + t.Run("insert_child_then_delete_parent_restrict", func(t *testing.T) { + if !kerneltype.IsNextGen() { + t.Skip("shared lock upgrade rollout acceptance is only required on next-gen") + } + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("set @@global.tidb_enable_foreign_key=1") + defer tk.MustExec("set @@global.tidb_enable_foreign_key=default") + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("set @@tidb_foreign_key_check_in_shared_lock=ON") + enableSharedLockUpgrade(tk) + prepareSharedLockUpgradeTables(tk, "") + + tk.MustExec("begin pessimistic") + tk.MustExec("insert into child values (1, 1)") + tk.MustGetErrCode("delete from parent where id = 1", errno.ErrRowIsReferenced2) + tk.MustExec("commit") + + tk.MustQuery("select * from parent order by id").Check(testkit.Rows("1 0", "2 0")) + tk.MustQuery("select * from child order by id").Check(testkit.Rows("1 1")) + tk.MustExec("admin check table parent") + tk.MustExec("admin check table child") + }) + + t.Run("insert_child_then_delete_parent_cascade", func(t *testing.T) { + if !kerneltype.IsNextGen() { + t.Skip("shared lock upgrade rollout acceptance is only required on next-gen") + } + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("set @@global.tidb_enable_foreign_key=1") + defer tk.MustExec("set @@global.tidb_enable_foreign_key=default") + tk.MustExec("set @@foreign_key_checks=1") + tk.MustExec("set @@tidb_foreign_key_check_in_shared_lock=ON") + enableSharedLockUpgrade(tk) + prepareSharedLockUpgradeTables(tk, "on delete cascade") + + tk.MustExec("begin pessimistic") + tk.MustExec("insert into child values (1, 1)") + tk.MustExec("delete from parent where id = 1") + tk.MustExec("commit") + + tk.MustQuery("select * from parent order by id").Check(testkit.Rows("2 0")) + tk.MustQuery("select * from child").Check(testkit.Rows()) + tk.MustExec("admin check table parent") + tk.MustExec("admin check table child") + }) } func TestSharedLockLockView(t *testing.T) {