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 }