New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
store: implement non-block read when coprocessor meets the lock of a large transaction #11986
Merged
Merged
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
eab9b2a
store: implement non-block read when coprocessor meets the lock of a …
tiancaiamao 1bcb0f4
make golint happy
tiancaiamao d86c0bc
Merge branch 'master' into non-block-read
tiancaiamao 294cfc3
Merge branch 'master' into non-block-read
tiancaiamao 5e57d47
Merge branch 'master' into non-block-read
tiancaiamao d4e967f
address comment
tiancaiamao ac063c5
address comment
tiancaiamao 4c5e6ac
address comment
tiancaiamao a457c9f
go fmt
tiancaiamao af8acac
address comment
tiancaiamao 8dc46b2
Merge branch 'master' into non-block-read
tiancaiamao e813646
Merge branch 'master' into non-block-read
tiancaiamao 6bcd36d
address comment
tiancaiamao 57e6669
set minCommitTS in the prewrite request
tiancaiamao 552d679
address comment
tiancaiamao 0e75536
Merge branch 'master' into non-block-read
tiancaiamao ef41338
address comment
tiancaiamao 2d0f7e0
address comment
tiancaiamao 34b829e
Merge branch 'master' into non-block-read
tiancaiamao 2514021
fix CI
tiancaiamao d0cd1f7
fix CI
tiancaiamao 6f7566b
address comment
tiancaiamao 414af18
address comment
tiancaiamao 217dd9e
Merge branch 'master' into non-block-read
tiancaiamao a4465cc
address comment
tiancaiamao 4413774
Merge branch 'master' into non-block-read
tiancaiamao a83d9dc
Merge branch 'master' into non-block-read
tiancaiamao 8b94a33
do not push minCommitTS = 0
tiancaiamao 95525ce
make golint happy
tiancaiamao 40c850c
Merge branch 'master' into non-block-read
tiancaiamao 1db31b6
address comment
tiancaiamao 72eef5b
Merge branch 'master' into non-block-read
MyonKeminta aaaea2c
Merge branch 'master' into non-block-read
sre-bot File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2019-present, 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, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package mocktikv_test | ||
|
||
import ( | ||
"context" | ||
|
||
. "github.com/pingcap/check" | ||
"github.com/pingcap/errors" | ||
"github.com/pingcap/kvproto/pkg/kvrpcpb" | ||
"github.com/pingcap/parser/model" | ||
"github.com/pingcap/tidb/domain" | ||
"github.com/pingcap/tidb/kv" | ||
"github.com/pingcap/tidb/session" | ||
"github.com/pingcap/tidb/store/mockstore" | ||
"github.com/pingcap/tidb/store/mockstore/mocktikv" | ||
"github.com/pingcap/tidb/tablecodec" | ||
"github.com/pingcap/tidb/util/testkit" | ||
) | ||
|
||
var _ = Suite(&testExecutorSuite{}) | ||
|
||
type testExecutorSuite struct { | ||
cluster *mocktikv.Cluster | ||
store kv.Storage | ||
mvccStore mocktikv.MVCCStore | ||
dom *domain.Domain | ||
} | ||
|
||
func (s *testExecutorSuite) SetUpSuite(c *C) { | ||
s.cluster = mocktikv.NewCluster() | ||
mocktikv.BootstrapWithSingleStore(s.cluster) | ||
s.mvccStore = mocktikv.MustNewMVCCStore() | ||
store, err := mockstore.NewMockTikvStore( | ||
mockstore.WithCluster(s.cluster), | ||
mockstore.WithMVCCStore(s.mvccStore), | ||
) | ||
c.Assert(err, IsNil) | ||
s.store = store | ||
session.SetSchemaLease(0) | ||
session.DisableStats4Test() | ||
s.dom, err = session.BootstrapSession(s.store) | ||
c.Assert(err, IsNil) | ||
} | ||
|
||
func (s *testExecutorSuite) TearDownSuite(c *C) { | ||
s.dom.Close() | ||
s.store.Close() | ||
} | ||
|
||
func (s *testExecutorSuite) TestResolvedLargeTxnLocks(c *C) { | ||
// This test checks the resolve lock functionality. | ||
// When a txn meets the lock of a large transaction, it should not block by the | ||
// lock. | ||
tk := testkit.NewTestKit(c, s.store) | ||
tk.MustExec("use test") | ||
tk.MustExec("create table t (id int primary key, val int)") | ||
dom := domain.GetDomain(tk.Se) | ||
schema := dom.InfoSchema() | ||
tbl, err := schema.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) | ||
c.Assert(err, IsNil) | ||
|
||
tk.MustExec("insert into t values (1, 1)") | ||
|
||
oracle := s.store.GetOracle() | ||
tso, err := oracle.GetTimestamp(context.Background()) | ||
c.Assert(err, IsNil) | ||
|
||
key := tablecodec.EncodeRowKeyWithHandle(tbl.Meta().ID, 1) | ||
pairs := s.mvccStore.Scan(key, nil, 1, tso, kvrpcpb.IsolationLevel_SI, nil) | ||
c.Assert(pairs, HasLen, 1) | ||
c.Assert(pairs[0].Err, IsNil) | ||
|
||
// Simulate a large txn (holding a pk lock with large TTL). | ||
// Secondary lock 200ms, primary lock 100s | ||
mocktikv.MustPrewriteOK(c, s.mvccStore, mocktikv.PutMutations("primary", "value"), "primary", tso, 100000) | ||
tiancaiamao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mocktikv.MustPrewriteOK(c, s.mvccStore, mocktikv.PutMutations(string(key), "value"), "primary", tso, 200) | ||
|
||
// Simulate the action of reading meet the lock of a large txn. | ||
// The lock of the large transaction should not block read. | ||
// The first time, this query should meet a lock on the secondary key, then resolve lock. | ||
// After that, the query should read the previous version data. | ||
tk.MustQuery("select * from t").Check(testkit.Rows("1 1")) | ||
|
||
// And check the large txn is still alive. | ||
pairs = s.mvccStore.Scan([]byte("primary"), nil, 1, tso, kvrpcpb.IsolationLevel_SI, nil) | ||
c.Assert(pairs, HasLen, 1) | ||
_, ok := errors.Cause(pairs[0].Err).(*mocktikv.ErrLocked) | ||
c.Assert(ok, IsTrue) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,7 +206,7 @@ func (l *mvccLock) lockErr(key []byte) error { | |
} | ||
} | ||
|
||
func (l *mvccLock) check(ts uint64, key []byte) (uint64, error) { | ||
func (l *mvccLock) check(ts uint64, key []byte, resolvedLocks []uint64) (uint64, error) { | ||
// ignore when ts is older than lock or lock's type is Lock. | ||
// Pessimistic lock doesn't block read. | ||
if l.startTS > ts || l.op == kvrpcpb.Op_Lock || l.op == kvrpcpb.Op_PessimisticLock { | ||
|
@@ -216,17 +216,23 @@ func (l *mvccLock) check(ts uint64, key []byte) (uint64, error) { | |
if ts == math.MaxUint64 && bytes.Equal(l.primary, key) { | ||
return l.startTS - 1, nil | ||
} | ||
// Skip lock if the lock is resolved. | ||
for _, resolved := range resolvedLocks { | ||
if l.startTS == resolved { | ||
return l.startTS, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should return the original TS because the lock.startTS may be smaller than the latest commit TS and smaller than read ts. We return the ts only for |
||
} | ||
} | ||
return 0, l.lockErr(key) | ||
} | ||
|
||
func (e *mvccEntry) Less(than btree.Item) bool { | ||
return bytes.Compare(e.key, than.(*mvccEntry).key) < 0 | ||
} | ||
|
||
func (e *mvccEntry) Get(ts uint64, isoLevel kvrpcpb.IsolationLevel) ([]byte, error) { | ||
func (e *mvccEntry) Get(ts uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) ([]byte, error) { | ||
if isoLevel == kvrpcpb.IsolationLevel_SI && e.lock != nil { | ||
var err error | ||
ts, err = e.lock.check(ts, e.key.Raw()) | ||
ts, err = e.lock.check(ts, e.key.Raw(), resolvedLocks) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -251,8 +257,8 @@ func (e *rawEntry) Less(than btree.Item) bool { | |
// MVCCStore is a mvcc key-value storage. | ||
type MVCCStore interface { | ||
Get(key []byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) ([]byte, error) | ||
Scan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair | ||
ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair | ||
Scan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) []Pair | ||
ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel, resolvedLocks []uint64) []Pair | ||
BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair | ||
PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, forUpdateTS uint64, ttl uint64) []error | ||
PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this
-present
.