From 1643cc1e69721259484f135f985e788d6c6091b7 Mon Sep 17 00:00:00 2001 From: db-storage Date: Fri, 10 May 2019 19:38:14 +0800 Subject: [PATCH] Add support check for MAX_EXECUTION_TIME. - This feature is request by [Feature 7008](https://github.com/pingcap/tidb/issues/7008). - Add support for system variable "session.max_execution_time" and "global.max_execution_time". - Support hint in Select Statement linke: "SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1". - Add some unit test for the above(all tests passed). --- server/conn.go | 2 +- server/conn_test.go | 10 ++++++++++ server/driver.go | 2 -- session/session.go | 7 +++---- session/session_test.go | 26 ++++++++++++++++++++++++++ sessionctx/variable/session.go | 25 +++++++++++++++---------- 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/server/conn.go b/server/conn.go index 6e8b3f5108299..84128954ea45d 100644 --- a/server/conn.go +++ b/server/conn.go @@ -1302,9 +1302,9 @@ func (cc *clientConn) writeChunks(ctx context.Context, rs ResultSet, binary bool failpoint.Inject("SleepInwriteChunks", func(val failpoint.Value) { time.Sleep(time.Duration(val.(int)) * time.Millisecond) }) + //MaxExecDuration() return 0 if there is no limit if rs.MaxExecDuration().Nanoseconds() > 0 && time.Now().After(rs.StartExecTime().Add(rs.MaxExecDuration())) { - logutil.Logger(ctx).Warn("1907", zap.Int64("timeout:", rs.MaxExecDuration().Nanoseconds())) return errors.New("Query execution was interrupted, max_execution_time exceeded") } diff --git a/server/conn_test.go b/server/conn_test.go index 78efad2042d7f..ff18266cd9e1c 100644 --- a/server/conn_test.go +++ b/server/conn_test.go @@ -243,6 +243,16 @@ func (ts ConnTestSuite) TestConnExecutionTimeout(c *C) { _, err = se.Execute(context.Background(), "select * FROM tidb;") c.Assert(err, IsNil) + _, err = se.Execute(context.Background(), "select * FROM tidb;") + c.Assert(err, IsNil) + + _, err = se.Execute(context.Background(), "set @@max_execution_time = 100;") + c.Assert(err, IsNil) + + //session's max_execution_time has been set before + err = cc.handleQuery(context.Background(), "select * FROM tidb;") + c.Assert(err.Error(), Equals, errors.New("Query execution was interrupted, max_execution_time exceeded").Error()) + _, err = se.Execute(context.Background(), "set @@max_execution_time = 100;") c.Assert(err, IsNil) diff --git a/server/driver.go b/server/driver.go index 51d0e375684dd..1e1ea786d4376 100644 --- a/server/driver.go +++ b/server/driver.go @@ -141,8 +141,6 @@ type ResultSet interface { StoreFetchedRows(rows []chunk.Row) GetFetchedRows() []chunk.Row Close() error - // SetMaxExecDuration(time.Duration) MaxExecDuration() time.Duration - //SetStartExecTime(time.Time) StartExecTime() time.Time } diff --git a/session/session.go b/session/session.go index 1f2b38935b6d2..377254b0c8bf0 100644 --- a/session/session.go +++ b/session/session.go @@ -964,11 +964,10 @@ func (s *session) Execute(ctx context.Context, sql string) (recordSets []sqlexec } const ( - // TiDBMaxExecutionTime is currently used for selection Statement only - TiDBMaxExecutionTime = "max_execution_time" + // MaxExecutionTime is currently used for selection Statement only + MaxExecutionTime = "max_execution_time" ) -//exeutionHints contains only maxExecutionTime now, but there maybe more in the future type exeutionHints struct { maxExecutionTime uint64 } @@ -977,7 +976,7 @@ func (s *session) getExecutionHints(hints []*ast.TableOptimizerHint) (execHints execHints = &exeutionHints{maxExecutionTime: 0} for _, hint := range hints { switch hint.HintName.L { - case TiDBMaxExecutionTime: + case MaxExecutionTime: execHints.maxExecutionTime = hint.MaxExecutionTime default: } diff --git a/session/session_test.go b/session/session_test.go index 204c919155fc5..58cffb65265a1 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -2698,3 +2698,29 @@ func (s *testSessionSuite) TestGrantViewRelated(c *C) { tkUser.MustQuery("select current_user();").Check(testkit.Rows("u_version29@%")) tkUser.MustExec("create view v_version29_c as select * from v_version29;") } + +func (s *testSessionSuite) TestMaxExeucteTime(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + + tk.MustExec("create table MaxExecTime( id int,name varchar(128),age int);") + tk.MustExec("begin") + tk.MustExec("insert into MaxExecTime (id,name,age) values (1,'john',18),(2,'lary',19),(3,'lily',18);") + + tk.MustQuery("select @@MAX_EXECUTION_TIME;").Check(testkit.Rows("0")) + tk.MustQuery("select @@global.MAX_EXECUTION_TIME;").Check(testkit.Rows("0")) + tk.MustQuery("select /*+ MAX_EXECUTION_TIME(1000) */ * FROM MaxExecTime;") + + tk.MustExec("set @@global.MAX_EXECUTION_TIME = 300;") + tk.MustQuery("select * FROM MaxExecTime;") + + tk.MustExec("set @@MAX_EXECUTION_TIME = 150;") + tk.MustQuery("select * FROM MaxExecTime;") + + tk.MustQuery("select @@global.MAX_EXECUTION_TIME;").Check(testkit.Rows("300")) + tk.MustQuery("select @@MAX_EXECUTION_TIME;").Check(testkit.Rows("150")) + + tk.MustExec("set @@global.MAX_EXECUTION_TIME = 0;") + tk.MustExec("set @@MAX_EXECUTION_TIME = 0;") + tk.MustExec("commit") + tk.MustExec("drop table if exists MaxExecTime;") +} diff --git a/sessionctx/variable/session.go b/sessionctx/variable/session.go index 8ae1e8b9df33a..0921096660ead 100644 --- a/sessionctx/variable/session.go +++ b/sessionctx/variable/session.go @@ -111,7 +111,7 @@ type TransactionContext struct { TableDeltaMap map[int64]TableDelta IsPessimistic bool - // For metrics. + // CreateTime For metrics. CreateTime time.Time StatementCount int } @@ -205,15 +205,14 @@ type SessionVars struct { PreparedStmtNameToID map[string]uint32 // preparedStmtID is id of prepared statement. preparedStmtID uint32 - // params for prepared statements + // PreparedParams params for prepared statements PreparedParams []types.Datum // ActiveRoles stores active roles for current user ActiveRoles []*auth.RoleIdentity - // retry information RetryInfo *RetryInfo - // Should be reset on transaction finished. + // TxnCtx Should be reset on transaction finished. TxnCtx *TransactionContext // KVVars is the variables for KV storage. @@ -221,9 +220,9 @@ type SessionVars struct { // TxnIsolationLevelOneShot is used to implements "set transaction isolation level ..." TxnIsolationLevelOneShot struct { - // state 0 means default - // state 1 means it's set in current transaction. - // state 2 means it should be used in current transaction. + // State 0 means default + // State 1 means it's set in current transaction. + // State 2 means it should be used in current transaction. State int Value string } @@ -364,7 +363,7 @@ type SessionVars struct { // CommandValue indicates which command current session is doing. CommandValue uint32 - // TIDBOptJoinOrderAlgoThreshold defines the minimal number of join nodes + // TiDBOptJoinReorderThreshold defines the minimal number of join nodes // to use the greedy join reorder algorithm. TiDBOptJoinReorderThreshold int @@ -380,6 +379,8 @@ type SessionVars struct { MaxExecutionTime uint64 // LowResolutionTSO is used for reading data with low resolution TSO which is updated once every two seconds. LowResolutionTSO bool + // PessimisticLock indicates whether new transaction should be pessimistic . + PessimisticLock bool } // ConnectionInfo present connection used by audit. @@ -690,7 +691,11 @@ func (s *SessionVars) SetSystemVar(name string, val string) error { s.SetStatusFlag(mysql.ServerStatusInTrans, false) } case MaxExecutionTime: - s.MaxExecutionTime = uint64(tidbOptInt64(val, 0)) + timeoutMS := tidbOptInt64(val, 0) + if timeoutMS < 0 { + timeoutMS = 0 + } + s.MaxExecutionTime = uint64(timeoutMS) case TiDBSkipUTF8Check: s.SkipUTF8Check = TiDBOptOn(val) case TiDBOptAggPushDown: @@ -890,7 +895,7 @@ type Concurrency struct { // HashAggPartialConcurrency is the number of concurrent hash aggregation partial worker. HashAggPartialConcurrency int - // HashAggPartialConcurrency is the number of concurrent hash aggregation final worker. + // HashAggFinalConcurrency is the number of concurrent hash aggregation final worker. HashAggFinalConcurrency int // IndexSerialScanConcurrency is the number of concurrent index serial scan worker.