From f242af22e85ae8f463196d3e59a5e8c2c5074e92 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Wed, 16 Oct 2019 17:05:28 +0800 Subject: [PATCH 01/21] support select for update no wait --- ddl/index.go | 2 +- executor/adapter.go | 2 +- executor/admin.go | 2 +- executor/executor.go | 17 +++-- executor/point_get.go | 4 +- go.mod | 4 ++ go.sum | 9 ++- kv/kv.go | 2 +- kv/mock.go | 2 +- kv/mock_test.go | 2 +- planner/core/point_get_plan.go | 4 +- planner/core/rule_column_pruning.go | 2 +- session/pessimistic_test.go | 86 ++++++++++++++++++++++++ store/mockstore/mocktikv/mvcc.go | 3 +- store/mockstore/mocktikv/mvcc_leveldb.go | 8 ++- store/mockstore/mocktikv/rpc.go | 10 +-- store/tikv/2pc.go | 10 +++ store/tikv/2pc_test.go | 10 +-- store/tikv/error.go | 1 + store/tikv/ticlient_test.go | 2 +- store/tikv/txn.go | 3 +- 21 files changed, 154 insertions(+), 31 deletions(-) diff --git a/ddl/index.go b/ddl/index.go index 1716cf2df3b4b..f1e5e6fdc0c16 100644 --- a/ddl/index.go +++ b/ddl/index.go @@ -869,7 +869,7 @@ func (w *addIndexWorker) backfillIndexInTxn(handleRange reorgIndexTask) (taskCtx // Lock the row key to notify us that someone delete or update the row, // then we should not backfill the index of it, otherwise the adding index is redundant. - err := txn.LockKeys(context.Background(), 0, idxRecord.key) + err := txn.LockKeys(context.Background(), 0, false, idxRecord.key) if err != nil { return errors.Trace(err) } diff --git a/executor/adapter.go b/executor/adapter.go index 79969e7af4dba..a945d6b0a39a6 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -557,7 +557,7 @@ func (a *ExecStmt) handlePessimisticDML(ctx context.Context, e Executor) error { return nil } forUpdateTS := txnCtx.GetForUpdateTS() - err = txn.LockKeys(ctx, forUpdateTS, keys...) + err = txn.LockKeys(ctx, forUpdateTS, false, keys...) if err == nil { return nil } diff --git a/executor/admin.go b/executor/admin.go index c9d0aa5f7fb6c..1b4bc3f28c0fc 100644 --- a/executor/admin.go +++ b/executor/admin.go @@ -432,7 +432,7 @@ func (e *RecoverIndexExec) backfillIndexInTxn(ctx context.Context, txn kv.Transa } recordKey := e.table.RecordKey(row.handle) - err := txn.LockKeys(ctx, 0, recordKey) + err := txn.LockKeys(ctx, 0, false, recordKey) if err != nil { return result, err } diff --git a/executor/executor.go b/executor/executor.go index 167a187a8db18..969ea18264a09 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -779,7 +779,7 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { return err } // If there's no handle or it's not a `SELECT FOR UPDATE` statement. - if len(e.tblID2Handle) == 0 || e.Lock != ast.SelectLockForUpdate { + if len(e.tblID2Handle) == 0 || (e.Lock != ast.SelectLockForUpdate && e.Lock != ast.SelectLockForUpdateNoWait) { return nil } if req.NumRows() != 0 { @@ -793,18 +793,27 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { } return nil } - return doLockKeys(ctx, e.ctx, e.keys...) + return doLockKeys(ctx, e.ctx, e.Lock == ast.SelectLockForUpdateNoWait, e.keys...) } -func doLockKeys(ctx context.Context, se sessionctx.Context, keys ...kv.Key) error { +// doLockKeys is the main entry for pessimistic lock keys +// lockNoWait means the lock operation will report error immediately if target key is already +// locked by others. used for (select for update nowait) situation +func doLockKeys(ctx context.Context, se sessionctx.Context, lockNoWait bool, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. txn, err := se.Txn(true) if err != nil { return err } + // TODO this is a problem, maybe we need to update forUpdateTS every time to avoid such case + // begin; select for update key1(here ErrLocked or other errors(or max_execution_time like util), + // key1 lock not get and async rollback key1 is raised) + // select for update key1 again(this time lock succ(maybe lock released by others)) + // the async rollback operation rollbacked the lock just acquired from + se.GetSessionVars().TxnCtx.SetForUpdateTS(se.GetSessionVars().TxnCtx.GetForUpdateTS() + 1) forUpdateTS := se.GetSessionVars().TxnCtx.GetForUpdateTS() - return txn.LockKeys(ctx, forUpdateTS, keys...) + return txn.LockKeys(ctx, forUpdateTS, lockNoWait, keys...) } // LimitExec represents limit executor diff --git a/executor/point_get.go b/executor/point_get.go index 7101542db379b..ac23adcc9e04b 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -44,6 +44,7 @@ func (b *executorBuilder) buildPointGet(p *plannercore.PointGetPlan) Executor { handle: p.Handle, startTS: startTS, lock: p.Lock, + nowait: p.ForUpdateNoWait, } b.isSelectForUpdate = p.IsForUpdate e.base().initCap = 1 @@ -63,6 +64,7 @@ type PointGetExecutor struct { snapshot kv.Snapshot done bool lock bool + nowait bool } // Open implements the Executor interface. @@ -148,7 +150,7 @@ func (e *PointGetExecutor) Next(ctx context.Context, req *chunk.Chunk) error { func (e *PointGetExecutor) lockKeyIfNeeded(ctx context.Context, key []byte) error { if e.lock { - return doLockKeys(ctx, e.ctx, key) + return doLockKeys(ctx, e.ctx, e.nowait, key) } return nil } diff --git a/go.mod b/go.mod index d904b5bbac557..c032581495d58 100644 --- a/go.mod +++ b/go.mod @@ -79,3 +79,7 @@ require ( ) go 1.13 + +replace github.com/pingcap/parser => github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae + +replace github.com/pingcap/kvproto => github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90 diff --git a/go.sum b/go.sum index 95a0b13364936..80186c36525a9 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= +github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae h1:EaLRRp9CPpDZQ3PCe3PtLA1BqY5e9i48RHtBLgMW/cI= +github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae/go.mod h1:LoM8lSJ7POQOA8WIpI6Eti5BHzZtUJhu1csFCjGkQVs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -159,15 +161,10 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= -github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1 h1:DNvxkdcjA0TBIIIF+K2w9KMlTzMZzLZ5JVF26kTCPhg= -github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/parser v0.0.0-20191012071233-32876040fefb h1:okeNsbftvzQ8I9DseKukhZURRYJUHOpRSHwlSZC0g0g= -github.com/pingcap/parser v0.0.0-20191012071233-32876040fefb/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 h1:GIEq+wZfrl2bcJxpuSrEH4H7/nlf5YdmpS+dU9lNIt8= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0/go.mod h1:G/6rJpnYwM0LKMec2rI82/5Kg6GaZMvlfB+e6/tvYmI= github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible h1:MkWCxgZpJBgY2f4HtwWMMFzSBb3+JPzeJgF3VrXE/bU= @@ -244,6 +241,8 @@ github.com/urfave/negroni v0.3.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKn github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= +github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90 h1:rzQ+EdmLdge8CqTHGhmnEi1xSZ/ATaa7cPCGrOg7yWM= +github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/kv/kv.go b/kv/kv.go index 8413d86f684f9..9cc404c035be4 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -169,7 +169,7 @@ type Transaction interface { // String implements fmt.Stringer interface. String() string // LockKeys tries to lock the entries with the keys in KV store. - LockKeys(ctx context.Context, forUpdateTS uint64, keys ...Key) error + LockKeys(ctx context.Context, forUpdateTS uint64, lockNoWait bool, keys ...Key) error // SetOption sets an option with a value, when val is nil, uses the default // value of this option. SetOption(opt Option, val interface{}) diff --git a/kv/mock.go b/kv/mock.go index 70f5ce831d0d7..592152432e3b4 100644 --- a/kv/mock.go +++ b/kv/mock.go @@ -39,7 +39,7 @@ func (t *mockTxn) String() string { return "" } -func (t *mockTxn) LockKeys(_ context.Context, _ uint64, _ ...Key) error { +func (t *mockTxn) LockKeys(_ context.Context, _ uint64, _ bool, _ ...Key) error { return nil } diff --git a/kv/mock_test.go b/kv/mock_test.go index 0555feb38f018..b0d5bea0b399e 100644 --- a/kv/mock_test.go +++ b/kv/mock_test.go @@ -38,7 +38,7 @@ func (s testMockSuite) TestInterface(c *C) { transaction, err := storage.Begin() c.Check(err, IsNil) - err = transaction.LockKeys(context.Background(), 0, Key("lock")) + err = transaction.LockKeys(context.Background(), 0, false, Key("lock")) c.Check(err, IsNil) transaction.SetOption(Option(23), struct{}{}) if mock, ok := transaction.(*mockTxn); ok { diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 78fff77ec95e8..e4841e151714f 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -53,6 +53,7 @@ type PointGetPlan struct { Lock bool IsForUpdate bool outputNames []*types.FieldName + ForUpdateNoWait bool } type nameValuePair struct { @@ -240,7 +241,7 @@ func TryFastPlan(ctx sessionctx.Context, node ast.Node) Plan { tableDual.SetSchema(fp.Schema()) return tableDual.Init(ctx, &property.StatsInfo{}, 0) } - if x.LockTp == ast.SelectLockForUpdate { + if x.LockTp == ast.SelectLockForUpdate || x.LockTp == ast.SelectLockForUpdateNoWait { // Locking of rows for update using SELECT FOR UPDATE only applies when autocommit // is disabled (either by beginning transaction with START TRANSACTION or by setting // autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked. @@ -249,6 +250,7 @@ func TryFastPlan(ctx sessionctx.Context, node ast.Node) Plan { if !sessVars.IsAutocommit() || sessVars.InTxn() { fp.Lock = true fp.IsForUpdate = true + fp.ForUpdateNoWait = x.LockTp == ast.SelectLockForUpdateNoWait } } return fp diff --git a/planner/core/rule_column_pruning.go b/planner/core/rule_column_pruning.go index e2dba4cfff9d7..8bf270c054e19 100644 --- a/planner/core/rule_column_pruning.go +++ b/planner/core/rule_column_pruning.go @@ -354,7 +354,7 @@ func (la *LogicalApply) PruneColumns(parentUsedCols []*expression.Column) error // PruneColumns implements LogicalPlan interface. func (p *LogicalLock) PruneColumns(parentUsedCols []*expression.Column) error { - if p.Lock != ast.SelectLockForUpdate { + if p.Lock != ast.SelectLockForUpdate && p.Lock != ast.SelectLockForUpdateNoWait { return p.baseLogicalPlan.PruneColumns(parentUsedCols) } diff --git a/session/pessimistic_test.go b/session/pessimistic_test.go index 98abee8433e2d..b000b05159887 100644 --- a/session/pessimistic_test.go +++ b/session/pessimistic_test.go @@ -391,3 +391,89 @@ func (s *testPessimisticSuite) TestOptimisticConflicts(c *C) { tk.MustExec("commit") tk.MustQuery("select * from conflict").Check(testkit.Rows("1 3")) } + +func (s *testPessimisticSuite) TestSelectForUpdateNoWait(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk2 := testkit.NewTestKitWithInit(c, s.store) + tk3 := testkit.NewTestKitWithInit(c, s.store) + + tk.MustExec("drop table if exists tk") + tk.MustExec("create table tk (c1 int primary key, c2 int)") + tk.MustExec("insert into tk values(1,1),(2,2),(3,3),(4,4),(5,5)") + + tk.MustExec("set @@autocommit = 0") + tk2.MustExec("set @@autocommit = 0") + tk3.MustExec("set @@autocommit = 0") + + // point get with no autocommit + tk.MustExec("begin pessimistic") + tk.MustExec("select * from tk where c1 = 2 for update") // lock succ + + tk2.MustExec("begin pessimistic") + _, err := tk2.Exec("select * from tk where c1 = 2 for update nowait") + c.Check(err, NotNil) + tk.MustExec("commit") + tk2.MustExec("select * from tk where c1 = 2 for update nowait") // lock succ + + tk3.MustExec("begin pessimistic") + _, err = tk3.Exec("select * from tk where c1 = 2 for update nowait") + c.Check(err, NotNil) + + tk2.MustExec("commit") + tk3.MustExec("select * from tk where c1 = 2 for update") + tk3.MustExec("commit") + tk.MustExec("commit") + + tk3.MustExec("begin pessimistic") + tk3.MustExec("update tk set c2 = c2 + 1 where c1 = 3") + tk2.MustExec("begin pessimistic") + _, err = tk2.Exec("select * from tk where c1 = 3 for update nowait") + c.Check(err, NotNil) + tk3.MustExec("commit") + tk2.MustExec("select * from tk where c1 = 3 for update nowait") + tk2.MustExec("commit") + + tk.MustExec("commit") + tk2.MustExec("commit") + tk3.MustExec("commit") + + // scan with no autocommit + tk.MustExec("begin pessimistic") + tk.MustExec("select * from tk where c1 >= 2 for update") + tk2.MustExec("begin pessimistic") + _, err = tk2.Exec("select * from tk where c1 = 2 for update nowait") + c.Check(err, NotNil) + _, err = tk2.Exec("select * from tk where c1 > 3 for update nowait") + c.Check(err, NotNil) + tk2.MustExec("select * from tk where c1 = 1 for update nowait") + tk2.MustExec("commit") + tk.MustQuery("select * from tk where c1 >= 2 for update").Check(testkit.Rows("2 2", "3 4", "4 4", "5 5")) + tk.MustExec("commit") + tk.MustExec("begin pessimistic") + tk.MustExec("update tk set c2 = c2 + 10 where c1 > 3") + tk3.MustExec("begin pessimistic") + _, err = tk3.Exec("select * from tk where c1 = 5 for update nowait") + c.Check(err, NotNil) + tk3.MustExec("select * from tk where c1 = 1 for update nowait") + tk.MustExec("commit") + tk3.MustQuery("select * from tk where c1 > 3 for update nowait").Check(testkit.Rows("4 14", "5 15")) + tk3.MustExec("commit") + + //delete + tk3.MustExec("begin pessimistic") + tk3.MustExec("delete from tk where c1 <= 2") + tk.MustExec("begin pessimistic") + _, err = tk.Exec("select * from tk where c1 = 1 for update nowait") + c.Check(err, NotNil) + tk3.MustExec("commit") + tk.MustQuery("select * from tk where c1 > 1 for update nowait").Check(testkit.Rows("3 4", "4 14", "5 15")) + tk.MustExec("update tk set c2 = c2 + 1 where c1 = 5") + tk2.MustExec("begin pessimistic") + _, err = tk2.Exec("select * from tk where c1 = 5 for update nowait") + c.Check(err, NotNil) + tk.MustExec("commit") + tk2.MustQuery("select * from tk where c1 = 5 for update nowait").Check(testkit.Rows("5 16")) + tk2.MustExec("update tk set c2 = c2 + 1 where c1 = 5") + tk2.MustQuery("select * from tk where c1 = 5 for update nowait").Check(testkit.Rows("5 17")) + tk2.MustExec("commit") +} diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index be85563479903..b89797de3c0ef 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -254,7 +254,8 @@ type MVCCStore interface { Scan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair - PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, forUpdateTS uint64, ttl uint64) []error + PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, + forUpdateTS uint64, ttl uint64, lockNoWait bool) []error PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error Prewrite(req *kvrpcpb.PrewriteRequest) []error Commit(keys [][]byte, startTS, commitTS uint64) error diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index bd16163959620..995f4a0bfc5e6 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -464,7 +464,8 @@ func reverse(values []mvccValue) { } // PessimisticLock writes the pessimistic lock. -func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, forUpdateTS uint64, ttl uint64) []error { +func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, + forUpdateTS uint64, ttl uint64, lockNoWait bool) []error { mvcc.mu.Lock() defer mvcc.mu.Unlock() @@ -477,6 +478,11 @@ func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary if err != nil { anyError = true } + if lockNoWait { + if _, ok := err.(*ErrLocked); ok { + break + } + } } if anyError { return errs diff --git a/store/mockstore/mocktikv/rpc.go b/store/mockstore/mocktikv/rpc.go index 1361ffdd30d95..b80e0f5a18735 100644 --- a/store/mockstore/mocktikv/rpc.go +++ b/store/mockstore/mocktikv/rpc.go @@ -308,10 +308,12 @@ func (h *rpcHandler) handleKvPessimisticLock(req *kvrpcpb.PessimisticLockRequest startTS := req.StartVersion regionID := req.Context.RegionId h.cluster.handleDelay(startTS, regionID) - errs := h.mvccStore.PessimisticLock(req.Mutations, req.PrimaryLock, req.GetStartVersion(), req.GetForUpdateTs(), req.GetLockTtl()) - - // TODO: remove this when implement sever side wait. - h.simulateServerSideWaitLock(errs) + errs := h.mvccStore.PessimisticLock(req.Mutations, req.PrimaryLock, req.GetStartVersion(), req.GetForUpdateTs(), + req.GetLockTtl(), req.Nowait) + if !req.Nowait { + // TODO: remove this when implement sever side wait. + h.simulateServerSideWaitLock(errs) + } return &kvrpcpb.PessimisticLockResponse{ Errors: convertToKeyErrors(errs), } diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index c70f11521eca4..93bd7e8ee6aa2 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -112,6 +112,8 @@ type twoPhaseCommitter struct { regionTxnSize map[uint64]int // Used by pessimistic transaction and large transaction. ttlManager + // Used for select for update nowait + lockNoWait bool } // batchExecutor is txn controller providing rate control like utils @@ -674,6 +676,7 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc ForUpdateTs: c.forUpdateTS, LockTtl: c.pessimisticTTL, IsFirstLock: c.isFirstLock, + Nowait: c.lockNoWait, }, pb.Context{Priority: c.priority, SyncLog: c.syncLog}) for { resp, err := c.store.SendReq(bo, req, batch.region, readTimeoutShort) @@ -702,6 +705,13 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc } var locks []*Lock for _, keyErr := range keyErrs { + // Check lock conflict error for nowait, if nowait set and key locked by others + // report error immediately and do no resolve locks any more + if c.lockNoWait { + if keyErr.GetLocked() != nil { + return ErrLockFailNoWait + } + } // Check already exists error if alreadyExist := keyErr.GetAlreadyExist(); alreadyExist != nil { key := alreadyExist.GetKey() diff --git a/store/tikv/2pc_test.go b/store/tikv/2pc_test.go index a84a4c12a30f4..9ddc31d14f672 100644 --- a/store/tikv/2pc_test.go +++ b/store/tikv/2pc_test.go @@ -506,7 +506,7 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { c.Assert(txn.Set(key, key), IsNil) txn.DelOption(kv.PresumeKeyNotExistsError) txn.DelOption(kv.PresumeKeyNotExists) - err := txn.LockKeys(context.Background(), txn.startTS, key) + err := txn.LockKeys(context.Background(), txn.startTS, false, key) c.Assert(err, NotNil) c.Assert(txn.Delete(key), IsNil) key2 := kv.Key("key2") @@ -518,9 +518,9 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { func (s *testCommitterSuite) TestPessimisticLockedKeysDedup(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) - err := txn.LockKeys(context.Background(), 100, kv.Key("abc"), kv.Key("def")) + err := txn.LockKeys(context.Background(), 100, false, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 100, kv.Key("abc"), kv.Key("def")) + err = txn.LockKeys(context.Background(), 100, false, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) c.Assert(txn.lockKeys, HasLen, 2) } @@ -530,11 +530,11 @@ func (s *testCommitterSuite) TestPessimisticTTL(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) time.Sleep(time.Millisecond * 100) - err := txn.LockKeys(context.Background(), txn.startTS, key) + err := txn.LockKeys(context.Background(), txn.startTS, false, key) c.Assert(err, IsNil) time.Sleep(time.Millisecond * 100) key2 := kv.Key("key2") - err = txn.LockKeys(context.Background(), txn.startTS, key2) + err = txn.LockKeys(context.Background(), txn.startTS, false, key2) c.Assert(err, IsNil) lockInfo := s.getLockInfo(c, key) elapsedTTL := lockInfo.LockTtl - PessimisticLockTTL diff --git a/store/tikv/error.go b/store/tikv/error.go index 5e775218a9f5e..7484aa0e0e431 100644 --- a/store/tikv/error.go +++ b/store/tikv/error.go @@ -38,6 +38,7 @@ var ( ErrRegionUnavailable = terror.ClassTiKV.New(mysql.ErrRegionUnavailable, mysql.MySQLErrName[mysql.ErrRegionUnavailable]) ErrTiKVServerBusy = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]) ErrGCTooEarly = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly]) + ErrLockFailNoWait = terror.ClassTiKV.New(mysql.ErrLockAcquireFailAndNoWaitSet, mysql.MySQLErrName[mysql.ErrLockAcquireFailAndNoWaitSet]) ) // ErrDeadlock wraps *kvrpcpb.Deadlock to implement the error interface. diff --git a/store/tikv/ticlient_test.go b/store/tikv/ticlient_test.go index e771a9bd61315..fb902746e85a1 100644 --- a/store/tikv/ticlient_test.go +++ b/store/tikv/ticlient_test.go @@ -119,7 +119,7 @@ func (s *testTiclientSuite) TestSingleKey(c *C) { txn := s.beginTxn(c) err := txn.Set(encodeKey(s.prefix, "key"), []byte("value")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 0, encodeKey(s.prefix, "key")) + err = txn.LockKeys(context.Background(), 0, false, encodeKey(s.prefix, "key")) c.Assert(err, IsNil) err = txn.Commit(context.Background()) c.Assert(err, IsNil) diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 123d22aa0e7ee..2d2f2ecdf7a8e 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -380,7 +380,7 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { return txn.committer.pessimisticRollbackKeys(NewBackoffer(context.Background(), cleanupMaxBackoff), txn.lockKeys) } -func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, keysInput ...kv.Key) error { +func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, lockNoWait bool, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput)) txn.mu.Lock() @@ -424,6 +424,7 @@ func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, keysInput // If the number of keys greater than 1, it can be on different region, // concurrently execute on multiple regions may lead to deadlock. txn.committer.isFirstLock = len(txn.lockKeys) == 0 && len(keys) == 1 + txn.committer.lockNoWait = lockNoWait err := txn.committer.pessimisticLockKeys(bo, keys) if err != nil { for _, key := range keys { From 9e8d6cf3a0841677887eee2adb2edcbc0747e63f Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 17 Oct 2019 14:32:30 +0800 Subject: [PATCH 02/21] refactor, handle select for update error will update "updateTS" --- config/config.go | 6 ++++++ ddl/index.go | 3 ++- executor/adapter.go | 15 ++++++++++++++- executor/admin.go | 3 ++- executor/executor.go | 19 +++++++++---------- executor/point_get.go | 22 +++++++++++----------- go.mod | 4 +--- go.sum | 6 ++++-- kv/kv.go | 2 +- kv/mock.go | 2 +- kv/mock_test.go | 3 ++- planner/core/point_get_plan.go | 19 ++++++++++++------- sessionctx/context.go | 1 - store/mockstore/mocktikv/mvcc.go | 2 +- store/mockstore/mocktikv/mvcc_leveldb.go | 5 +++-- store/mockstore/mocktikv/rpc.go | 5 +++-- store/tikv/2pc.go | 11 ++++++----- store/tikv/2pc_test.go | 11 ++++++----- store/tikv/ticlient_test.go | 3 ++- store/tikv/txn.go | 5 +++-- 20 files changed, 89 insertions(+), 58 deletions(-) diff --git a/config/config.go b/config/config.go index 61803441bb9e9..42840f69551ad 100644 --- a/config/config.go +++ b/config/config.go @@ -663,3 +663,9 @@ const ( OOMActionCancel = "cancel" OOMActionLog = "log" ) + +// Used for pessimistic lock wait time +var ( + LockAlwaysWait = uint64(0) + LockNoWait = uint64(1) +) diff --git a/ddl/index.go b/ddl/index.go index f1e5e6fdc0c16..007618945162a 100644 --- a/ddl/index.go +++ b/ddl/index.go @@ -25,6 +25,7 @@ import ( "github.com/pingcap/parser/ast" "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" + "github.com/pingcap/tidb/config" ddlutil "github.com/pingcap/tidb/ddl/util" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/infoschema" @@ -869,7 +870,7 @@ func (w *addIndexWorker) backfillIndexInTxn(handleRange reorgIndexTask) (taskCtx // Lock the row key to notify us that someone delete or update the row, // then we should not backfill the index of it, otherwise the adding index is redundant. - err := txn.LockKeys(context.Background(), 0, false, idxRecord.key) + err := txn.LockKeys(context.Background(), 0, config.LockAlwaysWait, idxRecord.key) if err != nil { return errors.Trace(err) } diff --git a/executor/adapter.go b/executor/adapter.go index a945d6b0a39a6..65fcec4cbbf27 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -557,7 +557,7 @@ func (a *ExecStmt) handlePessimisticDML(ctx context.Context, e Executor) error { return nil } forUpdateTS := txnCtx.GetForUpdateTS() - err = txn.LockKeys(ctx, forUpdateTS, false, keys...) + err = txn.LockKeys(ctx, forUpdateTS, config.LockAlwaysWait, keys...) if err == nil { return nil } @@ -595,6 +595,19 @@ func (a *ExecStmt) handlePessimisticLockError(ctx context.Context, err error) (E if conflictCommitTS > forUpdateTS { newForUpdateTS = conflictCommitTS } + } else if terror.ErrorEqual(err, tikv.ErrLockFailNoWait) { + // for nowait, when ErrLock happened, ErrLockFailNoWait will be returned, and in the same txn + // the select for updateTs must be updated, otherwise there maybe rollback problem. + // begin; select for update key1(here ErrLocked or other errors(or max_execution_time like util), + // key1 lock not get and async rollback key1 is raised) + // select for update key1 again(this time lock succ(maybe lock released by others)) + // the async rollback operation rollbacked the lock just acquired + newForUpdateTS, tsErr := a.Ctx.GetStore().GetOracle().GetTimestamp(ctx) + if tsErr != nil { + return nil, tsErr + } + txnCtx.SetForUpdateTS(newForUpdateTS) + return nil, err } else { return nil, err } diff --git a/executor/admin.go b/executor/admin.go index 1b4bc3f28c0fc..6933359b164c4 100644 --- a/executor/admin.go +++ b/executor/admin.go @@ -20,6 +20,7 @@ import ( "github.com/pingcap/parser/ast" "github.com/pingcap/parser/model" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/kv" @@ -432,7 +433,7 @@ func (e *RecoverIndexExec) backfillIndexInTxn(ctx context.Context, txn kv.Transa } recordKey := e.table.RecordKey(row.handle) - err := txn.LockKeys(ctx, 0, false, recordKey) + err := txn.LockKeys(ctx, 0, config.LockAlwaysWait, recordKey) if err != nil { return result, err } diff --git a/executor/executor.go b/executor/executor.go index 969ea18264a09..a048f1fcdb909 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -793,27 +793,26 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { } return nil } - return doLockKeys(ctx, e.ctx, e.Lock == ast.SelectLockForUpdateNoWait, e.keys...) + var lockWaitTime = config.LockAlwaysWait + if e.Lock == ast.SelectLockForUpdateNoWait { + lockWaitTime = config.LockNoWait + } + return doLockKeys(ctx, e.ctx, lockWaitTime, e.keys...) } // doLockKeys is the main entry for pessimistic lock keys -// lockNoWait means the lock operation will report error immediately if target key is already +// waitTime means the lock operation will wait in seconds if target key is already // locked by others. used for (select for update nowait) situation -func doLockKeys(ctx context.Context, se sessionctx.Context, lockNoWait bool, keys ...kv.Key) error { +// 0 means nowait +func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime uint64, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. txn, err := se.Txn(true) if err != nil { return err } - // TODO this is a problem, maybe we need to update forUpdateTS every time to avoid such case - // begin; select for update key1(here ErrLocked or other errors(or max_execution_time like util), - // key1 lock not get and async rollback key1 is raised) - // select for update key1 again(this time lock succ(maybe lock released by others)) - // the async rollback operation rollbacked the lock just acquired from - se.GetSessionVars().TxnCtx.SetForUpdateTS(se.GetSessionVars().TxnCtx.GetForUpdateTS() + 1) forUpdateTS := se.GetSessionVars().TxnCtx.GetForUpdateTS() - return txn.LockKeys(ctx, forUpdateTS, lockNoWait, keys...) + return txn.LockKeys(ctx, forUpdateTS, waitTime, keys...) } // LimitExec represents limit executor diff --git a/executor/point_get.go b/executor/point_get.go index ac23adcc9e04b..1b2cb70a8d709 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -44,7 +44,7 @@ func (b *executorBuilder) buildPointGet(p *plannercore.PointGetPlan) Executor { handle: p.Handle, startTS: startTS, lock: p.Lock, - nowait: p.ForUpdateNoWait, + lockWaitTime: p.LockWaitTime, } b.isSelectForUpdate = p.IsForUpdate e.base().initCap = 1 @@ -56,15 +56,15 @@ func (b *executorBuilder) buildPointGet(p *plannercore.PointGetPlan) Executor { type PointGetExecutor struct { baseExecutor - tblInfo *model.TableInfo - handle int64 - idxInfo *model.IndexInfo - idxVals []types.Datum - startTS uint64 - snapshot kv.Snapshot - done bool - lock bool - nowait bool + tblInfo *model.TableInfo + handle int64 + idxInfo *model.IndexInfo + idxVals []types.Datum + startTS uint64 + snapshot kv.Snapshot + done bool + lock bool + lockWaitTime uint64 } // Open implements the Executor interface. @@ -150,7 +150,7 @@ func (e *PointGetExecutor) Next(ctx context.Context, req *chunk.Chunk) error { func (e *PointGetExecutor) lockKeyIfNeeded(ctx context.Context, key []byte) error { if e.lock { - return doLockKeys(ctx, e.ctx, e.nowait, key) + return doLockKeys(ctx, e.ctx, e.lockWaitTime, key) } return nil } diff --git a/go.mod b/go.mod index c032581495d58..6d4a522b4df75 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/pingcap/errors v0.11.4 github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e - github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1 + github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2 github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 github.com/pingcap/parser v0.0.0-20191012071233-32876040fefb github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 @@ -81,5 +81,3 @@ require ( go 1.13 replace github.com/pingcap/parser => github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae - -replace github.com/pingcap/kvproto => github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90 diff --git a/go.sum b/go.sum index 80186c36525a9..f627ac20a2bf9 100644 --- a/go.sum +++ b/go.sum @@ -161,6 +161,10 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= +github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6GlvnmvkHNC1OrS/ETvXxbJkJ1Nrk4prtWo= +github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2 h1:bnzF93rtu6MQ/pVwRx28V2VfMiCG1fDq8f9TmdPFjKw= +github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= @@ -241,8 +245,6 @@ github.com/urfave/negroni v0.3.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKn github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= -github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90 h1:rzQ+EdmLdge8CqTHGhmnEi1xSZ/ATaa7cPCGrOg7yWM= -github.com/youjiali1995/kvproto v0.0.0-20191016061501-6883cfe78a90/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/kv/kv.go b/kv/kv.go index 9cc404c035be4..5aa3a9c923be8 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -169,7 +169,7 @@ type Transaction interface { // String implements fmt.Stringer interface. String() string // LockKeys tries to lock the entries with the keys in KV store. - LockKeys(ctx context.Context, forUpdateTS uint64, lockNoWait bool, keys ...Key) error + LockKeys(ctx context.Context, forUpdateTS uint64, lockWaitTime uint64, keys ...Key) error // SetOption sets an option with a value, when val is nil, uses the default // value of this option. SetOption(opt Option, val interface{}) diff --git a/kv/mock.go b/kv/mock.go index 592152432e3b4..e76a4be058921 100644 --- a/kv/mock.go +++ b/kv/mock.go @@ -39,7 +39,7 @@ func (t *mockTxn) String() string { return "" } -func (t *mockTxn) LockKeys(_ context.Context, _ uint64, _ bool, _ ...Key) error { +func (t *mockTxn) LockKeys(_ context.Context, _ uint64, _ uint64, _ ...Key) error { return nil } diff --git a/kv/mock_test.go b/kv/mock_test.go index b0d5bea0b399e..fd1a8dc88aa3f 100644 --- a/kv/mock_test.go +++ b/kv/mock_test.go @@ -17,6 +17,7 @@ import ( "context" . "github.com/pingcap/check" + "github.com/pingcap/tidb/config" ) var _ = Suite(testMockSuite{}) @@ -38,7 +39,7 @@ func (s testMockSuite) TestInterface(c *C) { transaction, err := storage.Begin() c.Check(err, IsNil) - err = transaction.LockKeys(context.Background(), 0, false, Key("lock")) + err = transaction.LockKeys(context.Background(), 0, config.LockAlwaysWait, Key("lock")) c.Check(err, IsNil) transaction.SetOption(Option(23), struct{}{}) if mock, ok := transaction.(*mockTxn); ok { diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index e4841e151714f..1b3daab995c02 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -23,6 +23,7 @@ import ( "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/opcode" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/planner/property" "github.com/pingcap/tidb/privilege" @@ -53,7 +54,7 @@ type PointGetPlan struct { Lock bool IsForUpdate bool outputNames []*types.FieldName - ForUpdateNoWait bool + LockWaitTime uint64 } type nameValuePair struct { @@ -250,7 +251,10 @@ func TryFastPlan(ctx sessionctx.Context, node ast.Node) Plan { if !sessVars.IsAutocommit() || sessVars.InTxn() { fp.Lock = true fp.IsForUpdate = true - fp.ForUpdateNoWait = x.LockTp == ast.SelectLockForUpdateNoWait + fp.LockWaitTime = config.LockAlwaysWait + if x.LockTp == ast.SelectLockForUpdateNoWait { + fp.LockWaitTime = config.LockNoWait + } } } return fp @@ -601,11 +605,12 @@ func tryPointGetPlan(ctx sessionctx.Context, selStmt *ast.SelectStmt) *PointGetP func newPointGetPlan(ctx sessionctx.Context, dbName string, schema *expression.Schema, tbl *model.TableInfo, names []*types.FieldName) *PointGetPlan { p := &PointGetPlan{ - basePlan: newBasePlan(ctx, "Point_Get", 0), - dbName: dbName, - schema: schema, - TblInfo: tbl, - outputNames: names, + basePlan: newBasePlan(ctx, "Point_Get", 0), + dbName: dbName, + schema: schema, + TblInfo: tbl, + outputNames: names, + LockWaitTime: config.LockAlwaysWait, } ctx.GetSessionVars().StmtCtx.Tables = []stmtctx.TableEntry{{DB: ctx.GetSessionVars().CurrentDB, Table: tbl.Name.L}} return p diff --git a/sessionctx/context.go b/sessionctx/context.go index 6c0b7e100aebe..f951eaa1bdf8a 100644 --- a/sessionctx/context.go +++ b/sessionctx/context.go @@ -16,7 +16,6 @@ package sessionctx import ( "context" "fmt" - "github.com/pingcap/parser/model" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/owner" diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index b89797de3c0ef..f7669a494177d 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -255,7 +255,7 @@ type MVCCStore interface { ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockNoWait bool) []error + forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error Prewrite(req *kvrpcpb.PrewriteRequest) []error Commit(keys [][]byte, startTS, commitTS uint64) error diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index 995f4a0bfc5e6..a8f4c977207fc 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -15,6 +15,7 @@ package mocktikv import ( "bytes" + "github.com/pingcap/tidb/config" "math" "sync" @@ -465,7 +466,7 @@ func reverse(values []mvccValue) { // PessimisticLock writes the pessimistic lock. func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockNoWait bool) []error { + forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error { mvcc.mu.Lock() defer mvcc.mu.Unlock() @@ -478,7 +479,7 @@ func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary if err != nil { anyError = true } - if lockNoWait { + if lockWaitTime == config.LockNoWait { if _, ok := err.(*ErrLocked); ok { break } diff --git a/store/mockstore/mocktikv/rpc.go b/store/mockstore/mocktikv/rpc.go index b80e0f5a18735..e7f8af6a86851 100644 --- a/store/mockstore/mocktikv/rpc.go +++ b/store/mockstore/mocktikv/rpc.go @@ -17,6 +17,7 @@ import ( "bytes" "context" "fmt" + "github.com/pingcap/tidb/config" "io" "math" "strconv" @@ -309,8 +310,8 @@ func (h *rpcHandler) handleKvPessimisticLock(req *kvrpcpb.PessimisticLockRequest regionID := req.Context.RegionId h.cluster.handleDelay(startTS, regionID) errs := h.mvccStore.PessimisticLock(req.Mutations, req.PrimaryLock, req.GetStartVersion(), req.GetForUpdateTs(), - req.GetLockTtl(), req.Nowait) - if !req.Nowait { + req.GetLockTtl(), req.WaitTimeout) + if req.WaitTimeout == config.LockAlwaysWait { // TODO: remove this when implement sever side wait. h.simulateServerSideWaitLock(errs) } diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 93bd7e8ee6aa2..b73ffb52154b9 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -16,6 +16,7 @@ package tikv import ( "bytes" "context" + "github.com/pingcap/tidb/config" "math" "sync" "sync/atomic" @@ -112,8 +113,8 @@ type twoPhaseCommitter struct { regionTxnSize map[uint64]int // Used by pessimistic transaction and large transaction. ttlManager - // Used for select for update nowait - lockNoWait bool + // Used for select for update in ms, 0 means always wait, 1 means nowait + lockWaitTime uint64 } // batchExecutor is txn controller providing rate control like utils @@ -676,7 +677,7 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc ForUpdateTs: c.forUpdateTS, LockTtl: c.pessimisticTTL, IsFirstLock: c.isFirstLock, - Nowait: c.lockNoWait, + WaitTimeout: c.lockWaitTime, }, pb.Context{Priority: c.priority, SyncLog: c.syncLog}) for { resp, err := c.store.SendReq(bo, req, batch.region, readTimeoutShort) @@ -706,8 +707,8 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc var locks []*Lock for _, keyErr := range keyErrs { // Check lock conflict error for nowait, if nowait set and key locked by others - // report error immediately and do no resolve locks any more - if c.lockNoWait { + // report error immediately and do no more resolve locks + if c.lockWaitTime == config.LockNoWait { if keyErr.GetLocked() != nil { return ErrLockFailNoWait } diff --git a/store/tikv/2pc_test.go b/store/tikv/2pc_test.go index 9ddc31d14f672..663b96f569e82 100644 --- a/store/tikv/2pc_test.go +++ b/store/tikv/2pc_test.go @@ -23,6 +23,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/errors" "github.com/pingcap/kvproto/pkg/kvrpcpb" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/mockstore/mocktikv" "github.com/pingcap/tidb/store/tikv/oracle" @@ -506,7 +507,7 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { c.Assert(txn.Set(key, key), IsNil) txn.DelOption(kv.PresumeKeyNotExistsError) txn.DelOption(kv.PresumeKeyNotExists) - err := txn.LockKeys(context.Background(), txn.startTS, false, key) + err := txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key) c.Assert(err, NotNil) c.Assert(txn.Delete(key), IsNil) key2 := kv.Key("key2") @@ -518,9 +519,9 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { func (s *testCommitterSuite) TestPessimisticLockedKeysDedup(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) - err := txn.LockKeys(context.Background(), 100, false, kv.Key("abc"), kv.Key("def")) + err := txn.LockKeys(context.Background(), 100, config.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 100, false, kv.Key("abc"), kv.Key("def")) + err = txn.LockKeys(context.Background(), 100, config.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) c.Assert(txn.lockKeys, HasLen, 2) } @@ -530,11 +531,11 @@ func (s *testCommitterSuite) TestPessimisticTTL(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) time.Sleep(time.Millisecond * 100) - err := txn.LockKeys(context.Background(), txn.startTS, false, key) + err := txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key) c.Assert(err, IsNil) time.Sleep(time.Millisecond * 100) key2 := kv.Key("key2") - err = txn.LockKeys(context.Background(), txn.startTS, false, key2) + err = txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key2) c.Assert(err, IsNil) lockInfo := s.getLockInfo(c, key) elapsedTTL := lockInfo.LockTtl - PessimisticLockTTL diff --git a/store/tikv/ticlient_test.go b/store/tikv/ticlient_test.go index fb902746e85a1..c36ff0f4142f5 100644 --- a/store/tikv/ticlient_test.go +++ b/store/tikv/ticlient_test.go @@ -22,6 +22,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/errors" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/mockstore/mocktikv" "github.com/pingcap/tidb/util/codec" @@ -119,7 +120,7 @@ func (s *testTiclientSuite) TestSingleKey(c *C) { txn := s.beginTxn(c) err := txn.Set(encodeKey(s.prefix, "key"), []byte("value")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 0, false, encodeKey(s.prefix, "key")) + err = txn.LockKeys(context.Background(), 0, config.LockAlwaysWait, encodeKey(s.prefix, "key")) c.Assert(err, IsNil) err = txn.Commit(context.Background()) c.Assert(err, IsNil) diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 2d2f2ecdf7a8e..52a837cdc4af4 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -380,7 +380,8 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { return txn.committer.pessimisticRollbackKeys(NewBackoffer(context.Background(), cleanupMaxBackoff), txn.lockKeys) } -func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, lockNoWait bool, keysInput ...kv.Key) error { +// lockWaitTime in ms, except that 0 means always wait lock, 1 means nowait lock +func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, lockWaitTime uint64, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput)) txn.mu.Lock() @@ -424,7 +425,7 @@ func (txn *tikvTxn) LockKeys(ctx context.Context, forUpdateTS uint64, lockNoWait // If the number of keys greater than 1, it can be on different region, // concurrently execute on multiple regions may lead to deadlock. txn.committer.isFirstLock = len(txn.lockKeys) == 0 && len(keys) == 1 - txn.committer.lockNoWait = lockNoWait + txn.committer.lockWaitTime = lockWaitTime err := txn.committer.pessimisticLockKeys(bo, keys) if err != nil { for _, key := range keys { From 70dc1eb41e54fcc26fe379560b8a71c988ccd19c Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 17 Oct 2019 20:24:52 +0800 Subject: [PATCH 03/21] move const1 --- config/config.go | 6 ------ ddl/index.go | 3 +-- executor/adapter.go | 2 +- executor/admin.go | 3 +-- executor/executor.go | 4 ++-- kv/kv.go | 6 ++++++ kv/mock_test.go | 3 +-- planner/core/point_get_plan.go | 8 ++++---- sessionctx/context.go | 1 + store/mockstore/mocktikv/mvcc_leveldb.go | 4 ++-- store/mockstore/mocktikv/rpc.go | 3 +-- store/tikv/2pc.go | 3 +-- store/tikv/2pc_test.go | 11 +++++------ store/tikv/ticlient_test.go | 3 +-- 14 files changed, 27 insertions(+), 33 deletions(-) diff --git a/config/config.go b/config/config.go index 42840f69551ad..61803441bb9e9 100644 --- a/config/config.go +++ b/config/config.go @@ -663,9 +663,3 @@ const ( OOMActionCancel = "cancel" OOMActionLog = "log" ) - -// Used for pessimistic lock wait time -var ( - LockAlwaysWait = uint64(0) - LockNoWait = uint64(1) -) diff --git a/ddl/index.go b/ddl/index.go index 007618945162a..c7d0be5d77acc 100644 --- a/ddl/index.go +++ b/ddl/index.go @@ -25,7 +25,6 @@ import ( "github.com/pingcap/parser/ast" "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" - "github.com/pingcap/tidb/config" ddlutil "github.com/pingcap/tidb/ddl/util" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/infoschema" @@ -870,7 +869,7 @@ func (w *addIndexWorker) backfillIndexInTxn(handleRange reorgIndexTask) (taskCtx // Lock the row key to notify us that someone delete or update the row, // then we should not backfill the index of it, otherwise the adding index is redundant. - err := txn.LockKeys(context.Background(), 0, config.LockAlwaysWait, idxRecord.key) + err := txn.LockKeys(context.Background(), 0, kv.LockAlwaysWait, idxRecord.key) if err != nil { return errors.Trace(err) } diff --git a/executor/adapter.go b/executor/adapter.go index 65fcec4cbbf27..b942fe003b5ea 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -557,7 +557,7 @@ func (a *ExecStmt) handlePessimisticDML(ctx context.Context, e Executor) error { return nil } forUpdateTS := txnCtx.GetForUpdateTS() - err = txn.LockKeys(ctx, forUpdateTS, config.LockAlwaysWait, keys...) + err = txn.LockKeys(ctx, forUpdateTS, kv.LockAlwaysWait, keys...) if err == nil { return nil } diff --git a/executor/admin.go b/executor/admin.go index 6933359b164c4..16074a154cc71 100644 --- a/executor/admin.go +++ b/executor/admin.go @@ -20,7 +20,6 @@ import ( "github.com/pingcap/parser/ast" "github.com/pingcap/parser/model" "github.com/pingcap/parser/terror" - "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/distsql" "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/kv" @@ -433,7 +432,7 @@ func (e *RecoverIndexExec) backfillIndexInTxn(ctx context.Context, txn kv.Transa } recordKey := e.table.RecordKey(row.handle) - err := txn.LockKeys(ctx, 0, config.LockAlwaysWait, recordKey) + err := txn.LockKeys(ctx, 0, kv.LockAlwaysWait, recordKey) if err != nil { return result, err } diff --git a/executor/executor.go b/executor/executor.go index a048f1fcdb909..fe88365eb848c 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -793,9 +793,9 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { } return nil } - var lockWaitTime = config.LockAlwaysWait + var lockWaitTime = kv.LockAlwaysWait if e.Lock == ast.SelectLockForUpdateNoWait { - lockWaitTime = config.LockNoWait + lockWaitTime = kv.LockNoWait } return doLockKeys(ctx, e.ctx, lockWaitTime, e.keys...) } diff --git a/kv/kv.go b/kv/kv.go index 5aa3a9c923be8..a74f5a6e8f5b8 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -364,3 +364,9 @@ type SplitableStore interface { WaitScatterRegionFinish(regionID uint64, backOff int) error CheckRegionInScattering(regionID uint64) (bool, error) } + +// Used for pessimistic lock wait time +var ( + LockAlwaysWait = uint64(0) + LockNoWait = uint64(1) +) diff --git a/kv/mock_test.go b/kv/mock_test.go index fd1a8dc88aa3f..e32ca84359675 100644 --- a/kv/mock_test.go +++ b/kv/mock_test.go @@ -17,7 +17,6 @@ import ( "context" . "github.com/pingcap/check" - "github.com/pingcap/tidb/config" ) var _ = Suite(testMockSuite{}) @@ -39,7 +38,7 @@ func (s testMockSuite) TestInterface(c *C) { transaction, err := storage.Begin() c.Check(err, IsNil) - err = transaction.LockKeys(context.Background(), 0, config.LockAlwaysWait, Key("lock")) + err = transaction.LockKeys(context.Background(), 0, LockAlwaysWait, Key("lock")) c.Check(err, IsNil) transaction.SetOption(Option(23), struct{}{}) if mock, ok := transaction.(*mockTxn); ok { diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 1b3daab995c02..4659099578602 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -23,8 +23,8 @@ import ( "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/opcode" "github.com/pingcap/parser/terror" - "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/expression" + "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/planner/property" "github.com/pingcap/tidb/privilege" "github.com/pingcap/tidb/sessionctx" @@ -251,9 +251,9 @@ func TryFastPlan(ctx sessionctx.Context, node ast.Node) Plan { if !sessVars.IsAutocommit() || sessVars.InTxn() { fp.Lock = true fp.IsForUpdate = true - fp.LockWaitTime = config.LockAlwaysWait + fp.LockWaitTime = kv.LockAlwaysWait if x.LockTp == ast.SelectLockForUpdateNoWait { - fp.LockWaitTime = config.LockNoWait + fp.LockWaitTime = kv.LockNoWait } } } @@ -610,7 +610,7 @@ func newPointGetPlan(ctx sessionctx.Context, dbName string, schema *expression.S schema: schema, TblInfo: tbl, outputNames: names, - LockWaitTime: config.LockAlwaysWait, + LockWaitTime: kv.LockAlwaysWait, } ctx.GetSessionVars().StmtCtx.Tables = []stmtctx.TableEntry{{DB: ctx.GetSessionVars().CurrentDB, Table: tbl.Name.L}} return p diff --git a/sessionctx/context.go b/sessionctx/context.go index f951eaa1bdf8a..6c0b7e100aebe 100644 --- a/sessionctx/context.go +++ b/sessionctx/context.go @@ -16,6 +16,7 @@ package sessionctx import ( "context" "fmt" + "github.com/pingcap/parser/model" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/owner" diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index a8f4c977207fc..ac458bacfe73a 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -15,7 +15,6 @@ package mocktikv import ( "bytes" - "github.com/pingcap/tidb/config" "math" "sync" @@ -28,6 +27,7 @@ import ( "github.com/pingcap/goleveldb/leveldb/util" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/tikv/oracle" "github.com/pingcap/tidb/util/codec" "github.com/pingcap/tidb/util/deadlock" @@ -479,7 +479,7 @@ func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary if err != nil { anyError = true } - if lockWaitTime == config.LockNoWait { + if lockWaitTime == kv.LockNoWait { if _, ok := err.(*ErrLocked); ok { break } diff --git a/store/mockstore/mocktikv/rpc.go b/store/mockstore/mocktikv/rpc.go index e7f8af6a86851..a4fdd62c4dc52 100644 --- a/store/mockstore/mocktikv/rpc.go +++ b/store/mockstore/mocktikv/rpc.go @@ -17,7 +17,6 @@ import ( "bytes" "context" "fmt" - "github.com/pingcap/tidb/config" "io" "math" "strconv" @@ -311,7 +310,7 @@ func (h *rpcHandler) handleKvPessimisticLock(req *kvrpcpb.PessimisticLockRequest h.cluster.handleDelay(startTS, regionID) errs := h.mvccStore.PessimisticLock(req.Mutations, req.PrimaryLock, req.GetStartVersion(), req.GetForUpdateTs(), req.GetLockTtl(), req.WaitTimeout) - if req.WaitTimeout == config.LockAlwaysWait { + if req.WaitTimeout == kv.LockAlwaysWait { // TODO: remove this when implement sever side wait. h.simulateServerSideWaitLock(errs) } diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index b73ffb52154b9..a6340f0e562cf 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -16,7 +16,6 @@ package tikv import ( "bytes" "context" - "github.com/pingcap/tidb/config" "math" "sync" "sync/atomic" @@ -708,7 +707,7 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc for _, keyErr := range keyErrs { // Check lock conflict error for nowait, if nowait set and key locked by others // report error immediately and do no more resolve locks - if c.lockWaitTime == config.LockNoWait { + if c.lockWaitTime == kv.LockNoWait { if keyErr.GetLocked() != nil { return ErrLockFailNoWait } diff --git a/store/tikv/2pc_test.go b/store/tikv/2pc_test.go index 663b96f569e82..bf2b2b7b3ca0e 100644 --- a/store/tikv/2pc_test.go +++ b/store/tikv/2pc_test.go @@ -23,7 +23,6 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/errors" "github.com/pingcap/kvproto/pkg/kvrpcpb" - "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/mockstore/mocktikv" "github.com/pingcap/tidb/store/tikv/oracle" @@ -507,7 +506,7 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { c.Assert(txn.Set(key, key), IsNil) txn.DelOption(kv.PresumeKeyNotExistsError) txn.DelOption(kv.PresumeKeyNotExists) - err := txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key) + err := txn.LockKeys(context.Background(), txn.startTS, kv.LockAlwaysWait, key) c.Assert(err, NotNil) c.Assert(txn.Delete(key), IsNil) key2 := kv.Key("key2") @@ -519,9 +518,9 @@ func (s *testCommitterSuite) TestUnsetPrimaryKey(c *C) { func (s *testCommitterSuite) TestPessimisticLockedKeysDedup(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) - err := txn.LockKeys(context.Background(), 100, config.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) + err := txn.LockKeys(context.Background(), 100, kv.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 100, config.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) + err = txn.LockKeys(context.Background(), 100, kv.LockAlwaysWait, kv.Key("abc"), kv.Key("def")) c.Assert(err, IsNil) c.Assert(txn.lockKeys, HasLen, 2) } @@ -531,11 +530,11 @@ func (s *testCommitterSuite) TestPessimisticTTL(c *C) { txn := s.begin(c) txn.SetOption(kv.Pessimistic, true) time.Sleep(time.Millisecond * 100) - err := txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key) + err := txn.LockKeys(context.Background(), txn.startTS, kv.LockAlwaysWait, key) c.Assert(err, IsNil) time.Sleep(time.Millisecond * 100) key2 := kv.Key("key2") - err = txn.LockKeys(context.Background(), txn.startTS, config.LockAlwaysWait, key2) + err = txn.LockKeys(context.Background(), txn.startTS, kv.LockAlwaysWait, key2) c.Assert(err, IsNil) lockInfo := s.getLockInfo(c, key) elapsedTTL := lockInfo.LockTtl - PessimisticLockTTL diff --git a/store/tikv/ticlient_test.go b/store/tikv/ticlient_test.go index c36ff0f4142f5..cb6c66e66e0d7 100644 --- a/store/tikv/ticlient_test.go +++ b/store/tikv/ticlient_test.go @@ -22,7 +22,6 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/errors" - "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/store/mockstore/mocktikv" "github.com/pingcap/tidb/util/codec" @@ -120,7 +119,7 @@ func (s *testTiclientSuite) TestSingleKey(c *C) { txn := s.beginTxn(c) err := txn.Set(encodeKey(s.prefix, "key"), []byte("value")) c.Assert(err, IsNil) - err = txn.LockKeys(context.Background(), 0, config.LockAlwaysWait, encodeKey(s.prefix, "key")) + err = txn.LockKeys(context.Background(), 0, kv.LockAlwaysWait, encodeKey(s.prefix, "key")) c.Assert(err, IsNil) err = txn.Commit(context.Background()) c.Assert(err, IsNil) From d2bc394725e07b2bf96580b4b891e5e77fe32f62 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 17 Oct 2019 21:43:22 +0800 Subject: [PATCH 04/21] add LockType in LockInfo --- go.mod | 2 ++ go.sum | 6 ++---- kv/kv.go | 6 ++++++ store/mockstore/mocktikv/errors.go | 14 ++++++++------ store/mockstore/mocktikv/mvcc.go | 14 +++++++++----- store/mockstore/mocktikv/mvcc_leveldb.go | 14 ++++++++------ store/mockstore/mocktikv/rpc.go | 1 + store/tikv/2pc.go | 10 ++++++++-- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 6d4a522b4df75..82882a917e39d 100644 --- a/go.mod +++ b/go.mod @@ -81,3 +81,5 @@ require ( go 1.13 replace github.com/pingcap/parser => github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae + +replace github.com/pingcap/kvproto => github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca diff --git a/go.sum b/go.sum index f627ac20a2bf9..b8645d9c662af 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= +github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca h1:aYOkiPp+idsKBGAWiNyZNl8K7PsdVRQSH5+7+hYHCYY= +github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae h1:EaLRRp9CPpDZQ3PCe3PtLA1BqY5e9i48RHtBLgMW/cI= github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae/go.mod h1:LoM8lSJ7POQOA8WIpI6Eti5BHzZtUJhu1csFCjGkQVs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -161,10 +163,6 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= -github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6GlvnmvkHNC1OrS/ETvXxbJkJ1Nrk4prtWo= -github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2 h1:bnzF93rtu6MQ/pVwRx28V2VfMiCG1fDq8f9TmdPFjKw= -github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= diff --git a/kv/kv.go b/kv/kv.go index a74f5a6e8f5b8..a871abe7b547e 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -370,3 +370,9 @@ var ( LockAlwaysWait = uint64(0) LockNoWait = uint64(1) ) + +// Used to distinguish pessmistic Lock or common lock +const ( + TypeLock uint32 = iota + TypePessmisticLock +) diff --git a/store/mockstore/mocktikv/errors.go b/store/mockstore/mocktikv/errors.go index 32dce279ee52d..88e337c56d920 100644 --- a/store/mockstore/mocktikv/errors.go +++ b/store/mockstore/mocktikv/errors.go @@ -18,16 +18,18 @@ import "fmt" // ErrLocked is returned when trying to Read/Write on a locked key. Client should // backoff or cleanup the lock then retry. type ErrLocked struct { - Key MvccKey - Primary []byte - StartTS uint64 - TTL uint64 - TxnSize uint64 + Key MvccKey + Primary []byte + StartTS uint64 + TTL uint64 + TxnSize uint64 + LockType uint32 } // Error formats the lock to a string. func (e *ErrLocked) Error() string { - return fmt.Sprintf("key is locked, key: %q, primary: %q, txnStartTS: %v", e.Key, e.Primary, e.StartTS) + return fmt.Sprintf("key is locked, key: %q, primary: %q, txnStartTS: %v, LockType: %v", + e.Key, e.Primary, e.StartTS, e.LockType) } // ErrKeyAlreadyExist is returned when key exists but this key has a constraint that diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index f7669a494177d..59bd01620c526 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -49,6 +49,7 @@ type mvccLock struct { forUpdateTS uint64 txnSize uint64 minCommitTS uint64 + lockType uint32 } type mvccEntry struct { @@ -71,6 +72,7 @@ func (l *mvccLock) MarshalBinary() ([]byte, error) { mh.WriteNumber(&buf, l.forUpdateTS) mh.WriteNumber(&buf, l.txnSize) mh.WriteNumber(&buf, l.minCommitTS) + mh.WriteNumber(&buf, l.lockType) return buf.Bytes(), errors.Trace(mh.err) } @@ -86,6 +88,7 @@ func (l *mvccLock) UnmarshalBinary(data []byte) error { mh.ReadNumber(buf, &l.forUpdateTS) mh.ReadNumber(buf, &l.txnSize) mh.ReadNumber(buf, &l.minCommitTS) + mh.ReadNumber(buf, &l.lockType) return errors.Trace(mh.err) } @@ -198,11 +201,12 @@ func newEntry(key MvccKey) *mvccEntry { // Note that parameter key is raw key, while key in ErrLocked is mvcc key. func (l *mvccLock) lockErr(key []byte) error { return &ErrLocked{ - Key: mvccEncode(key, lockVer), - Primary: l.primary, - StartTS: l.startTS, - TTL: l.ttl, - TxnSize: l.txnSize, + Key: mvccEncode(key, lockVer), + Primary: l.primary, + StartTS: l.startTS, + TTL: l.ttl, + TxnSize: l.txnSize, + LockType: l.lockType, } } diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index ac458bacfe73a..501fbb5fbff29 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -533,6 +533,7 @@ func (mvcc *MVCCLevelDB) pessimisticLockMutation(batch *leveldb.Batch, mutation op: kvrpcpb.Op_PessimisticLock, ttl: ttl, forUpdateTS: forUpdateTS, + lockType: kv.TypePessmisticLock, } writeKey := mvccEncode(mutation.Key, lockVer) writeValue, err := lock.MarshalBinary() @@ -734,12 +735,13 @@ func prewriteMutation(db *leveldb.DB, batch *leveldb.Batch, op = kvrpcpb.Op_Put } lock := mvccLock{ - startTS: startTS, - primary: primary, - value: mutation.Value, - op: op, - ttl: ttl, - txnSize: txnSize, + startTS: startTS, + primary: primary, + value: mutation.Value, + op: op, + ttl: ttl, + txnSize: txnSize, + lockType: kv.TypeLock, } // Write minCommitTS on the primary lock. if bytes.Equal(primary, mutation.GetKey()) { diff --git a/store/mockstore/mocktikv/rpc.go b/store/mockstore/mocktikv/rpc.go index a4fdd62c4dc52..9468136402fe4 100644 --- a/store/mockstore/mocktikv/rpc.go +++ b/store/mockstore/mocktikv/rpc.go @@ -58,6 +58,7 @@ func convertToKeyError(err error) *kvrpcpb.KeyError { LockVersion: locked.StartTS, LockTtl: locked.TTL, TxnSize: locked.TxnSize, + LockType: locked.LockType, }, } } diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index a6340f0e562cf..800257df6a928 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -708,8 +708,14 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc // Check lock conflict error for nowait, if nowait set and key locked by others // report error immediately and do no more resolve locks if c.lockWaitTime == kv.LockNoWait { - if keyErr.GetLocked() != nil { - return ErrLockFailNoWait + if lockInfo := keyErr.GetLocked(); lockInfo != nil { + // if the lock left behind whose related txn is already committed or rollbacked, + // (eg secondary locks not committed or rollbacked yet) + // we cant return "nowait conflict" directly, still need to backoff and + // do resolve work + if lockInfo.LockType == kv.TypePessmisticLock { + return ErrLockFailNoWait + } } } // Check already exists error From c103a778fef7cfc06e0eec7d1ffa3116abe74a93 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 18 Oct 2019 11:11:42 +0800 Subject: [PATCH 05/21] lockType use kvrpc.Op --- go.mod | 2 +- go.sum | 4 ++-- kv/kv.go | 6 ------ store/mockstore/mocktikv/errors.go | 8 ++++++-- store/mockstore/mocktikv/mvcc.go | 5 +---- store/mockstore/mocktikv/mvcc_leveldb.go | 14 ++++++-------- store/tikv/2pc.go | 2 +- 7 files changed, 17 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 82882a917e39d..47ad4ad184b96 100644 --- a/go.mod +++ b/go.mod @@ -82,4 +82,4 @@ go 1.13 replace github.com/pingcap/parser => github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae -replace github.com/pingcap/kvproto => github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca +replace github.com/pingcap/kvproto => github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1 diff --git a/go.sum b/go.sum index b8645d9c662af..33eb4653541a0 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= -github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca h1:aYOkiPp+idsKBGAWiNyZNl8K7PsdVRQSH5+7+hYHCYY= -github.com/cfzjywxk/kvproto v0.0.0-20191017131702-d1db15853eca/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1 h1:xIbwJ3BrEa3XhDLHKo38nHFXm1F/Cv4bW5LxjnSZUS4= +github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae h1:EaLRRp9CPpDZQ3PCe3PtLA1BqY5e9i48RHtBLgMW/cI= github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae/go.mod h1:LoM8lSJ7POQOA8WIpI6Eti5BHzZtUJhu1csFCjGkQVs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/kv/kv.go b/kv/kv.go index a871abe7b547e..a74f5a6e8f5b8 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -370,9 +370,3 @@ var ( LockAlwaysWait = uint64(0) LockNoWait = uint64(1) ) - -// Used to distinguish pessmistic Lock or common lock -const ( - TypeLock uint32 = iota - TypePessmisticLock -) diff --git a/store/mockstore/mocktikv/errors.go b/store/mockstore/mocktikv/errors.go index 88e337c56d920..f2ce4f0643316 100644 --- a/store/mockstore/mocktikv/errors.go +++ b/store/mockstore/mocktikv/errors.go @@ -13,7 +13,11 @@ package mocktikv -import "fmt" +import ( + "fmt" + + "github.com/pingcap/kvproto/pkg/kvrpcpb" +) // ErrLocked is returned when trying to Read/Write on a locked key. Client should // backoff or cleanup the lock then retry. @@ -23,7 +27,7 @@ type ErrLocked struct { StartTS uint64 TTL uint64 TxnSize uint64 - LockType uint32 + LockType kvrpcpb.Op } // Error formats the lock to a string. diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index 59bd01620c526..bc81a80d8eacf 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -49,7 +49,6 @@ type mvccLock struct { forUpdateTS uint64 txnSize uint64 minCommitTS uint64 - lockType uint32 } type mvccEntry struct { @@ -72,7 +71,6 @@ func (l *mvccLock) MarshalBinary() ([]byte, error) { mh.WriteNumber(&buf, l.forUpdateTS) mh.WriteNumber(&buf, l.txnSize) mh.WriteNumber(&buf, l.minCommitTS) - mh.WriteNumber(&buf, l.lockType) return buf.Bytes(), errors.Trace(mh.err) } @@ -88,7 +86,6 @@ func (l *mvccLock) UnmarshalBinary(data []byte) error { mh.ReadNumber(buf, &l.forUpdateTS) mh.ReadNumber(buf, &l.txnSize) mh.ReadNumber(buf, &l.minCommitTS) - mh.ReadNumber(buf, &l.lockType) return errors.Trace(mh.err) } @@ -206,7 +203,7 @@ func (l *mvccLock) lockErr(key []byte) error { StartTS: l.startTS, TTL: l.ttl, TxnSize: l.txnSize, - LockType: l.lockType, + LockType: l.op, } } diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index 501fbb5fbff29..ac458bacfe73a 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -533,7 +533,6 @@ func (mvcc *MVCCLevelDB) pessimisticLockMutation(batch *leveldb.Batch, mutation op: kvrpcpb.Op_PessimisticLock, ttl: ttl, forUpdateTS: forUpdateTS, - lockType: kv.TypePessmisticLock, } writeKey := mvccEncode(mutation.Key, lockVer) writeValue, err := lock.MarshalBinary() @@ -735,13 +734,12 @@ func prewriteMutation(db *leveldb.DB, batch *leveldb.Batch, op = kvrpcpb.Op_Put } lock := mvccLock{ - startTS: startTS, - primary: primary, - value: mutation.Value, - op: op, - ttl: ttl, - txnSize: txnSize, - lockType: kv.TypeLock, + startTS: startTS, + primary: primary, + value: mutation.Value, + op: op, + ttl: ttl, + txnSize: txnSize, } // Write minCommitTS on the primary lock. if bytes.Equal(primary, mutation.GetKey()) { diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 800257df6a928..79ab9627a0cb9 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -713,7 +713,7 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc // (eg secondary locks not committed or rollbacked yet) // we cant return "nowait conflict" directly, still need to backoff and // do resolve work - if lockInfo.LockType == kv.TypePessmisticLock { + if lockInfo.LockType == pb.Op_PessimisticLock { return ErrLockFailNoWait } } From b69efa672a7235b989b639531a8d08336ef0d801 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 18 Oct 2019 15:12:02 +0800 Subject: [PATCH 06/21] gomod, refactor some logic --- executor/adapter.go | 33 ++++++++++++++++++++++++++++++--- executor/executor.go | 4 ++-- go.mod | 8 ++------ go.sum | 10 ++++++---- store/tikv/2pc.go | 24 +++++++++++------------- store/tikv/error.go | 29 +++++++++++++++-------------- store/tikv/lock_resolver.go | 22 ++++++++++++---------- 7 files changed, 78 insertions(+), 52 deletions(-) diff --git a/executor/adapter.go b/executor/adapter.go index b942fe003b5ea..7c28dc73348e0 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -24,6 +24,7 @@ import ( "github.com/opentracing/opentracing-go" "github.com/pingcap/errors" + "github.com/pingcap/failpoint" "github.com/pingcap/log" "github.com/pingcap/parser/ast" "github.com/pingcap/parser/model" @@ -568,6 +569,32 @@ func (a *ExecStmt) handlePessimisticDML(ctx context.Context, e Executor) error { } } +// GetTimestampWithRetry tries to get timestamp using retry and backoff mechanism +func (a *ExecStmt) GetTimestampWithRetry(ctx context.Context) (uint64, error) { + tsoMaxBackoff := 15000 + bo := tikv.NewBackoffer(context.Background(), tsoMaxBackoff) + if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { + span1 := span.Tracer().StartSpan("ExecStmt.getTimestampWithRetry", opentracing.ChildOf(span.Context())) + defer span1.Finish() + ctx = opentracing.ContextWithSpan(ctx, span1) + } + for { + ts, err := a.Ctx.GetStore().GetOracle().GetTimestamp(ctx) + // mock get ts fail + failpoint.Inject("ExecStmt get ts error", func() (uint64, error) { + return 0, errors.New("ExecStmt get ts error") + }) + + if err == nil { + return ts, nil + } + err = bo.Backoff(tikv.BoPDRPC, errors.Errorf("ExecStmt get timestamp failed: %v", err)) + if err != nil { + return 0, errors.Trace(err) + } + } +} + // handlePessimisticLockError updates TS and rebuild executor if the err is write conflict. func (a *ExecStmt) handlePessimisticLockError(ctx context.Context, err error) (Executor, error) { txnCtx := a.Ctx.GetSessionVars().TxnCtx @@ -595,14 +622,14 @@ func (a *ExecStmt) handlePessimisticLockError(ctx context.Context, err error) (E if conflictCommitTS > forUpdateTS { newForUpdateTS = conflictCommitTS } - } else if terror.ErrorEqual(err, tikv.ErrLockFailNoWait) { - // for nowait, when ErrLock happened, ErrLockFailNoWait will be returned, and in the same txn + } else if terror.ErrorEqual(err, tikv.ErrLockAcquireFailAndNoWaitSet) { + // for nowait, when ErrLock happened, ErrLockAcquireFailAndNoWaitSet will be returned, and in the same txn // the select for updateTs must be updated, otherwise there maybe rollback problem. // begin; select for update key1(here ErrLocked or other errors(or max_execution_time like util), // key1 lock not get and async rollback key1 is raised) // select for update key1 again(this time lock succ(maybe lock released by others)) // the async rollback operation rollbacked the lock just acquired - newForUpdateTS, tsErr := a.Ctx.GetStore().GetOracle().GetTimestamp(ctx) + newForUpdateTS, tsErr := a.GetTimestampWithRetry(ctx) if tsErr != nil { return nil, tsErr } diff --git a/executor/executor.go b/executor/executor.go index fe88365eb848c..77949ddf5265b 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -801,9 +801,9 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { } // doLockKeys is the main entry for pessimistic lock keys -// waitTime means the lock operation will wait in seconds if target key is already +// waitTime means the lock operation will wait in milliseconds if target key is already // locked by others. used for (select for update nowait) situation -// 0 means nowait +// except 0 means alwaysWait 1 means nowait func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime uint64, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. diff --git a/go.mod b/go.mod index 47ad4ad184b96..d474aac5f65f2 100644 --- a/go.mod +++ b/go.mod @@ -38,9 +38,9 @@ require ( github.com/pingcap/errors v0.11.4 github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e - github.com/pingcap/kvproto v0.0.0-20191017080330-9aa964641cd2 + github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 - github.com/pingcap/parser v0.0.0-20191012071233-32876040fefb + github.com/pingcap/parser v0.0.0-20191018070627-7bd38fdb63b0 github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible github.com/pingcap/tipb v0.0.0-20191015023537-709b39e7f8bb @@ -79,7 +79,3 @@ require ( ) go 1.13 - -replace github.com/pingcap/parser => github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae - -replace github.com/pingcap/kvproto => github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1 diff --git a/go.sum b/go.sum index 33eb4653541a0..9be48e71a4ba1 100644 --- a/go.sum +++ b/go.sum @@ -9,10 +9,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= -github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1 h1:xIbwJ3BrEa3XhDLHKo38nHFXm1F/Cv4bW5LxjnSZUS4= -github.com/cfzjywxk/kvproto v0.0.0-20191018030134-67d3d4d59cf1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae h1:EaLRRp9CPpDZQ3PCe3PtLA1BqY5e9i48RHtBLgMW/cI= -github.com/cfzjywxk/parser v0.0.0-20191016072124-6c2853d8b1ae/go.mod h1:LoM8lSJ7POQOA8WIpI6Eti5BHzZtUJhu1csFCjGkQVs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -163,10 +159,16 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= +github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6GlvnmvkHNC1OrS/ETvXxbJkJ1Nrk4prtWo= +github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe h1:zvMCi+JuuiGFN1ekrn6QKaMIDklJvkJpUn9vgR98iIA= +github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= +github.com/pingcap/parser v0.0.0-20191018070627-7bd38fdb63b0 h1:u30C+MpxtXP2kooEjRjoCqz9dMhBV9wq2syyavfeOxg= +github.com/pingcap/parser v0.0.0-20191018070627-7bd38fdb63b0/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 h1:GIEq+wZfrl2bcJxpuSrEH4H7/nlf5YdmpS+dU9lNIt8= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0/go.mod h1:G/6rJpnYwM0LKMec2rI82/5Kg6GaZMvlfB+e6/tvYmI= github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible h1:MkWCxgZpJBgY2f4HtwWMMFzSBb3+JPzeJgF3VrXE/bU= diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 79ab9627a0cb9..96d2ab2447fd7 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -705,19 +705,6 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc } var locks []*Lock for _, keyErr := range keyErrs { - // Check lock conflict error for nowait, if nowait set and key locked by others - // report error immediately and do no more resolve locks - if c.lockWaitTime == kv.LockNoWait { - if lockInfo := keyErr.GetLocked(); lockInfo != nil { - // if the lock left behind whose related txn is already committed or rollbacked, - // (eg secondary locks not committed or rollbacked yet) - // we cant return "nowait conflict" directly, still need to backoff and - // do resolve work - if lockInfo.LockType == pb.Op_PessimisticLock { - return ErrLockFailNoWait - } - } - } // Check already exists error if alreadyExist := keyErr.GetAlreadyExist(); alreadyExist != nil { key := alreadyExist.GetKey() @@ -736,6 +723,17 @@ func (c *twoPhaseCommitter) pessimisticLockSingleBatch(bo *Backoffer, batch batc if err1 != nil { return errors.Trace(err1) } + // Check lock conflict error for nowait, if nowait set and key locked by others, + // report error immediately and do no more resolve locks. + // if the lock left behind whose related txn is already committed or rollbacked, + // (eg secondary locks not committed or rollbacked yet) + // we cant return "nowait conflict" directly + if c.lockWaitTime == kv.LockNoWait && lock.LockType == pb.Op_PessimisticLock { + // the pessimistic lock found could be lock left behind(timeout but not recycled yet) + if !c.store.oracle.IsExpired(lock.TxnID, lock.TTL) { + return ErrLockAcquireFailAndNoWaitSet + } + } locks = append(locks, lock) } _, err = c.store.lockResolver.ResolveLocks(bo, c.startTS, locks) diff --git a/store/tikv/error.go b/store/tikv/error.go index 7484aa0e0e431..75175bb438fc7 100644 --- a/store/tikv/error.go +++ b/store/tikv/error.go @@ -32,13 +32,13 @@ const mismatchClusterID = "mismatch cluster id" // MySQL error instances. var ( - ErrTiKVServerTimeout = terror.ClassTiKV.New(mysql.ErrTiKVServerTimeout, mysql.MySQLErrName[mysql.ErrTiKVServerTimeout]) - ErrResolveLockTimeout = terror.ClassTiKV.New(mysql.ErrResolveLockTimeout, mysql.MySQLErrName[mysql.ErrResolveLockTimeout]) - ErrPDServerTimeout = terror.ClassTiKV.New(mysql.ErrPDServerTimeout, mysql.MySQLErrName[mysql.ErrPDServerTimeout]) - ErrRegionUnavailable = terror.ClassTiKV.New(mysql.ErrRegionUnavailable, mysql.MySQLErrName[mysql.ErrRegionUnavailable]) - ErrTiKVServerBusy = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]) - ErrGCTooEarly = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly]) - ErrLockFailNoWait = terror.ClassTiKV.New(mysql.ErrLockAcquireFailAndNoWaitSet, mysql.MySQLErrName[mysql.ErrLockAcquireFailAndNoWaitSet]) + ErrTiKVServerTimeout = terror.ClassTiKV.New(mysql.ErrTiKVServerTimeout, mysql.MySQLErrName[mysql.ErrTiKVServerTimeout]) + ErrResolveLockTimeout = terror.ClassTiKV.New(mysql.ErrResolveLockTimeout, mysql.MySQLErrName[mysql.ErrResolveLockTimeout]) + ErrPDServerTimeout = terror.ClassTiKV.New(mysql.ErrPDServerTimeout, mysql.MySQLErrName[mysql.ErrPDServerTimeout]) + ErrRegionUnavailable = terror.ClassTiKV.New(mysql.ErrRegionUnavailable, mysql.MySQLErrName[mysql.ErrRegionUnavailable]) + ErrTiKVServerBusy = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]) + ErrGCTooEarly = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly]) + ErrLockAcquireFailAndNoWaitSet = terror.ClassTiKV.New(mysql.ErrLockAcquireFailAndNoWaitSet, mysql.MySQLErrName[mysql.ErrLockAcquireFailAndNoWaitSet]) ) // ErrDeadlock wraps *kvrpcpb.Deadlock to implement the error interface. @@ -54,13 +54,14 @@ func (d *ErrDeadlock) Error() string { func init() { tikvMySQLErrCodes := map[terror.ErrCode]uint16{ - mysql.ErrTiKVServerTimeout: mysql.ErrTiKVServerTimeout, - mysql.ErrResolveLockTimeout: mysql.ErrResolveLockTimeout, - mysql.ErrPDServerTimeout: mysql.ErrPDServerTimeout, - mysql.ErrRegionUnavailable: mysql.ErrRegionUnavailable, - mysql.ErrTiKVServerBusy: mysql.ErrTiKVServerBusy, - mysql.ErrGCTooEarly: mysql.ErrGCTooEarly, - mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue, + mysql.ErrTiKVServerTimeout: mysql.ErrTiKVServerTimeout, + mysql.ErrResolveLockTimeout: mysql.ErrResolveLockTimeout, + mysql.ErrPDServerTimeout: mysql.ErrPDServerTimeout, + mysql.ErrRegionUnavailable: mysql.ErrRegionUnavailable, + mysql.ErrTiKVServerBusy: mysql.ErrTiKVServerBusy, + mysql.ErrGCTooEarly: mysql.ErrGCTooEarly, + mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue, + mysql.ErrLockAcquireFailAndNoWaitSet: mysql.ErrLockAcquireFailAndNoWaitSet, } terror.ErrClassToMySQLCodes[terror.ClassTiKV] = tikvMySQLErrCodes } diff --git a/store/tikv/lock_resolver.go b/store/tikv/lock_resolver.go index bae4fa76516ab..ae5dddb2c5528 100644 --- a/store/tikv/lock_resolver.go +++ b/store/tikv/lock_resolver.go @@ -129,11 +129,12 @@ var ttlFactor = 6000 // Lock represents a lock from tikv server. type Lock struct { - Key []byte - Primary []byte - TxnID uint64 - TTL uint64 - TxnSize uint64 + Key []byte + Primary []byte + TxnID uint64 + TTL uint64 + TxnSize uint64 + LockType kvrpcpb.Op } func (l *Lock) String() string { @@ -143,11 +144,12 @@ func (l *Lock) String() string { // NewLock creates a new *Lock. func NewLock(l *kvrpcpb.LockInfo) *Lock { return &Lock{ - Key: l.GetKey(), - Primary: l.GetPrimaryLock(), - TxnID: l.GetLockVersion(), - TTL: l.GetLockTtl(), - TxnSize: l.GetTxnSize(), + Key: l.GetKey(), + Primary: l.GetPrimaryLock(), + TxnID: l.GetLockVersion(), + TTL: l.GetLockTtl(), + TxnSize: l.GetTxnSize(), + LockType: l.LockType, } } From 3f4205b9cbceb91d5e1a1573281993a373b56490 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 18 Oct 2019 18:28:12 +0800 Subject: [PATCH 07/21] typo --- executor/adapter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/adapter.go b/executor/adapter.go index 7c28dc73348e0..5bb327b5a9caa 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -574,7 +574,7 @@ func (a *ExecStmt) GetTimestampWithRetry(ctx context.Context) (uint64, error) { tsoMaxBackoff := 15000 bo := tikv.NewBackoffer(context.Background(), tsoMaxBackoff) if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { - span1 := span.Tracer().StartSpan("ExecStmt.getTimestampWithRetry", opentracing.ChildOf(span.Context())) + span1 := span.Tracer().StartSpan("ExecStmt.GetTimestampWithRetry", opentracing.ChildOf(span.Context())) defer span1.Finish() ctx = opentracing.ContextWithSpan(ctx, span1) } From 38c5cafcc84dbc74c62d13e4d21a0bf8a7a8763d Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 18 Oct 2019 18:44:20 +0800 Subject: [PATCH 08/21] format --- planner/core/point_get_plan.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index cf627c1858faa..d61674cbd2a1d 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -606,12 +606,12 @@ func tryPointGetPlan(ctx sessionctx.Context, selStmt *ast.SelectStmt) *PointGetP func newPointGetPlan(ctx sessionctx.Context, dbName string, schema *expression.Schema, tbl *model.TableInfo, names []*types.FieldName) *PointGetPlan { p := &PointGetPlan{ - basePlan: newBasePlan(ctx, plancodec.TypePointGet, 0), - dbName: dbName, - schema: schema, - TblInfo: tbl, - outputNames: names, - LockWaitTime: kv.LockAlwaysWait, + basePlan: newBasePlan(ctx, plancodec.TypePointGet, 0), + dbName: dbName, + schema: schema, + TblInfo: tbl, + outputNames: names, + LockWaitTime: kv.LockAlwaysWait, } ctx.GetSessionVars().StmtCtx.Tables = []stmtctx.TableEntry{{DB: ctx.GetSessionVars().CurrentDB, Table: tbl.Name.L}} return p From 99935c3ce8a51db74dfba80391de2aeec4818ff9 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 24 Oct 2019 11:14:06 +0800 Subject: [PATCH 09/21] go sum --- go.sum | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.sum b/go.sum index 523e1f8ab7b7f..db8b1ed354c30 100644 --- a/go.sum +++ b/go.sum @@ -160,6 +160,8 @@ github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6Glvnmv github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1 h1:DNvxkdcjA0TBIIIF+K2w9KMlTzMZzLZ5JVF26kTCPhg= github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe h1:zvMCi+JuuiGFN1ekrn6QKaMIDklJvkJpUn9vgR98iIA= +github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= From 34dccb972ebca4d3632b20e1fcb641cc73ba4850 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 24 Oct 2019 11:18:37 +0800 Subject: [PATCH 10/21] go sum --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index db8b1ed354c30..a663c0f46f0df 100644 --- a/go.sum +++ b/go.sum @@ -158,8 +158,6 @@ github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rG github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6GlvnmvkHNC1OrS/ETvXxbJkJ1Nrk4prtWo= github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1 h1:DNvxkdcjA0TBIIIF+K2w9KMlTzMZzLZ5JVF26kTCPhg= -github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe h1:zvMCi+JuuiGFN1ekrn6QKaMIDklJvkJpUn9vgR98iIA= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= From 5c52dbd31198ed92fcf9aea206724419256f07b1 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Thu, 24 Oct 2019 23:59:07 +0800 Subject: [PATCH 11/21] format --- store/tikv/error.go | 4 ++-- store/tikv/txn.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/store/tikv/error.go b/store/tikv/error.go index 33d6521158908..30879aa85b9e7 100644 --- a/store/tikv/error.go +++ b/store/tikv/error.go @@ -39,7 +39,7 @@ var ( ErrTiKVServerBusy = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]) ErrGCTooEarly = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly]) ErrQueryInterrupted = terror.ClassTiKV.New(mysql.ErrQueryInterrupted, mysql.MySQLErrName[mysql.ErrQueryInterrupted]) - ErrLockAcquireFailAndNoWaitSet = terror.ClassTiKV.New(mysql.ErrLockAcquireFailAndNoWaitSet, mysql.MySQLErrName[mysql.ErrLockAcquireFailAndNoWaitSet]) + ErrLockAcquireFailAndNoWaitSet = terror.ClassTiKV.New(mysql.ErrLockAcquireFailAndNoWaitSet, mysql.MySQLErrName[mysql.ErrLockAcquireFailAndNoWaitSet]) ) // ErrDeadlock wraps *kvrpcpb.Deadlock to implement the error interface. @@ -62,7 +62,7 @@ func init() { mysql.ErrTiKVServerBusy: mysql.ErrTiKVServerBusy, mysql.ErrGCTooEarly: mysql.ErrGCTooEarly, mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue, - mysql.ErrQueryInterrupted: mysql.ErrQueryInterrupted, + mysql.ErrQueryInterrupted: mysql.ErrQueryInterrupted, mysql.ErrLockAcquireFailAndNoWaitSet: mysql.ErrLockAcquireFailAndNoWaitSet, } terror.ErrClassToMySQLCodes[terror.ClassTiKV] = tikvMySQLErrCodes diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 700a84668bf53..22890ad365a60 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -426,7 +426,7 @@ func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS ui // If the number of keys greater than 1, it can be on different region, // concurrently execute on multiple regions may lead to deadlock. txn.committer.isFirstLock = len(txn.lockKeys) == 0 && len(keys) == 1 - txn.committer.lockWaitTime = lockWaitTime + txn.committer.lockWaitTime = lockWaitTime err := txn.committer.pessimisticLockKeys(bo, killed, keys) if killed != nil { // If the kill signal is received during waiting for pessimisticLock, From 1a4d0b3bec16a60bc5e9555339d944335ffb6442 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 00:02:11 +0800 Subject: [PATCH 12/21] tidy --- go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/go.sum b/go.sum index 00883102fe62e..86d5bdf8b5099 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mo github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= From 4afc621d7ae5cd9a5376e66f43b52aa7040f3c3a Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 00:17:33 +0800 Subject: [PATCH 13/21] tidy sum --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 86d5bdf8b5099..85f764b99b50f 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,6 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= -github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7 h1:tt24R4cv6GlvnmvkHNC1OrS/ETvXxbJkJ1Nrk4prtWo= -github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe h1:zvMCi+JuuiGFN1ekrn6QKaMIDklJvkJpUn9vgR98iIA= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= From de469ca345d3cca293a68114b5cabd076fbaa1e3 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 00:25:00 +0800 Subject: [PATCH 14/21] tidy --- go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/go.sum b/go.sum index 85f764b99b50f..748241fb292ff 100644 --- a/go.sum +++ b/go.sum @@ -157,6 +157,7 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c h1:hvQd3aOLKLF7x github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= +github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe h1:zvMCi+JuuiGFN1ekrn6QKaMIDklJvkJpUn9vgR98iIA= github.com/pingcap/kvproto v0.0.0-20191018060334-75b7ebae12fe/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= From fddc2e80c59494c39a0dc766eb6a560671f2c523 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 15:08:25 +0800 Subject: [PATCH 15/21] refactoration, add case --- executor/adapter.go | 6 +++--- kv/kv.go | 2 ++ session/pessimistic_test.go | 42 +++++++++++++++++++++++++++++++++++++ store/tikv/2pc.go | 17 ++++++++------- store/tikv/txn.go | 6 ++++-- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/executor/adapter.go b/executor/adapter.go index 73d68d1b06a5d..5249bd6f387c7 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -572,17 +572,17 @@ func (a *ExecStmt) handlePessimisticDML(ctx context.Context, e Executor) error { // GetTimestampWithRetry tries to get timestamp using retry and backoff mechanism func (a *ExecStmt) GetTimestampWithRetry(ctx context.Context) (uint64, error) { tsoMaxBackoff := 15000 - bo := tikv.NewBackoffer(context.Background(), tsoMaxBackoff) if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { span1 := span.Tracer().StartSpan("ExecStmt.GetTimestampWithRetry", opentracing.ChildOf(span.Context())) defer span1.Finish() ctx = opentracing.ContextWithSpan(ctx, span1) } + bo := tikv.NewBackoffer(ctx, tsoMaxBackoff) for { ts, err := a.Ctx.GetStore().GetOracle().GetTimestamp(ctx) // mock get ts fail - failpoint.Inject("ExecStmt get ts error", func() (uint64, error) { - return 0, errors.New("ExecStmt get ts error") + failpoint.Inject("ExecStmtGetTsError", func() (uint64, error) { + return 0, errors.New("ExecStmtGetTsError") }) if err == nil { diff --git a/kv/kv.go b/kv/kv.go index 64460ace6c4a9..3519243a42221 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -368,6 +368,8 @@ type SplitableStore interface { } // Used for pessimistic lock wait time +// these two constants are special for lock protocol with tikv +// 0 means always wait, 1 means nowait, others meaning lock wait in milliseconds var ( LockAlwaysWait = uint64(0) LockNoWait = uint64(1) diff --git a/session/pessimistic_test.go b/session/pessimistic_test.go index 1e7eeb6d56d56..04e4dbcbd19c5 100644 --- a/session/pessimistic_test.go +++ b/session/pessimistic_test.go @@ -15,6 +15,7 @@ package session_test import ( "fmt" + "github.com/pingcap/failpoint" "sync" "sync/atomic" "time" @@ -481,6 +482,47 @@ func (s *testPessimisticSuite) TestSelectForUpdateNoWait(c *C) { tk2.MustExec("commit") } +func (s *testPessimisticSuite) TestAsyncRollBackNoWait(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk2 := testkit.NewTestKitWithInit(c, s.store) + tk3 := testkit.NewTestKitWithInit(c, s.store) + tk.MustExec("drop table if exists tk") + tk.MustExec("create table tk (c1 int primary key, c2 int)") + tk.MustExec("insert into tk values(1,1),(2,2),(3,3),(4,4),(5,17)") + + tk.MustExec("set @@autocommit = 0") + tk2.MustExec("set @@autocommit = 0") + tk3.MustExec("set @@autocommit = 0") + + // test get ts failed for handlePessimisticLockError when using nowait + // even though async rollback for pessimistic lock may rollback later locked key if get ts failed from pd + // the txn correctness should be ensured + c.Assert(failpoint.Enable("github.com/pingcap/tidb/executor/ExecStmtGetTsError", "return"), IsNil) + c.Assert(failpoint.Enable("github.com/pingcap/tidb/store/tikv/AsyncRollBackSleep", "return"), IsNil) + tk.MustExec("begin pessimistic") + tk.MustExec("select * from tk where c1 > 0 for update nowait") + tk2.MustExec("begin pessimistic") + _, err := tk2.Exec("select * from tk where c1 > 0 for update nowait") + c.Check(err, NotNil) + tk.MustExec("commit") + tk2.MustQuery("select * from tk where c1 > 0 for update nowait") + tk2.MustQuery("select * from tk where c1 = 5 for update nowait").Check(testkit.Rows("5 17")) + tk3.MustExec("begin pessimistic") + tk3.MustExec("update tk set c2 = 1 where c1 = 5") // here lock succ happen in getTs failed from pd + tk2.MustExec("update tk set c2 = c2 + 100 where c1 > 0") // this will not get effect + time.Sleep(3 * time.Second) + _, err = tk2.Exec("commit") + c.Check(err, NotNil) // txn abort because pessimistic lock not found + tk3.MustExec("commit") + tk3.MustExec("begin pessimistic") + tk3.MustQuery("select * from tk where c1 = 5 for update nowait").Check(testkit.Rows("5 1")) + tk3.MustQuery("select * from tk where c1 = 4 for update nowait").Check(testkit.Rows("4 4")) + tk3.MustQuery("select * from tk where c1 = 3 for update nowait").Check(testkit.Rows("3 3")) + tk3.MustExec("commit") + c.Assert(failpoint.Disable("github.com/pingcap/tidb/executor/ExecStmtGetTsError"), IsNil) + c.Assert(failpoint.Disable("github.com/pingcap/tidb/store/tikv/AsyncRollBackSleep"), IsNil) +} + func (s *testPessimisticSuite) TestWaitLockKill(c *C) { // Test kill command works on waiting pessimistic lock. tk := testkit.NewTestKitWithInit(c, s.store) diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 19bd3f87c91f9..d630cd4b71f63 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -46,7 +46,10 @@ type twoPhaseCommitAction interface { type actionPrewrite struct{} type actionCommit struct{} type actionCleanup struct{} -type actionPessimisticLock struct{ killed *uint32 } +type actionPessimisticLock struct { + killed *uint32 + lockWaitTime uint64 +} type actionPessimisticRollback struct{} var ( @@ -125,8 +128,6 @@ type twoPhaseCommitter struct { regionTxnSize map[uint64]int // Used by pessimistic transaction and large transaction. ttlManager - // Used for select for update in ms, 0 means always wait, 1 means nowait - lockWaitTime uint64 } // batchExecutor is txn controller providing rate control like utils @@ -666,7 +667,6 @@ func (action actionPessimisticLock) handleSingleBatch(c *twoPhaseCommitter, bo * ForUpdateTs: c.forUpdateTS, LockTtl: c.pessimisticTTL, IsFirstLock: c.isFirstLock, - WaitTimeout: c.lockWaitTime, }, pb.Context{Priority: c.priority, SyncLog: c.syncLog}) for { resp, err := c.store.SendReq(bo, req, batch.region, readTimeoutShort) @@ -682,7 +682,7 @@ func (action actionPessimisticLock) handleSingleBatch(c *twoPhaseCommitter, bo * if err != nil { return errors.Trace(err) } - err = c.pessimisticLockKeys(bo, action.killed, batch.keys) + err = c.pessimisticLockKeys(bo, action.killed, action.lockWaitTime, batch.keys) return errors.Trace(err) } if resp.Resp == nil { @@ -718,7 +718,7 @@ func (action actionPessimisticLock) handleSingleBatch(c *twoPhaseCommitter, bo * // if the lock left behind whose related txn is already committed or rollbacked, // (eg secondary locks not committed or rollbacked yet) // we cant return "nowait conflict" directly - if c.lockWaitTime == kv.LockNoWait && lock.LockType == pb.Op_PessimisticLock { + if action.lockWaitTime == kv.LockNoWait && lock.LockType == pb.Op_PessimisticLock { // the pessimistic lock found could be lock left behind(timeout but not recycled yet) if !c.store.oracle.IsExpired(lock.TxnID, lock.TTL) { return ErrLockAcquireFailAndNoWaitSet @@ -947,8 +947,9 @@ func (c *twoPhaseCommitter) cleanupKeys(bo *Backoffer, keys [][]byte) error { return c.doActionOnKeys(bo, actionCleanup{}, keys) } -func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, keys [][]byte) error { - return c.doActionOnKeys(bo, actionPessimisticLock{killed}, keys) +func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime uint64, + keys [][]byte) error { + return c.doActionOnKeys(bo, actionPessimisticLock{killed, lockWaitTime}, keys) } func (c *twoPhaseCommitter) pessimisticRollbackKeys(bo *Backoffer, keys [][]byte) error { diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 22890ad365a60..d23a723d24ff3 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -426,8 +426,7 @@ func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS ui // If the number of keys greater than 1, it can be on different region, // concurrently execute on multiple regions may lead to deadlock. txn.committer.isFirstLock = len(txn.lockKeys) == 0 && len(keys) == 1 - txn.committer.lockWaitTime = lockWaitTime - err := txn.committer.pessimisticLockKeys(bo, killed, keys) + err := txn.committer.pessimisticLockKeys(bo, killed, lockWaitTime, keys) if killed != nil { // If the kill signal is received during waiting for pessimisticLock, // pessimisticLockKeys would handle the error but it doesn't reset the flag. @@ -482,6 +481,9 @@ func (txn *tikvTxn) asyncPessimisticRollback(ctx context.Context, keys [][]byte) wg := new(sync.WaitGroup) wg.Add(1) go func() { + failpoint.Inject("AsyncRollBackSleep", func() { + time.Sleep(2 * time.Second) + }) err := committer.pessimisticRollbackKeys(NewBackoffer(ctx, pessimisticRollbackMaxBackoff), keys) if err != nil { logutil.Logger(ctx).Warn("[kv] pessimisticRollback failed.", zap.Error(err)) From 119a307170b53ed9661543ec1fcffadf8145966f Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 15:55:58 +0800 Subject: [PATCH 16/21] add missing --- store/tikv/2pc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index d630cd4b71f63..324d82b186b73 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -667,6 +667,7 @@ func (action actionPessimisticLock) handleSingleBatch(c *twoPhaseCommitter, bo * ForUpdateTs: c.forUpdateTS, LockTtl: c.pessimisticTTL, IsFirstLock: c.isFirstLock, + WaitTimeout: action.lockWaitTime, }, pb.Context{Priority: c.priority, SyncLog: c.syncLog}) for { resp, err := c.store.SendReq(bo, req, batch.region, readTimeoutShort) From 09bdcb270934a6975da352334da0c39d645467a7 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 25 Oct 2019 16:02:44 +0800 Subject: [PATCH 17/21] import --- session/pessimistic_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session/pessimistic_test.go b/session/pessimistic_test.go index 04e4dbcbd19c5..a73566fdf6ac3 100644 --- a/session/pessimistic_test.go +++ b/session/pessimistic_test.go @@ -15,13 +15,13 @@ package session_test import ( "fmt" - "github.com/pingcap/failpoint" "sync" "sync/atomic" "time" . "github.com/pingcap/check" "github.com/pingcap/errors" + "github.com/pingcap/failpoint" "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/terror" "github.com/pingcap/tidb/domain" From afa7beab2a0a92a5739a2a9c3d32e65d457ae250 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 1 Nov 2019 12:46:05 +0800 Subject: [PATCH 18/21] format --- executor/point_get.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/point_get.go b/executor/point_get.go index ed82472f20421..067e5aaeebc7f 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -70,7 +70,7 @@ func (e *PointGetExecutor) Init(p *plannercore.PointGetPlan, startTs uint64) { e.startTS = startTs e.done = false e.lock = p.Lock - e.lockWaitTime = p.LockWaitTime + e.lockWaitTime = p.LockWaitTime } // Open implements the Executor interface. From 4b3dfce86a9fc02ecfbb2d8ea4e1b37196ac2660 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 1 Nov 2019 15:02:34 +0800 Subject: [PATCH 19/21] change nowait signal to int64 --- executor/executor.go | 2 +- executor/point_get.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- kv/kv.go | 8 ++++---- kv/mock.go | 2 +- planner/core/point_get_plan.go | 2 +- store/mockstore/mocktikv/mvcc.go | 2 +- store/mockstore/mocktikv/mvcc_leveldb.go | 2 +- store/tikv/2pc.go | 4 ++-- store/tikv/txn.go | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index a12943fd161dd..ed9f9ed9a4282 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -826,7 +826,7 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { // waitTime means the lock operation will wait in milliseconds if target key is already // locked by others. used for (select for update nowait) situation // except 0 means alwaysWait 1 means nowait -func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime uint64, keys ...kv.Key) error { +func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime int64, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. txn, err := se.Txn(true) diff --git a/executor/point_get.go b/executor/point_get.go index 067e5aaeebc7f..f055d2937c474 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -58,7 +58,7 @@ type PointGetExecutor struct { snapshot kv.Snapshot done bool lock bool - lockWaitTime uint64 + lockWaitTime int64 } // Init set fields needed for PointGetExecutor reuse, this does NOT change baseExecutor field diff --git a/go.mod b/go.mod index 5d57c0dbaa133..0f54cb4bc0037 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/pingcap/errors v0.11.4 github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e - github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 + github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 github.com/pingcap/parser v0.0.0-20191031081038-bfb0c3adf567 github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 diff --git a/go.sum b/go.sum index 7004b341bb518..fdce1c8e131fa 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 h1:qqGSXCFr9Uc5VIDBEt4zlmMcI8e4GlkWfDVzQ+dexRk= -github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 h1:C5nV9osqA+R/R2fxYxVfqAUlCi3Oo5yJ/JSKDeHSAOk= +github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= diff --git a/kv/kv.go b/kv/kv.go index 3519243a42221..807ecaf36c715 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -169,7 +169,7 @@ type Transaction interface { // String implements fmt.Stringer interface. String() string // LockKeys tries to lock the entries with the keys in KV store. - LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keys ...Key) error + LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keys ...Key) error // SetOption sets an option with a value, when val is nil, uses the default // value of this option. SetOption(opt Option, val interface{}) @@ -369,8 +369,8 @@ type SplitableStore interface { // Used for pessimistic lock wait time // these two constants are special for lock protocol with tikv -// 0 means always wait, 1 means nowait, others meaning lock wait in milliseconds +// 0 means always wait, -1 means nowait, others meaning lock wait in milliseconds var ( - LockAlwaysWait = uint64(0) - LockNoWait = uint64(1) + LockAlwaysWait = int64(0) + LockNoWait = int64(-1) ) diff --git a/kv/mock.go b/kv/mock.go index 4f4582b264775..2e0332b6a4fa3 100644 --- a/kv/mock.go +++ b/kv/mock.go @@ -39,7 +39,7 @@ func (t *mockTxn) String() string { return "" } -func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ uint64, _ ...Key) error { +func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ int64, _ ...Key) error { return nil } diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 01e56ebef713a..a7270e97d6904 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -55,7 +55,7 @@ type PointGetPlan struct { Lock bool IsForUpdate bool outputNames []*types.FieldName - LockWaitTime uint64 + LockWaitTime int64 } type nameValuePair struct { diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index bc81a80d8eacf..ffed3c0b22e14 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -256,7 +256,7 @@ type MVCCStore interface { ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error + forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error Prewrite(req *kvrpcpb.PrewriteRequest) []error Commit(keys [][]byte, startTS, commitTS uint64) error diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index 785011f67a373..74c67228fb287 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -466,7 +466,7 @@ func reverse(values []mvccValue) { // PessimisticLock writes the pessimistic lock. func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error { + forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error { mvcc.mu.Lock() defer mvcc.mu.Unlock() diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 32cd25c1de337..d66922c309b1b 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -48,7 +48,7 @@ type actionCommit struct{} type actionCleanup struct{} type actionPessimisticLock struct { killed *uint32 - lockWaitTime uint64 + lockWaitTime int64 } type actionPessimisticRollback struct{} @@ -975,7 +975,7 @@ func (c *twoPhaseCommitter) cleanupKeys(bo *Backoffer, keys [][]byte) error { return c.doActionOnKeys(bo, actionCleanup{}, keys) } -func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime uint64, +func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime int64, keys [][]byte) error { return c.doActionOnKeys(bo, actionPessimisticLock{killed, lockWaitTime}, keys) } diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 6ac03dd1b57d3..0d26ac5dfbfdb 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -382,7 +382,7 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { } // lockWaitTime in ms, except that 0 means always wait lock, 1 means nowait lock -func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keysInput ...kv.Key) error { +func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput)) txn.mu.Lock() From edcaf66eb4c85707d56408ef96b0ee94d2c52cd3 Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Mon, 4 Nov 2019 14:33:23 +0800 Subject: [PATCH 20/21] Revert "change nowait signal to int64" This reverts commit 4b3dfce86a9fc02ecfbb2d8ea4e1b37196ac2660. --- executor/executor.go | 2 +- executor/point_get.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- kv/kv.go | 8 ++++---- kv/mock.go | 2 +- planner/core/point_get_plan.go | 2 +- store/mockstore/mocktikv/mvcc.go | 2 +- store/mockstore/mocktikv/mvcc_leveldb.go | 2 +- store/tikv/2pc.go | 4 ++-- store/tikv/txn.go | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index ed9f9ed9a4282..a12943fd161dd 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -826,7 +826,7 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { // waitTime means the lock operation will wait in milliseconds if target key is already // locked by others. used for (select for update nowait) situation // except 0 means alwaysWait 1 means nowait -func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime int64, keys ...kv.Key) error { +func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime uint64, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. txn, err := se.Txn(true) diff --git a/executor/point_get.go b/executor/point_get.go index f055d2937c474..067e5aaeebc7f 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -58,7 +58,7 @@ type PointGetExecutor struct { snapshot kv.Snapshot done bool lock bool - lockWaitTime int64 + lockWaitTime uint64 } // Init set fields needed for PointGetExecutor reuse, this does NOT change baseExecutor field diff --git a/go.mod b/go.mod index 0f54cb4bc0037..5d57c0dbaa133 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/pingcap/errors v0.11.4 github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e - github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 + github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 github.com/pingcap/parser v0.0.0-20191031081038-bfb0c3adf567 github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 diff --git a/go.sum b/go.sum index fdce1c8e131fa..7004b341bb518 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 h1:C5nV9osqA+R/R2fxYxVfqAUlCi3Oo5yJ/JSKDeHSAOk= -github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w= +github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 h1:qqGSXCFr9Uc5VIDBEt4zlmMcI8e4GlkWfDVzQ+dexRk= +github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= diff --git a/kv/kv.go b/kv/kv.go index 807ecaf36c715..3519243a42221 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -169,7 +169,7 @@ type Transaction interface { // String implements fmt.Stringer interface. String() string // LockKeys tries to lock the entries with the keys in KV store. - LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keys ...Key) error + LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keys ...Key) error // SetOption sets an option with a value, when val is nil, uses the default // value of this option. SetOption(opt Option, val interface{}) @@ -369,8 +369,8 @@ type SplitableStore interface { // Used for pessimistic lock wait time // these two constants are special for lock protocol with tikv -// 0 means always wait, -1 means nowait, others meaning lock wait in milliseconds +// 0 means always wait, 1 means nowait, others meaning lock wait in milliseconds var ( - LockAlwaysWait = int64(0) - LockNoWait = int64(-1) + LockAlwaysWait = uint64(0) + LockNoWait = uint64(1) ) diff --git a/kv/mock.go b/kv/mock.go index 2e0332b6a4fa3..4f4582b264775 100644 --- a/kv/mock.go +++ b/kv/mock.go @@ -39,7 +39,7 @@ func (t *mockTxn) String() string { return "" } -func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ int64, _ ...Key) error { +func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ uint64, _ ...Key) error { return nil } diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index a7270e97d6904..01e56ebef713a 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -55,7 +55,7 @@ type PointGetPlan struct { Lock bool IsForUpdate bool outputNames []*types.FieldName - LockWaitTime int64 + LockWaitTime uint64 } type nameValuePair struct { diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index ffed3c0b22e14..bc81a80d8eacf 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -256,7 +256,7 @@ type MVCCStore interface { ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error + forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error Prewrite(req *kvrpcpb.PrewriteRequest) []error Commit(keys [][]byte, startTS, commitTS uint64) error diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index 74c67228fb287..785011f67a373 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -466,7 +466,7 @@ func reverse(values []mvccValue) { // PessimisticLock writes the pessimistic lock. func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error { + forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error { mvcc.mu.Lock() defer mvcc.mu.Unlock() diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index d66922c309b1b..32cd25c1de337 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -48,7 +48,7 @@ type actionCommit struct{} type actionCleanup struct{} type actionPessimisticLock struct { killed *uint32 - lockWaitTime int64 + lockWaitTime uint64 } type actionPessimisticRollback struct{} @@ -975,7 +975,7 @@ func (c *twoPhaseCommitter) cleanupKeys(bo *Backoffer, keys [][]byte) error { return c.doActionOnKeys(bo, actionCleanup{}, keys) } -func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime int64, +func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime uint64, keys [][]byte) error { return c.doActionOnKeys(bo, actionPessimisticLock{killed, lockWaitTime}, keys) } diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 0d26ac5dfbfdb..6ac03dd1b57d3 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -382,7 +382,7 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { } // lockWaitTime in ms, except that 0 means always wait lock, 1 means nowait lock -func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keysInput ...kv.Key) error { +func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput)) txn.mu.Lock() From 16b26c4ec3c9591f0f7b7cb2795bff758ca68dcf Mon Sep 17 00:00:00 2001 From: cfzjywxk Date: Fri, 1 Nov 2019 15:02:34 +0800 Subject: [PATCH 21/21] change nowait signal to int64 --- executor/executor.go | 2 +- executor/point_get.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- kv/kv.go | 8 ++++---- kv/mock.go | 2 +- planner/core/point_get_plan.go | 2 +- store/mockstore/mocktikv/mvcc.go | 2 +- store/mockstore/mocktikv/mvcc_leveldb.go | 2 +- store/tikv/2pc.go | 4 ++-- store/tikv/txn.go | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index a12943fd161dd..ed9f9ed9a4282 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -826,7 +826,7 @@ func (e *SelectLockExec) Next(ctx context.Context, req *chunk.Chunk) error { // waitTime means the lock operation will wait in milliseconds if target key is already // locked by others. used for (select for update nowait) situation // except 0 means alwaysWait 1 means nowait -func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime uint64, keys ...kv.Key) error { +func doLockKeys(ctx context.Context, se sessionctx.Context, waitTime int64, keys ...kv.Key) error { se.GetSessionVars().TxnCtx.ForUpdate = true // Lock keys only once when finished fetching all results. txn, err := se.Txn(true) diff --git a/executor/point_get.go b/executor/point_get.go index 067e5aaeebc7f..f055d2937c474 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -58,7 +58,7 @@ type PointGetExecutor struct { snapshot kv.Snapshot done bool lock bool - lockWaitTime uint64 + lockWaitTime int64 } // Init set fields needed for PointGetExecutor reuse, this does NOT change baseExecutor field diff --git a/go.mod b/go.mod index 5d57c0dbaa133..0f54cb4bc0037 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/pingcap/errors v0.11.4 github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e - github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 + github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 github.com/pingcap/parser v0.0.0-20191031081038-bfb0c3adf567 github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 diff --git a/go.sum b/go.sum index 7004b341bb518..fdce1c8e131fa 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/pingcap/failpoint v0.0.0-20190512135322-30cc7431d99c/go.mod h1:DNS3Qg github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= -github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1 h1:qqGSXCFr9Uc5VIDBEt4zlmMcI8e4GlkWfDVzQ+dexRk= -github.com/pingcap/kvproto v0.0.0-20191025022903-62abb760d9b1/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= +github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466 h1:C5nV9osqA+R/R2fxYxVfqAUlCi3Oo5yJ/JSKDeHSAOk= +github.com/pingcap/kvproto v0.0.0-20191101062931-76b56d6eb466/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w= github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= diff --git a/kv/kv.go b/kv/kv.go index 3519243a42221..807ecaf36c715 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -169,7 +169,7 @@ type Transaction interface { // String implements fmt.Stringer interface. String() string // LockKeys tries to lock the entries with the keys in KV store. - LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keys ...Key) error + LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keys ...Key) error // SetOption sets an option with a value, when val is nil, uses the default // value of this option. SetOption(opt Option, val interface{}) @@ -369,8 +369,8 @@ type SplitableStore interface { // Used for pessimistic lock wait time // these two constants are special for lock protocol with tikv -// 0 means always wait, 1 means nowait, others meaning lock wait in milliseconds +// 0 means always wait, -1 means nowait, others meaning lock wait in milliseconds var ( - LockAlwaysWait = uint64(0) - LockNoWait = uint64(1) + LockAlwaysWait = int64(0) + LockNoWait = int64(-1) ) diff --git a/kv/mock.go b/kv/mock.go index 4f4582b264775..2e0332b6a4fa3 100644 --- a/kv/mock.go +++ b/kv/mock.go @@ -39,7 +39,7 @@ func (t *mockTxn) String() string { return "" } -func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ uint64, _ ...Key) error { +func (t *mockTxn) LockKeys(_ context.Context, _ *uint32, _ uint64, _ int64, _ ...Key) error { return nil } diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 01e56ebef713a..a7270e97d6904 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -55,7 +55,7 @@ type PointGetPlan struct { Lock bool IsForUpdate bool outputNames []*types.FieldName - LockWaitTime uint64 + LockWaitTime int64 } type nameValuePair struct { diff --git a/store/mockstore/mocktikv/mvcc.go b/store/mockstore/mocktikv/mvcc.go index bc81a80d8eacf..ffed3c0b22e14 100644 --- a/store/mockstore/mocktikv/mvcc.go +++ b/store/mockstore/mocktikv/mvcc.go @@ -256,7 +256,7 @@ type MVCCStore interface { ReverseScan(startKey, endKey []byte, limit int, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair BatchGet(ks [][]byte, startTS uint64, isoLevel kvrpcpb.IsolationLevel) []Pair PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error + forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error PessimisticRollback(keys [][]byte, startTS, forUpdateTS uint64) []error Prewrite(req *kvrpcpb.PrewriteRequest) []error Commit(keys [][]byte, startTS, commitTS uint64) error diff --git a/store/mockstore/mocktikv/mvcc_leveldb.go b/store/mockstore/mocktikv/mvcc_leveldb.go index 785011f67a373..74c67228fb287 100644 --- a/store/mockstore/mocktikv/mvcc_leveldb.go +++ b/store/mockstore/mocktikv/mvcc_leveldb.go @@ -466,7 +466,7 @@ func reverse(values []mvccValue) { // PessimisticLock writes the pessimistic lock. func (mvcc *MVCCLevelDB) PessimisticLock(mutations []*kvrpcpb.Mutation, primary []byte, startTS, - forUpdateTS uint64, ttl uint64, lockWaitTime uint64) []error { + forUpdateTS uint64, ttl uint64, lockWaitTime int64) []error { mvcc.mu.Lock() defer mvcc.mu.Unlock() diff --git a/store/tikv/2pc.go b/store/tikv/2pc.go index 32cd25c1de337..d66922c309b1b 100644 --- a/store/tikv/2pc.go +++ b/store/tikv/2pc.go @@ -48,7 +48,7 @@ type actionCommit struct{} type actionCleanup struct{} type actionPessimisticLock struct { killed *uint32 - lockWaitTime uint64 + lockWaitTime int64 } type actionPessimisticRollback struct{} @@ -975,7 +975,7 @@ func (c *twoPhaseCommitter) cleanupKeys(bo *Backoffer, keys [][]byte) error { return c.doActionOnKeys(bo, actionCleanup{}, keys) } -func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime uint64, +func (c *twoPhaseCommitter) pessimisticLockKeys(bo *Backoffer, killed *uint32, lockWaitTime int64, keys [][]byte) error { return c.doActionOnKeys(bo, actionPessimisticLock{killed, lockWaitTime}, keys) } diff --git a/store/tikv/txn.go b/store/tikv/txn.go index 6ac03dd1b57d3..0d26ac5dfbfdb 100644 --- a/store/tikv/txn.go +++ b/store/tikv/txn.go @@ -382,7 +382,7 @@ func (txn *tikvTxn) rollbackPessimisticLocks() error { } // lockWaitTime in ms, except that 0 means always wait lock, 1 means nowait lock -func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime uint64, keysInput ...kv.Key) error { +func (txn *tikvTxn) LockKeys(ctx context.Context, killed *uint32, forUpdateTS uint64, lockWaitTime int64, keysInput ...kv.Key) error { // Exclude keys that are already locked. keys := make([][]byte, 0, len(keysInput)) txn.mu.Lock()