From dffe29355a0b8a87f58ca13dd7304d97016faadf Mon Sep 17 00:00:00 2001 From: crazycs Date: Tue, 3 Sep 2019 23:11:49 +0800 Subject: [PATCH] *: not send tso request when point get with max tso (#11981) --- executor/adapter.go | 2 +- planner/optimize.go | 17 +++++++++++++++++ session/session.go | 13 +++++++++++-- sessionctx/context.go | 2 ++ util/mock/context.go | 4 ++++ 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/executor/adapter.go b/executor/adapter.go index 5c4fabb5b6..e79946e12c 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -769,7 +769,7 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) { // IsPointGetWithPKOrUniqueKeyByAutoCommit returns true when meets following conditions: // 1. ctx is auto commit tagged // 2. txn is not valid -// 2. plan is point get by pk, or point get by unique index (no double read) +// 3. plan is point get by pk, or point get by unique index (no double read) func IsPointGetWithPKOrUniqueKeyByAutoCommit(ctx sessionctx.Context, p plannercore.Plan) (bool, error) { // check auto commit if !ctx.GetSessionVars().IsAutocommit() { diff --git a/planner/optimize.go b/planner/optimize.go index b44ba76ff5..8ed38f5bb9 100644 --- a/planner/optimize.go +++ b/planner/optimize.go @@ -36,9 +36,14 @@ import ( func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (plannercore.Plan, error) { fp := plannercore.TryFastPlan(sctx, node) if fp != nil { + if !isPointGetWithoutDoubleRead(sctx, fp) { + sctx.PrepareTxnFuture(ctx) + } return fp, nil } + sctx.PrepareTxnFuture(ctx) + var oriHint *bindinfo.HintsSet if stmtNode, ok := node.(ast.StmtNode); ok { oriHint = addHint(sctx, stmtNode) @@ -203,6 +208,18 @@ func handleInvalidBindRecord(ctx context.Context, sctx sessionctx.Context, stmtN } } +// isPointGetWithoutDoubleRead returns true when meets following conditions: +// 1. ctx is auto commit tagged. +// 2. plan is point get by pk. +func isPointGetWithoutDoubleRead(ctx sessionctx.Context, p plannercore.Plan) bool { + if !ctx.GetSessionVars().IsAutocommit() { + return false + } + + v, ok := p.(*plannercore.PointGetPlan) + return ok && v.IndexInfo == nil +} + func init() { plannercore.OptimizeAstNode = Optimize } diff --git a/session/session.go b/session/session.go index a801298f9a..d2f770c44f 100644 --- a/session/session.go +++ b/session/session.go @@ -1146,6 +1146,7 @@ func (s *session) PrepareStmt(sql string) (stmtID uint32, paramCount int, fields // NewPrepareExec may need startTS to build the executor, for example prepare statement has subquery in int. // So we have to call PrepareTxnCtx here. s.PrepareTxnCtx(ctx) + s.PrepareTxnFuture(ctx) prepareExec := executor.NewPrepareExec(s, executor.GetInfoSchema(s), sql) err = prepareExec.Next(ctx, nil) if err != nil { @@ -1785,8 +1786,6 @@ func (s *session) PrepareTxnCtx(ctx context.Context) { return } - txnFuture := s.getTxnFuture(ctx) - s.txn.changeInvalidToPending(txnFuture) is := domain.GetDomain(s).InfoSchema() s.sessionVars.TxnCtx = &variable.TransactionContext{ InfoSchema: is, @@ -1807,6 +1806,16 @@ func (s *session) PrepareTxnCtx(ctx context.Context) { } } +// PrepareTxnFuture uses to try to get txn future. +func (s *session) PrepareTxnFuture(ctx context.Context) { + if s.txn.validOrPending() { + return + } + + txnFuture := s.getTxnFuture(ctx) + s.txn.changeInvalidToPending(txnFuture) +} + // RefreshTxnCtx implements context.RefreshTxnCtx interface. func (s *session) RefreshTxnCtx(ctx context.Context) error { if err := s.doCommit(ctx); err != nil { diff --git a/sessionctx/context.go b/sessionctx/context.go index 5589832918..97fd17948d 100644 --- a/sessionctx/context.go +++ b/sessionctx/context.go @@ -98,6 +98,8 @@ type Context interface { ReleaseAllTableLocks() // HasLockedTables uses to check whether this session locked any tables. HasLockedTables() bool + // PrepareTxnFuture uses to prepare txn by future. + PrepareTxnFuture(ctx context.Context) } type basicCtxType int diff --git a/util/mock/context.go b/util/mock/context.go index 31ddddb5fe..889b5b2fd6 100644 --- a/util/mock/context.go +++ b/util/mock/context.go @@ -247,6 +247,10 @@ func (c *Context) HasLockedTables() bool { return false } +// PrepareTxnFuture implements the sessionctx.Context interface. +func (c *Context) PrepareTxnFuture(ctx context.Context) { +} + // Close implements the sessionctx.Context interface. func (c *Context) Close() { }