Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions error/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ func (d *ErrDeadlock) Error() string {
return d.String()
}

// ErrLockUpgradeConflict wraps *kvrpcpb.LockUpgradeConflict to implement the error interface.
type ErrLockUpgradeConflict struct {
*kvrpcpb.LockUpgradeConflict
}

func (e *ErrLockUpgradeConflict) Error() string {
return fmt.Sprintf("lock upgrade conflict { %s }", e.String())
}

// ErrSharedLockLost wraps *kvrpcpb.SharedLockLost to report that a transaction
// deterministically lost its shared-lock ownership during an upgrade.
type ErrSharedLockLost struct {
*kvrpcpb.SharedLockLost
}

func (e *ErrSharedLockLost) Error() string {
return fmt.Sprintf("shared lock lost { %s }", e.String())
}

// PDError wraps *pdpb.Error to implement the error interface.
type PDError struct {
Err *pdpb.Error
Expand Down Expand Up @@ -338,10 +357,18 @@ func ExtractKeyErr(keyErr *kvrpcpb.KeyError) error {

redact.RedactKeyErrIfNecessary(keyErr)

if keyErr.SharedLockLost != nil {
return errors.WithStack(&ErrSharedLockLost{SharedLockLost: keyErr.SharedLockLost})
}

if keyErr.Conflict != nil {
return errors.WithStack(NewErrWriteConflict(keyErr.GetConflict()))
}

if keyErr.LockUpgradeConflict != nil {
return errors.WithStack(&ErrLockUpgradeConflict{LockUpgradeConflict: keyErr.LockUpgradeConflict})
}

if keyErr.Retryable != "" {
return errors.WithStack(&ErrRetryable{Retryable: keyErr.Retryable})
}
Expand Down
55 changes: 55 additions & 0 deletions error/error_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,68 @@
package error

import (
stderrs "errors"
"testing"

"github.com/pingcap/errors"
"github.com/pingcap/kvproto/pkg/kvrpcpb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestExtractKeyErrLockUpgradeConflict(t *testing.T) {
keyErr := &kvrpcpb.KeyError{
LockUpgradeConflict: &kvrpcpb.LockUpgradeConflict{
Key: []byte("key"),
StartTs: 101,
OwnerStartTs: 202,
Reason: kvrpcpb.LockUpgradeConflict_SecondUpgrader,
},
}

err := ExtractKeyErr(keyErr)
require.Error(t, err)
require.False(t, IsErrWriteConflict(err))

var retryable *ErrRetryable
require.False(t, stderrs.As(err, &retryable))

var conflict *ErrLockUpgradeConflict
require.ErrorAs(t, err, &conflict)
require.Equal(t, []byte("key"), conflict.Key)
require.Equal(t, uint64(101), conflict.StartTs)
require.Equal(t, uint64(202), conflict.OwnerStartTs)
require.Equal(t, kvrpcpb.LockUpgradeConflict_SecondUpgrader, conflict.Reason)
}

func TestExtractKeyErrSharedLockLost(t *testing.T) {
keyErr := &kvrpcpb.KeyError{
SharedLockLost: &kvrpcpb.SharedLockLost{
Key: []byte("key"),
StartTs: 101,
},
Conflict: &kvrpcpb.WriteConflict{
StartTs: 101,
Reason: kvrpcpb.WriteConflict_PessimisticRetry,
},
}

err := ExtractKeyErr(keyErr)
require.Error(t, err)
require.False(t, IsErrWriteConflict(err))
require.False(t, IsErrorUndetermined(err))

var retryable *ErrRetryable
require.False(t, stderrs.As(err, &retryable))
var deadlock *ErrDeadlock
require.False(t, stderrs.As(err, &deadlock))

var lost *ErrSharedLockLost
require.ErrorAs(t, err, &lost)
require.Equal(t, []byte("key"), lost.Key)
require.Equal(t, uint64(101), lost.StartTs)
}

func TestExtractDebugInfoStrFromKeyErr(t *testing.T) {
origRedact := errors.RedactLogEnabled.Load()
defer errors.RedactLogEnabled.Store(origRedact)
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/pingcap/errors v0.11.5-0.20241219054535-6b8c588c3122
github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86
github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989
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.20221110025148-ca232912c9f3
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.5
Expand All @@ -35,6 +35,8 @@ require (
modernc.org/mathutil v1.7.1
)

replace github.com/pingcap/kvproto => github.com/wfxr/kvproto v0.0.0-20260806092442-d04fa0402753

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 h1:tdMsjOqUR7YXH
github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86/go.mod h1:exzhVYca3WRtd6gclGNErRWb1qEgff3LYta0LvRmON4=
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-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 v1.1.1-0.20221110025148-ca232912c9f3 h1:HR/ylkkLmGdSSDaD8IDP+SZrdhV1Kibl9KrHxJ9eciw=
github.com/pingcap/log v1.1.1-0.20221110025148-ca232912c9f3/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -119,6 +117,8 @@ github.com/tikv/pd/client v0.0.0-20260708075407-4e05b9d2c2d3 h1:OoBvgoeWmdNEXtS+
github.com/tikv/pd/client v0.0.0-20260708075407-4e05b9d2c2d3/go.mod h1:3/Bu91CJONgkDA+Y0v/cnbROSJnu5tQ09vv7JGybUBA=
github.com/twmb/murmur3 v1.1.3 h1:D83U0XYKcHRYwYIpBKf3Pks91Z0Byda/9SJ8B6EMRcA=
github.com/twmb/murmur3 v1.1.3/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
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/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
Expand Down
3 changes: 2 additions & 1 deletion integration_tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/ninedraft/israce v0.0.3
github.com/pingcap/errors v0.11.5-0.20260508054701-306e305bcf41
github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86
github.com/pingcap/kvproto v0.0.0-20260721064811-683dad8fa368
github.com/pingcap/kvproto v0.0.0-20260806092442-d04fa0402753

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

cd integration_tests

go list -m -f '{{.Path}}@{{.Version}}{{if .Replace}} => {{.Replace.Path}}@{{.Replace.Version}}{{end}}' \
  github.com/pingcap/kvproto

go mod graph |
  awk '$2 ~ /^github.com\/pingcap\/kvproto@/ { print $2 }' |
  sort -u

go mod tidy -diff
go mod verify

Repository: tikv/client-go

Length of output: 144


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,120p'
echo "== go.mod snippets =="
if [ -f integration_tests/go.mod ]; then
  nl -ba integration_tests/go.mod | sed -n '1,40p;160,190p'
fi
echo "== go.sum kvproto entries =="
if [ -f integration_tests/go.sum ]; then
  rg -n 'github.com/(pingcap|wfxr)/kvproto|github.com/tikv/client-go/v2' integration_tests/go.sum || true
fi
echo "== imports/usages =="
rg -n 'pingcap/kvproto|wfxr/kvproto|ErrShared|LockShared|shared.lock|shared lock' -g '*.go' -g 'go.mod' -g 'go.sum' integration_tests || true

Repository: tikv/client-go

Length of output: 3794


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== integration_tests/go.mod lines =="
sed -n '1,35p;150,190p' integration_tests/go.mod
echo "== integration_tests/go.sum kvproto references =="
awk '
  /github\.com\/(pingcap|wfxr)\/kvproto/ || /github\.com\/tikv\/client-go/v2/ { print }
' integration_tests/go.sum | sed -n '1,120p'
echo "== shared-lock error schema definitions =="
rg -n 'ErrShared|Shared|shared_lock|shared lock|lock_shared|LockShared' integration_tests shared_lock_test lock_test internal error --glob '*.go' --glob 'go.mod' --glob 'go.sum' || true
echo "== go command availability =="
command -v go || true
go version || true

Repository: tikv/client-go

Length of output: 3462


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== go.sum kvproto references =="
grep -n 'github.com/\(pingcap\|wfxr\)/kvproto\|github.com/tikv/client-go/v2' integration_tests/go.sum || true
echo "== shared_lock references =="
grep -RInE 'ErrShared|Shared|shared_lock|shared lock|lock_shared|LockShared' integration_tests --include='*.go' --include='go.mod' --include='go.sum' || true
echo "== go command availability =="
command -v go || true
go version || true

Repository: tikv/client-go

Length of output: 7333


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

cd integration_tests

echo "== required module line =="
grep -n 'require github.com/pingcap/kvproto\|github.com/pingcap/kvproto' go.mod
echo "== replace directive line =="
grep -n '^replace github.com/pingcap/kvproto' go.mod
echo "== direct module info =="
go list -m -json github.com/pingcap/kvproto | sed -n '1,80p'
echo "== module graph kvproto lines =="
go mod graph | grep 'github.com/pingcap/kvproto@' | sort -u || true
echo "== tidy diff status =="
if ! go mod tidy -diff; then
  true
fi
echo "== module verify status =="
if ! go mod verify; then
  true
fi

Repository: tikv/client-go

Length of output: 368


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

cd integration_tests

echo "== module info =="
go list -m -json github.com/pingcap/kvproto
echo "== module graph kvproto lines =="
go mod graph | grep 'github.com/pingcap/kvproto@' | sort -u || true
echo "== mod tidy diff exit status =="
go mod tidy; echo "exit=$?"
echo "== mod verify exit status =="
go mod verify; echo "exit=$?"

Repository: tikv/client-go

Length of output: 22249


Limit the kvproto replacement to the versions that need it.

The unversioned replace directive also substitutes the older github.com/pingcap/kvproto@v0.0.0-20260622063236-b41e86365ce0 selected by tikb/pd/client, while the direct module target is the newer commit. Scope the replacement to the single version that requires github.com/wfxr/kvproto unless the older transitive version is also compatible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integration_tests/go.mod` at line 10, Scope the kvproto replacement in the
integration test module to the specific newer version requiring
github.com/wfxr/kvproto, rather than replacing every kvproto version. Preserve
the older transitive version selected by tikb/pd/client unless compatibility
with the replacement is verified.

github.com/pingcap/tidb v1.1.0-beta.0.20260715060322-10292a4f8697
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.0
Expand Down Expand Up @@ -177,5 +177,6 @@ require (

replace (
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/tikv/client-go/v2 => ../
)
Loading
Loading