From ec8351ca9a6cbc04e84ae8d01ab3770802b45cd5 Mon Sep 17 00:00:00 2001 From: Chengpeng Yan <41809508+Reminiscent@users.noreply.github.com> Date: Tue, 3 Aug 2021 16:47:07 +0800 Subject: [PATCH] bindinfo: add status vars for 'last_plan_binding_update_time' (#26340) --- bindinfo/bind_test.go | 28 ++++++++++++++++++++++++++++ bindinfo/handle.go | 1 + bindinfo/stat.go | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 bindinfo/stat.go diff --git a/bindinfo/bind_test.go b/bindinfo/bind_test.go index 256c1be1ec036..e168122354e3b 100644 --- a/bindinfo/bind_test.go +++ b/bindinfo/bind_test.go @@ -2132,3 +2132,31 @@ func (s *testSuite) TestTemporaryTable(c *C) { tk.MustGetErrCode("create binding for update t set a = 1 where b = 1 and c > 1 using update /*+ use_index(t, c) */ t set a = 1 where b = 1 and c > 1", errno.ErrOptOnTemporaryTable) tk.MustGetErrCode("create binding for delete from t where b = 1 and c > 1 using delete /*+ use_index(t, c) */ from t where b = 1 and c > 1", errno.ErrOptOnTemporaryTable) } + +func (s *testSuite) TestBindingLastUpdateTime(c *C) { + tk := testkit.NewTestKit(c, s.store) + s.cleanBindingEnv(tk) + tk.MustExec("use test") + tk.MustExec("drop table if exists t0;") + tk.MustExec("create table t0(a int, key(a));") + tk.MustExec("create global binding for select * from t0 using select * from t0 use index(a);") + tk.MustExec("admin reload bindings;") + + bindHandle := bindinfo.NewBindHandle(tk.Se) + err := bindHandle.Update(true) + c.Check(err, IsNil) + sql, hash := parser.NormalizeDigest("select * from test . t0") + bindData := bindHandle.GetBindRecord(hash.String(), sql, "test") + c.Assert(len(bindData.Bindings), Equals, 1) + bind := bindData.Bindings[0] + updateTime := bind.UpdateTime.String() + + rows1 := tk.MustQuery("show status like 'last_plan_binding_update_time';").Rows() + updateTime1 := rows1[0][1] + c.Assert(updateTime1, Equals, updateTime) + + rows2 := tk.MustQuery("show session status like 'last_plan_binding_update_time';").Rows() + updateTime2 := rows2[0][1] + c.Assert(updateTime2, Equals, updateTime) + tk.MustQuery(`show global status like 'last_plan_binding_update_time';`).Check(testkit.Rows()) +} diff --git a/bindinfo/handle.go b/bindinfo/handle.go index 2281af3c88bd3..a69c0638d2dc3 100644 --- a/bindinfo/handle.go +++ b/bindinfo/handle.go @@ -114,6 +114,7 @@ func NewBindHandle(ctx sessionctx.Context) *BindHandle { // BindSQL has already been validated when coming here, so we use nil sctx parameter. return handle.AddBindRecord(nil, record) } + variable.RegisterStatistics(handle) return handle } diff --git a/bindinfo/stat.go b/bindinfo/stat.go new file mode 100644 index 0000000000000..aea98669002d1 --- /dev/null +++ b/bindinfo/stat.go @@ -0,0 +1,39 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package bindinfo + +import ( + "github.com/pingcap/tidb/sessionctx/variable" +) + +var ( + lastPlanBindingUpdateTime = "last_plan_binding_update_time" +) + +// GetScope gets the status variables scope. +func (h *BindHandle) GetScope(status string) variable.ScopeFlag { + return variable.ScopeSession +} + +// Stats returns the server statistics. +func (h *BindHandle) Stats(vars *variable.SessionVars) (map[string]interface{}, error) { + h.bindInfo.Lock() + defer func() { + h.bindInfo.Unlock() + }() + m := make(map[string]interface{}) + m[lastPlanBindingUpdateTime] = h.bindInfo.lastUpdateTime.String() + + return m, nil +}