github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/schemareplicant/perfschema/tables_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package perfschema_test
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"os"
    22  	"path/filepath"
    23  	"runtime"
    24  	"runtime/pprof"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    29  	. "github.com/whtcorpsinc/check"
    30  	"github.com/whtcorpsinc/failpoint"
    31  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    32  	"github.com/whtcorpsinc/milevadb/ekv"
    33  	"github.com/whtcorpsinc/milevadb/petri"
    34  	"github.com/whtcorpsinc/milevadb/schemareplicant/perfschema"
    35  	"github.com/whtcorpsinc/milevadb/soliton/testkit"
    36  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    37  	"github.com/whtcorpsinc/milevadb/stochastik"
    38  )
    39  
    40  func TestT(t *testing.T) {
    41  	CustomVerboseFlag = true
    42  	TestingT(t)
    43  }
    44  
    45  var _ = Suite(&testBlockSuite{})
    46  
    47  type testBlockSuite struct {
    48  	causetstore ekv.CausetStorage
    49  	dom         *petri.Petri
    50  }
    51  
    52  func (s *testBlockSuite) SetUpSuite(c *C) {
    53  	testleak.BeforeTest()
    54  
    55  	var err error
    56  	s.causetstore, err = mockstore.NewMockStore()
    57  	c.Assert(err, IsNil)
    58  	stochastik.DisableStats4Test()
    59  	s.dom, err = stochastik.BootstrapStochastik(s.causetstore)
    60  	c.Assert(err, IsNil)
    61  }
    62  
    63  func (s *testBlockSuite) TearDownSuite(c *C) {
    64  	defer testleak.AfterTest(c)()
    65  	s.dom.Close()
    66  	s.causetstore.Close()
    67  }
    68  
    69  func (s *testBlockSuite) TestPredefinedBlocks(c *C) {
    70  	c.Assert(perfschema.IsPredefinedBlock("EVENTS_memexs_summary_by_digest"), IsTrue)
    71  	c.Assert(perfschema.IsPredefinedBlock("memexs"), IsFalse)
    72  }
    73  
    74  func (s *testBlockSuite) TestPerfSchemaBlocks(c *C) {
    75  	tk := testkit.NewTestKit(c, s.causetstore)
    76  
    77  	tk.MustInterDirc("use performance_schema")
    78  	tk.MustQuery("select * from global_status where variable_name = 'Ssl_verify_mode'").Check(testkit.Events())
    79  	tk.MustQuery("select * from stochastik_status where variable_name = 'Ssl_verify_mode'").Check(testkit.Events())
    80  	tk.MustQuery("select * from setup_actors").Check(testkit.Events())
    81  	tk.MustQuery("select * from events_stages_history_long").Check(testkit.Events())
    82  }
    83  
    84  func currentSourceDir() string {
    85  	_, file, _, _ := runtime.Caller(0)
    86  	return filepath.Dir(file)
    87  }
    88  
    89  func (s *testBlockSuite) TestEinsteinDBProfileCPU(c *C) {
    90  	router := http.NewServeMux()
    91  	mockServer := httptest.NewServer(router)
    92  	mockAddr := strings.TrimPrefix(mockServer.URL, "http://")
    93  	defer mockServer.Close()
    94  
    95  	copyHandler := func(filename string) http.HandlerFunc {
    96  		return func(w http.ResponseWriter, _ *http.Request) {
    97  			file, err := os.Open(filepath.Join(currentSourceDir(), filename))
    98  			if err != nil {
    99  				http.Error(w, err.Error(), http.StatusBadRequest)
   100  				return
   101  			}
   102  			defer func() { terror.Log(file.Close()) }()
   103  			_, err = io.Copy(w, file)
   104  			terror.Log(err)
   105  		}
   106  	}
   107  	// mock einsteindb profile
   108  	router.HandleFunc("/debug/pprof/profile", copyHandler("testdata/einsteindb.cpu.profile"))
   109  
   110  	// failpoint setting
   111  	servers := []string{
   112  		strings.Join([]string{"einsteindb", mockAddr, mockAddr}, ","),
   113  		strings.Join([]string{"fidel", mockAddr, mockAddr}, ","),
   114  	}
   115  	fpExpr := strings.Join(servers, ";")
   116  	fpName := "github.com/whtcorpsinc/milevadb/schemareplicant/perfschema/mockRemoteNodeStatusAddress"
   117  	c.Assert(failpoint.Enable(fpName, fmt.Sprintf(`return("%s")`, fpExpr)), IsNil)
   118  	defer func() { c.Assert(failpoint.Disable(fpName), IsNil) }()
   119  
   120  	tk := testkit.NewTestKit(c, s.causetstore)
   121  
   122  	tk.MustInterDirc("use performance_schema")
   123  	result := tk.MustQuery("select function, percent_abs, percent_rel from einsteindb_profile_cpu where depth < 3")
   124  
   125  	warnings := tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   126  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   127  
   128  	result.Check(testkit.Events(
   129  		"root 100% 100%",
   130  		"├─einsteindb::server::load_statistics::linux::ThreadLoadStatistics::record::h59facb8d680e7794 75.00% 75.00%",
   131  		"│ └─procinfo::pid::stat::stat_task::h69e1aa2c331aebb6 75.00% 100%",
   132  		"├─nom::nom::digit::h905aaaeff7d8ec8e 16.07% 16.07%",
   133  		"│ ├─<embedded::iter::adapters::Enumerate<I> as embedded::iter::traits::iterator::Iterator>::next::h16936f9061bb75e4 6.25% 38.89%",
   134  		"│ ├─Unknown 3.57% 22.22%",
   135  		"│ ├─<&u8 as nom::traits::AsChar>::is_dec_digit::he9eacc3fad26ab81 2.68% 16.67%",
   136  		"│ ├─<&[u8] as nom::traits::InputIter>::iter_indices::h6192338433683bff 1.79% 11.11%",
   137  		"│ └─<&[T] as nom::traits::Slice<embedded::ops::range::RangeFrom<usize>>>::slice::h38d31f11f84aa302 1.79% 11.11%",
   138  		"├─<jemallocator::Jemalloc as embedded::alloc::GlobalAlloc>::realloc::h5199c50710ab6f9d 1.79% 1.79%",
   139  		"│ └─rallocx 1.79% 100%",
   140  		"├─<jemallocator::Jemalloc as embedded::alloc::GlobalAlloc>::dealloc::hea83459aa98dd2dc 1.79% 1.79%",
   141  		"│ └─sdallocx 1.79% 100%",
   142  		"├─<jemallocator::Jemalloc as embedded::alloc::GlobalAlloc>::alloc::hc7962e02169a5c56 0.89% 0.89%",
   143  		"│ └─mallocx 0.89% 100%",
   144  		"├─engine::rocks::soliton::engine_metrics::flush_engine_iostall_properties::h64a7661c95aa1db7 0.89% 0.89%",
   145  		"│ └─lmdb::lmdb::EDB::get_map_property_cf::h9722f9040411af44 0.89% 100%",
   146  		"├─embedded::ptr::real_drop_in_place::h8def0d99e7136f33 0.89% 0.89%",
   147  		"│ └─<alloc::raw_vec::RawVec<T,A> as embedded::ops::drop::Drop>::drop::h9b59b303bffde02c 0.89% 100%",
   148  		"├─einsteindb_util::metrics::threads_linux::ThreadInfoStatistics::record::ha8cc290b3f46af88 0.89% 0.89%",
   149  		"│ └─procinfo::pid::stat::stat_task::h69e1aa2c331aebb6 0.89% 100%",
   150  		"├─crossbeam_utils::backoff::Backoff::snooze::h5c121ef4ce616a3c 0.89% 0.89%",
   151  		"│ └─embedded::iter::range::<impl embedded::iter::traits::iterator::Iterator for embedded::ops::range::Range<A>>::next::hdb23ceb766e7a91f 0.89% 100%",
   152  		"└─<hashbrown::raw::bitmask::BitMaskIter as embedded::iter::traits::iterator::Iterator>::next::he129c78b3deb639d 0.89% 0.89%",
   153  		"  └─Unknown 0.89% 100%"))
   154  
   155  	// We can use current processe profile to mock profile of FIDel because the FIDel has the
   156  	// same way of retrieving profile with MilevaDB. And the purpose of this test case is used
   157  	// to make sure all profile HTTP API have been accessed.
   158  	accessed := map[string]struct{}{}
   159  	handlerFactory := func(name string, debug ...int) func(w http.ResponseWriter, _ *http.Request) {
   160  		debugLevel := 0
   161  		if len(debug) > 0 {
   162  			debugLevel = debug[0]
   163  		}
   164  		return func(w http.ResponseWriter, _ *http.Request) {
   165  			profile := pprof.Lookup(name)
   166  			if profile == nil {
   167  				http.Error(w, fmt.Sprintf("profile %s not found", name), http.StatusBadRequest)
   168  				return
   169  			}
   170  			if err := profile.WriteTo(w, debugLevel); err != nil {
   171  				http.Error(w, err.Error(), http.StatusBadRequest)
   172  				return
   173  			}
   174  			accessed[name] = struct{}{}
   175  		}
   176  	}
   177  
   178  	// mock FIDel profile
   179  	router.HandleFunc("/fidel/api/v1/debug/pprof/profile", copyHandler("../../soliton/profile/testdata/test.pprof"))
   180  	router.HandleFunc("/fidel/api/v1/debug/pprof/heap", handlerFactory("heap"))
   181  	router.HandleFunc("/fidel/api/v1/debug/pprof/mutex", handlerFactory("mutex"))
   182  	router.HandleFunc("/fidel/api/v1/debug/pprof/allocs", handlerFactory("allocs"))
   183  	router.HandleFunc("/fidel/api/v1/debug/pprof/causet", handlerFactory("causet"))
   184  	router.HandleFunc("/fidel/api/v1/debug/pprof/goroutine", handlerFactory("goroutine", 2))
   185  
   186  	tk.MustQuery("select * from FIDel_profile_cpu where depth < 3")
   187  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   188  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   189  
   190  	tk.MustQuery("select * from FIDel_profile_memory where depth < 3")
   191  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   192  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   193  
   194  	tk.MustQuery("select * from FIDel_profile_mutex where depth < 3")
   195  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   196  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   197  
   198  	tk.MustQuery("select * from FIDel_profile_allocs where depth < 3")
   199  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   200  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   201  
   202  	tk.MustQuery("select * from FIDel_profile_block where depth < 3")
   203  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   204  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   205  
   206  	tk.MustQuery("select * from FIDel_profile_goroutines")
   207  	warnings = tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   208  	c.Assert(len(warnings), Equals, 0, Commentf("expect no warnings, but found: %+v", warnings))
   209  
   210  	c.Assert(len(accessed), Equals, 5, Commentf("expect all HTTP API had been accessed, but found: %v", accessed))
   211  }