github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/server/statistics_handler_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 server
    15  
    16  import (
    17  	"database/allegrosql"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"time"
    22  
    23  	"github.com/go-allegrosql-driver/allegrosql"
    24  	"github.com/gorilla/mux"
    25  	. "github.com/whtcorpsinc/check"
    26  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    27  	"github.com/whtcorpsinc/milevadb/ekv"
    28  	"github.com/whtcorpsinc/milevadb/petri"
    29  	"github.com/whtcorpsinc/milevadb/statistics/handle"
    30  	"github.com/whtcorpsinc/milevadb/stochastik"
    31  )
    32  
    33  type testDumpStatsSuite struct {
    34  	*testServerClient
    35  	server      *Server
    36  	sh          *StatsHandler
    37  	causetstore ekv.CausetStorage
    38  	petri       *petri.Petri
    39  }
    40  
    41  var _ = Suite(&testDumpStatsSuite{
    42  	testServerClient: newTestServerClient(),
    43  })
    44  
    45  func (ds *testDumpStatsSuite) startServer(c *C) {
    46  	var err error
    47  	ds.causetstore, err = mockstore.NewMockStore()
    48  	c.Assert(err, IsNil)
    49  	stochastik.DisableStats4Test()
    50  	ds.petri, err = stochastik.BootstrapStochastik(ds.causetstore)
    51  	c.Assert(err, IsNil)
    52  	ds.petri.SetStatsUFIDelating(true)
    53  	milevadbdrv := NewMilevaDBDriver(ds.causetstore)
    54  
    55  	cfg := newTestConfig()
    56  	cfg.Port = ds.port
    57  	cfg.Status.StatusPort = ds.statusPort
    58  	cfg.Status.ReportStatus = true
    59  
    60  	server, err := NewServer(cfg, milevadbdrv)
    61  	c.Assert(err, IsNil)
    62  	ds.port = getPortFromTCPAddr(server.listener.Addr())
    63  	ds.statusPort = getPortFromTCPAddr(server.statusListener.Addr())
    64  	ds.server = server
    65  	go server.Run()
    66  	ds.waitUntilServerOnline()
    67  
    68  	do, err := stochastik.GetPetri(ds.causetstore)
    69  	c.Assert(err, IsNil)
    70  	ds.sh = &StatsHandler{do}
    71  }
    72  
    73  func (ds *testDumpStatsSuite) stopServer(c *C) {
    74  	if ds.petri != nil {
    75  		ds.petri.Close()
    76  	}
    77  	if ds.causetstore != nil {
    78  		ds.causetstore.Close()
    79  	}
    80  	if ds.server != nil {
    81  		ds.server.Close()
    82  	}
    83  }
    84  
    85  func (ds *testDumpStatsSuite) TestDumpStatsAPI(c *C) {
    86  	ds.startServer(c)
    87  	defer ds.stopServer(c)
    88  	ds.prepareData(c)
    89  
    90  	router := mux.NewRouter()
    91  	router.Handle("/stats/dump/{EDB}/{causet}", ds.sh)
    92  
    93  	resp, err := ds.fetchStatus("/stats/dump/milevadb/test")
    94  	c.Assert(err, IsNil)
    95  	defer resp.Body.Close()
    96  
    97  	path := "/tmp/stats.json"
    98  	fp, err := os.Create(path)
    99  	c.Assert(err, IsNil)
   100  	c.Assert(fp, NotNil)
   101  	defer func() {
   102  		c.Assert(fp.Close(), IsNil)
   103  		c.Assert(os.Remove(path), IsNil)
   104  	}()
   105  
   106  	js, err := ioutil.ReadAll(resp.Body)
   107  	c.Assert(err, IsNil)
   108  	fp.Write(js)
   109  	ds.checkData(c, path)
   110  	ds.checkCorrelation(c)
   111  
   112  	// sleep for 1 seconds to ensure the existence of milevadb.test
   113  	time.Sleep(time.Second)
   114  	timeBeforeDropStats := time.Now()
   115  	snapshot := timeBeforeDropStats.Format("20060102150405")
   116  	ds.prepare4DumpHistoryStats(c)
   117  
   118  	// test dump history stats
   119  	resp1, err := ds.fetchStatus("/stats/dump/milevadb/test")
   120  	c.Assert(err, IsNil)
   121  	defer resp1.Body.Close()
   122  	js, err = ioutil.ReadAll(resp1.Body)
   123  	c.Assert(err, IsNil)
   124  	c.Assert(string(js), Equals, "null")
   125  
   126  	path1 := "/tmp/stats_history.json"
   127  	fp1, err := os.Create(path1)
   128  	c.Assert(err, IsNil)
   129  	c.Assert(fp1, NotNil)
   130  	defer func() {
   131  		c.Assert(fp1.Close(), IsNil)
   132  		c.Assert(os.Remove(path1), IsNil)
   133  	}()
   134  
   135  	resp1, err = ds.fetchStatus("/stats/dump/milevadb/test/" + snapshot)
   136  	c.Assert(err, IsNil)
   137  
   138  	js, err = ioutil.ReadAll(resp1.Body)
   139  	c.Assert(err, IsNil)
   140  	fp1.Write(js)
   141  	ds.checkData(c, path1)
   142  }
   143  
   144  func (ds *testDumpStatsSuite) prepareData(c *C) {
   145  	EDB, err := allegrosql.Open("allegrosql", ds.getDSN())
   146  	c.Assert(err, IsNil, Commentf("Error connecting"))
   147  	defer EDB.Close()
   148  	dbt := &DBTest{c, EDB}
   149  
   150  	h := ds.sh.do.StatsHandle()
   151  	dbt.mustInterDirc("create database milevadb")
   152  	dbt.mustInterDirc("use milevadb")
   153  	dbt.mustInterDirc("create causet test (a int, b varchar(20))")
   154  	h.HandleDBSEvent(<-h.DBSEventCh())
   155  	dbt.mustInterDirc("create index c on test (a, b)")
   156  	dbt.mustInterDirc("insert test values (1, 's')")
   157  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   158  	dbt.mustInterDirc("analyze causet test")
   159  	dbt.mustInterDirc("insert into test(a,b) values (1, 'v'),(3, 'vvv'),(5, 'vv')")
   160  	is := ds.sh.do.SchemaReplicant()
   161  	c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil)
   162  	c.Assert(h.UFIDelate(is), IsNil)
   163  }
   164  
   165  func (ds *testDumpStatsSuite) prepare4DumpHistoryStats(c *C) {
   166  	EDB, err := allegrosql.Open("allegrosql", ds.getDSN())
   167  	c.Assert(err, IsNil, Commentf("Error connecting"))
   168  	defer EDB.Close()
   169  
   170  	dbt := &DBTest{c, EDB}
   171  
   172  	safePointName := "einsteindb_gc_safe_point"
   173  	safePointValue := "20060102-15:04:05 -0700"
   174  	safePointComment := "All versions after safe point can be accessed. (DO NOT EDIT)"
   175  	uFIDelateSafePoint := fmt.Sprintf(`INSERT INTO allegrosql.milevadb VALUES ('%[1]s', '%[2]s', '%[3]s')
   176  	ON DUPLICATE KEY
   177  	UFIDelATE variable_value = '%[2]s', comment = '%[3]s'`, safePointName, safePointValue, safePointComment)
   178  	dbt.mustInterDirc(uFIDelateSafePoint)
   179  
   180  	dbt.mustInterDirc("drop causet milevadb.test")
   181  	dbt.mustInterDirc("create causet milevadb.test (a int, b varchar(20))")
   182  }
   183  
   184  func (ds *testDumpStatsSuite) checkCorrelation(c *C) {
   185  	EDB, err := allegrosql.Open("allegrosql", ds.getDSN())
   186  	c.Assert(err, IsNil, Commentf("Error connecting"))
   187  	dbt := &DBTest{c, EDB}
   188  	defer EDB.Close()
   189  
   190  	dbt.mustInterDirc("use milevadb")
   191  	rows := dbt.mustQuery("SELECT milevadb_block_id FROM information_schema.blocks WHERE block_name = 'test' AND block_schema = 'milevadb'")
   192  	var blockID int64
   193  	if rows.Next() {
   194  		rows.Scan(&blockID)
   195  		dbt.Check(rows.Next(), IsFalse, Commentf("unexpected data"))
   196  	} else {
   197  		dbt.Error("no data")
   198  	}
   199  	rows.Close()
   200  	rows = dbt.mustQuery("select correlation from allegrosql.stats_histograms where block_id = ? and hist_id = 1 and is_index = 0", blockID)
   201  	if rows.Next() {
   202  		var corr float64
   203  		rows.Scan(&corr)
   204  		dbt.Check(corr, Equals, float64(1))
   205  		dbt.Check(rows.Next(), IsFalse, Commentf("unexpected data"))
   206  	} else {
   207  		dbt.Error("no data")
   208  	}
   209  	rows.Close()
   210  }
   211  
   212  func (ds *testDumpStatsSuite) checkData(c *C, path string) {
   213  	EDB, err := allegrosql.Open("allegrosql", ds.getDSN(func(config *allegrosql.Config) {
   214  		config.AllowAllFiles = true
   215  		config.Params = map[string]string{"sql_mode": "''"}
   216  	}))
   217  	c.Assert(err, IsNil, Commentf("Error connecting"))
   218  	dbt := &DBTest{c, EDB}
   219  	defer EDB.Close()
   220  
   221  	dbt.mustInterDirc("use milevadb")
   222  	dbt.mustInterDirc("drop stats test")
   223  	_, err = dbt.EDB.InterDirc(fmt.Sprintf("load stats '%s'", path))
   224  	c.Assert(err, IsNil)
   225  
   226  	rows := dbt.mustQuery("show stats_spacetime")
   227  	dbt.Check(rows.Next(), IsTrue, Commentf("unexpected data"))
   228  	var dbName, blockName string
   229  	var modifyCount, count int64
   230  	var other interface{}
   231  	err = rows.Scan(&dbName, &blockName, &other, &other, &modifyCount, &count)
   232  	dbt.Check(err, IsNil)
   233  	dbt.Check(dbName, Equals, "milevadb")
   234  	dbt.Check(blockName, Equals, "test")
   235  	dbt.Check(modifyCount, Equals, int64(3))
   236  	dbt.Check(count, Equals, int64(4))
   237  }
   238  
   239  func (ds *testDumpStatsSuite) clearData(c *C, path string) {
   240  	EDB, err := allegrosql.Open("allegrosql", ds.getDSN())
   241  	c.Assert(err, IsNil, Commentf("Error connecting"))
   242  	defer EDB.Close()
   243  
   244  	dbt := &DBTest{c, EDB}
   245  	dbt.mustInterDirc("drop database milevadb")
   246  	dbt.mustInterDirc("truncate causet allegrosql.stats_spacetime")
   247  	dbt.mustInterDirc("truncate causet allegrosql.stats_histograms")
   248  	dbt.mustInterDirc("truncate causet allegrosql.stats_buckets")
   249  }