diff --git a/integration_tests/snapshot_test.go b/integration_tests/snapshot_test.go index 2e19342d..a8244ed4 100644 --- a/integration_tests/snapshot_test.go +++ b/integration_tests/snapshot_test.go @@ -47,6 +47,7 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/suite" "github.com/tikv/client-go/v2/error" + "github.com/tikv/client-go/v2/oracle" "github.com/tikv/client-go/v2/tikv" "github.com/tikv/client-go/v2/tikvrpc" "github.com/tikv/client-go/v2/txnkv" @@ -395,3 +396,27 @@ func (s *testSnapshotSuite) TestRCRead() { s.deleteKeys(keys) } } + +func (s *testSnapshotSuite) TestSnapshotCacheBypassMaxUint64() { + txn := s.beginTxn() + s.Nil(txn.Set([]byte("x"), []byte("x"))) + s.Nil(txn.Set([]byte("y"), []byte("y"))) + s.Nil(txn.Set([]byte("z"), []byte("z"))) + s.Nil(txn.Commit(context.Background())) + // cache version < math.MaxUint64 + startTS, err := s.store.GetTimestampWithRetry(tikv.NewNoopBackoff(context.Background()), oracle.GlobalTxnScope) + s.Nil(err) + snapshot := s.store.GetSnapshot(startTS) + snapshot.Get(context.Background(), []byte("x")) + snapshot.BatchGet(context.Background(), [][]byte{[]byte("y"), []byte("z")}) + s.Equal(snapshot.SnapCache(), map[string][]byte{ + "x": []byte("x"), + "y": []byte("y"), + "z": []byte("z"), + }) + // not cache version == math.MaxUint64 + snapshot = s.store.GetSnapshot(math.MaxUint64) + snapshot.Get(context.Background(), []byte("x")) + snapshot.BatchGet(context.Background(), [][]byte{[]byte("y"), []byte("z")}) + s.Empty(snapshot.SnapCache()) +} diff --git a/txnkv/txnsnapshot/snapshot.go b/txnkv/txnsnapshot/snapshot.go index cb5b38b1..f40e6bc9 100644 --- a/txnkv/txnsnapshot/snapshot.go +++ b/txnkv/txnsnapshot/snapshot.go @@ -1007,6 +1007,11 @@ func (s *KVSnapshot) SnapCache() map[string][]byte { // UpdateSnapshotCache sets the values of cache, for further fast read with same keys. func (s *KVSnapshot) UpdateSnapshotCache(keys [][]byte, m map[string][]byte) { + // s.version == math.MaxUint64 is used in special transaction, which always read the latest data. + // do not cache it to avoid anomaly. + if s.version == math.MaxUint64 { + return + } s.mu.Lock() defer s.mu.Unlock() if s.mu.cached == nil {