github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/petri_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 petri 15 16 import ( 17 "context" 18 "crypto/tls" 19 "math" 20 "net" 21 "runtime" 22 "testing" 23 "time" 24 25 "github.com/ngaut/pools" 26 dto "github.com/prometheus/client_perceptron/go" 27 "github.com/whtcorpsinc/BerolinaSQL/ast" 28 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 29 "github.com/whtcorpsinc/BerolinaSQL/terror" 30 . "github.com/whtcorpsinc/check" 31 "github.com/whtcorpsinc/errors" 32 "github.com/whtcorpsinc/failpoint" 33 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle" 34 "github.com/whtcorpsinc/milevadb/causetstore/mockstore" 35 "github.com/whtcorpsinc/milevadb/dbs" 36 "github.com/whtcorpsinc/milevadb/ekv" 37 "github.com/whtcorpsinc/milevadb/errno" 38 "github.com/whtcorpsinc/milevadb/metrics" 39 "github.com/whtcorpsinc/milevadb/petri/infosync" 40 "github.com/whtcorpsinc/milevadb/soliton" 41 "github.com/whtcorpsinc/milevadb/soliton/mock" 42 "github.com/whtcorpsinc/milevadb/soliton/testleak" 43 "github.com/whtcorpsinc/milevadb/spacetime" 44 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 45 "go.etcd.io/etcd/integration" 46 ) 47 48 func TestT(t *testing.T) { 49 CustomVerboseFlag = true 50 TestingT(t) 51 } 52 53 var _ = Suite(&testSuite{}) 54 55 type testSuite struct { 56 } 57 58 func mockFactory() (pools.Resource, error) { 59 return nil, errors.New("mock factory should not be called") 60 } 61 62 func sysMockFactory(dom *Petri) (pools.Resource, error) { 63 return nil, nil 64 } 65 66 type mockEtcdBackend struct { 67 ekv.CausetStorage 68 FIDelAddrs []string 69 } 70 71 func (mebd *mockEtcdBackend) EtcdAddrs() ([]string, error) { 72 return mebd.FIDelAddrs, nil 73 } 74 func (mebd *mockEtcdBackend) TLSConfig() *tls.Config { return nil } 75 func (mebd *mockEtcdBackend) StartGCWorker() error { 76 panic("not implemented") 77 } 78 79 // ETCD use ip:port as unix socket address, however this address is invalid on windows. 80 // We have to skip some of the test in such case. 81 // https://github.com/etcd-io/etcd/blob/f0faa5501d936cd8c9f561bb9d1baca70eb67ab1/pkg/types/urls.go#L42 82 func unixSocketAvailable() bool { 83 c, err := net.Listen("unix", "127.0.0.1:0") 84 if err == nil { 85 c.Close() 86 return true 87 } 88 return false 89 } 90 91 func TestInfo(t *testing.T) { 92 if runtime.GOOS == "windows" { 93 t.Skip("integration.NewClusterV3 will create file contains a defCauson which is not allowed on Windows") 94 } 95 if !unixSocketAvailable() { 96 return 97 } 98 testleak.BeforeTest() 99 defer testleak.AfterTestT(t)() 100 dbsLease := 80 * time.Millisecond 101 s, err := mockstore.NewMockStore() 102 if err != nil { 103 t.Fatal(err) 104 } 105 clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1}) 106 defer clus.Terminate(t) 107 mockStore := &mockEtcdBackend{ 108 CausetStorage: s, 109 FIDelAddrs: []string{clus.Members[0].GRPCAddr()}} 110 dom := NewPetri(mockStore, dbsLease, 0, 0, mockFactory) 111 defer func() { 112 dom.Close() 113 s.Close() 114 }() 115 116 cli := clus.RandClient() 117 dom.etcdClient = cli 118 // Mock new DBS and init the schemaReplicant syncer with etcd client. 119 goCtx := context.Background() 120 dom.dbs = dbs.NewDBS( 121 goCtx, 122 dbs.WithEtcdClient(dom.GetEtcdClient()), 123 dbs.WithStore(s), 124 dbs.WithInfoHandle(dom.infoHandle), 125 dbs.WithLease(dbsLease), 126 ) 127 err = dom.dbs.Start(nil) 128 if err != nil { 129 t.Fatal(err) 130 } 131 err = failpoint.Enable("github.com/whtcorpsinc/milevadb/petri/MockReplaceDBS", `return(true)`) 132 if err != nil { 133 t.Fatal(err) 134 } 135 err = dom.Init(dbsLease, sysMockFactory) 136 if err != nil { 137 t.Fatal(err) 138 } 139 err = failpoint.Disable("github.com/whtcorpsinc/milevadb/petri/MockReplaceDBS") 140 if err != nil { 141 t.Fatal(err) 142 } 143 144 // Test for GetServerInfo and GetServerInfoByID. 145 dbsID := dom.dbs.GetID() 146 serverInfo, err := infosync.GetServerInfo() 147 if err != nil { 148 t.Fatal(err) 149 } 150 info, err := infosync.GetServerInfoByID(goCtx, dbsID) 151 if err != nil { 152 t.Fatal(err) 153 } 154 if serverInfo.ID != info.ID { 155 t.Fatalf("server self info %v, info %v", serverInfo, info) 156 } 157 _, err = infosync.GetServerInfoByID(goCtx, "not_exist_id") 158 if err == nil || (err != nil && err.Error() != "[info-syncer] get /milevadb/server/info/not_exist_id failed") { 159 t.Fatal(err) 160 } 161 162 // Test for GetAllServerInfo. 163 infos, err := infosync.GetAllServerInfo(goCtx) 164 if err != nil { 165 t.Fatal(err) 166 } 167 if len(infos) != 1 || infos[dbsID].ID != info.ID { 168 t.Fatalf("server one info %v, info %v", infos[dbsID], info) 169 } 170 171 // Test the scene where syncer.Done() gets the information. 172 err = failpoint.Enable("github.com/whtcorpsinc/milevadb/dbs/soliton/ErrorMockStochastikDone", `return(true)`) 173 if err != nil { 174 t.Fatal(err) 175 } 176 <-dom.dbs.SchemaSyncer().Done() 177 err = failpoint.Disable("github.com/whtcorpsinc/milevadb/dbs/soliton/ErrorMockStochastikDone") 178 if err != nil { 179 t.Fatal(err) 180 } 181 time.Sleep(15 * time.Millisecond) 182 syncerStarted := false 183 for i := 0; i < 1000; i++ { 184 if dom.SchemaValidator.IsStarted() { 185 syncerStarted = true 186 break 187 } 188 time.Sleep(5 * time.Millisecond) 189 } 190 if !syncerStarted { 191 t.Fatal("start syncer failed") 192 } 193 // Make sure loading schemaReplicant is normal. 194 cs := &ast.CharsetOpt{ 195 Chs: "utf8", 196 DefCaus: "utf8_bin", 197 } 198 ctx := mock.NewContext() 199 err = dom.dbs.CreateSchema(ctx, perceptron.NewCIStr("aaa"), cs) 200 if err != nil { 201 t.Fatal(err) 202 } 203 err = dom.Reload() 204 if err != nil { 205 t.Fatal(err) 206 } 207 if dom.SchemaReplicant().SchemaMetaVersion() != 1 { 208 t.Fatalf("uFIDelate schemaReplicant version failed, ver %d", dom.SchemaReplicant().SchemaMetaVersion()) 209 } 210 211 // Test for RemoveServerInfo. 212 dom.info.RemoveServerInfo() 213 infos, err = infosync.GetAllServerInfo(goCtx) 214 if err != nil || len(infos) != 0 { 215 t.Fatalf("err %v, infos %v", err, infos) 216 } 217 } 218 219 type mockStochastikManager struct { 220 PS []*soliton.ProcessInfo 221 } 222 223 func (msm *mockStochastikManager) ShowProcessList() map[uint64]*soliton.ProcessInfo { 224 ret := make(map[uint64]*soliton.ProcessInfo) 225 for _, item := range msm.PS { 226 ret[item.ID] = item 227 } 228 return ret 229 } 230 231 func (msm *mockStochastikManager) GetProcessInfo(id uint64) (*soliton.ProcessInfo, bool) { 232 for _, item := range msm.PS { 233 if item.ID == id { 234 return item, true 235 } 236 } 237 return &soliton.ProcessInfo{}, false 238 } 239 240 func (msm *mockStochastikManager) Kill(cid uint64, query bool) {} 241 242 func (msm *mockStochastikManager) UFIDelateTLSConfig(cfg *tls.Config) {} 243 244 func (*testSuite) TestT(c *C) { 245 defer testleak.AfterTest(c)() 246 causetstore, err := mockstore.NewMockStore() 247 c.Assert(err, IsNil) 248 dbsLease := 80 * time.Millisecond 249 dom := NewPetri(causetstore, dbsLease, 0, 0, mockFactory) 250 err = dom.Init(dbsLease, sysMockFactory) 251 c.Assert(err, IsNil) 252 ctx := mock.NewContext() 253 ctx.CausetStore = dom.CausetStore() 254 dd := dom.DBS() 255 c.Assert(dd, NotNil) 256 c.Assert(dd.GetLease(), Equals, 80*time.Millisecond) 257 258 snapTS := oracle.EncodeTSO(oracle.GetPhysical(time.Now())) 259 cs := &ast.CharsetOpt{ 260 Chs: "utf8", 261 DefCaus: "utf8_bin", 262 } 263 err = dd.CreateSchema(ctx, perceptron.NewCIStr("aaa"), cs) 264 c.Assert(err, IsNil) 265 // Test for fetchSchemasWithBlocks when "blocks" isn't nil. 266 err = dd.CreateBlock(ctx, &ast.CreateBlockStmt{Block: &ast.BlockName{ 267 Schema: perceptron.NewCIStr("aaa"), 268 Name: perceptron.NewCIStr("tbl")}}) 269 c.Assert(err, IsNil) 270 is := dom.SchemaReplicant() 271 c.Assert(is, NotNil) 272 273 // for uFIDelating the self schemaReplicant version 274 goCtx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 275 err = dd.SchemaSyncer().TenantCheckAllVersions(goCtx, is.SchemaMetaVersion()) 276 cancel() 277 c.Assert(err, IsNil) 278 snapIs, err := dom.GetSnapshotSchemaReplicant(snapTS) 279 c.Assert(snapIs, NotNil) 280 c.Assert(err, IsNil) 281 // Make sure that the self schemaReplicant version doesn't be changed. 282 goCtx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond) 283 err = dd.SchemaSyncer().TenantCheckAllVersions(goCtx, is.SchemaMetaVersion()) 284 cancel() 285 c.Assert(err, IsNil) 286 287 // for GetSnapshotSchemaReplicant 288 currSnapTS := oracle.EncodeTSO(oracle.GetPhysical(time.Now())) 289 currSnapIs, err := dom.GetSnapshotSchemaReplicant(currSnapTS) 290 c.Assert(err, IsNil) 291 c.Assert(currSnapIs, NotNil) 292 c.Assert(currSnapIs.SchemaMetaVersion(), Equals, is.SchemaMetaVersion()) 293 294 // for GetSnapshotMeta 295 dbInfo, ok := currSnapIs.SchemaByName(perceptron.NewCIStr("aaa")) 296 c.Assert(ok, IsTrue) 297 tbl, err := currSnapIs.BlockByName(perceptron.NewCIStr("aaa"), perceptron.NewCIStr("tbl")) 298 c.Assert(err, IsNil) 299 m, err := dom.GetSnapshotMeta(snapTS) 300 c.Assert(err, IsNil) 301 tblInfo1, err := m.GetBlock(dbInfo.ID, tbl.Meta().ID) 302 c.Assert(spacetime.ErrDBNotExists.Equal(err), IsTrue) 303 c.Assert(tblInfo1, IsNil) 304 m, err = dom.GetSnapshotMeta(currSnapTS) 305 c.Assert(err, IsNil) 306 tblInfo2, err := m.GetBlock(dbInfo.ID, tbl.Meta().ID) 307 c.Assert(err, IsNil) 308 c.Assert(tbl.Meta(), DeepEquals, tblInfo2) 309 310 // Test for tryLoadSchemaDiffs when "isTooOldSchema" is false. 311 err = dd.CreateSchema(ctx, perceptron.NewCIStr("bbb"), cs) 312 c.Assert(err, IsNil) 313 err = dom.Reload() 314 c.Assert(err, IsNil) 315 316 // for schemaValidator 317 schemaVer := dom.SchemaValidator.(*schemaValidator).LatestSchemaVersion() 318 ver, err := causetstore.CurrentVersion() 319 c.Assert(err, IsNil) 320 ts := ver.Ver 321 322 _, succ := dom.SchemaValidator.Check(ts, schemaVer, nil) 323 c.Assert(succ, Equals, ResultSucc) 324 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/petri/ErrorMockReloadFailed", `return(true)`), IsNil) 325 err = dom.Reload() 326 c.Assert(err, NotNil) 327 _, succ = dom.SchemaValidator.Check(ts, schemaVer, nil) 328 c.Assert(succ, Equals, ResultSucc) 329 time.Sleep(dbsLease) 330 331 ver, err = causetstore.CurrentVersion() 332 c.Assert(err, IsNil) 333 ts = ver.Ver 334 _, succ = dom.SchemaValidator.Check(ts, schemaVer, nil) 335 c.Assert(succ, Equals, ResultUnknown) 336 c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/petri/ErrorMockReloadFailed"), IsNil) 337 err = dom.Reload() 338 c.Assert(err, IsNil) 339 _, succ = dom.SchemaValidator.Check(ts, schemaVer, nil) 340 c.Assert(succ, Equals, ResultSucc) 341 342 // For slow query. 343 dom.LogSlowQuery(&SlowQueryInfo{ALLEGROALLEGROSQL: "aaa", Duration: time.Second, Internal: true}) 344 dom.LogSlowQuery(&SlowQueryInfo{ALLEGROALLEGROSQL: "bbb", Duration: 3 * time.Second}) 345 dom.LogSlowQuery(&SlowQueryInfo{ALLEGROALLEGROSQL: "ccc", Duration: 2 * time.Second}) 346 // DefCauslecting slow queries is asynchronous, wait a while to ensure it's done. 347 time.Sleep(5 * time.Millisecond) 348 349 res := dom.ShowSlowQuery(&ast.ShowSlow{Tp: ast.ShowSlowTop, Count: 2}) 350 c.Assert(res, HasLen, 2) 351 c.Assert(res[0].ALLEGROALLEGROSQL, Equals, "bbb") 352 c.Assert(res[0].Duration, Equals, 3*time.Second) 353 c.Assert(res[1].ALLEGROALLEGROSQL, Equals, "ccc") 354 c.Assert(res[1].Duration, Equals, 2*time.Second) 355 356 res = dom.ShowSlowQuery(&ast.ShowSlow{Tp: ast.ShowSlowTop, Count: 2, HoTT: ast.ShowSlowHoTTInternal}) 357 c.Assert(res, HasLen, 1) 358 c.Assert(res[0].ALLEGROALLEGROSQL, Equals, "aaa") 359 c.Assert(res[0].Duration, Equals, time.Second) 360 c.Assert(res[0].Internal, Equals, true) 361 362 res = dom.ShowSlowQuery(&ast.ShowSlow{Tp: ast.ShowSlowTop, Count: 4, HoTT: ast.ShowSlowHoTTAll}) 363 c.Assert(res, HasLen, 3) 364 c.Assert(res[0].ALLEGROALLEGROSQL, Equals, "bbb") 365 c.Assert(res[0].Duration, Equals, 3*time.Second) 366 c.Assert(res[1].ALLEGROALLEGROSQL, Equals, "ccc") 367 c.Assert(res[1].Duration, Equals, 2*time.Second) 368 c.Assert(res[2].ALLEGROALLEGROSQL, Equals, "aaa") 369 c.Assert(res[2].Duration, Equals, time.Second) 370 c.Assert(res[2].Internal, Equals, true) 371 372 res = dom.ShowSlowQuery(&ast.ShowSlow{Tp: ast.ShowSlowRecent, Count: 2}) 373 c.Assert(res, HasLen, 2) 374 c.Assert(res[0].ALLEGROALLEGROSQL, Equals, "ccc") 375 c.Assert(res[0].Duration, Equals, 2*time.Second) 376 c.Assert(res[1].ALLEGROALLEGROSQL, Equals, "bbb") 377 c.Assert(res[1].Duration, Equals, 3*time.Second) 378 379 metrics.PanicCounter.Reset() 380 // Since the stats lease is 0 now, so create a new ticker will panic. 381 // Test that they can recover from panic correctly. 382 dom.uFIDelateStatsWorker(ctx, nil) 383 dom.autoAnalyzeWorker(nil) 384 counter := metrics.PanicCounter.WithLabelValues(metrics.LabelPetri) 385 pb := &dto.Metric{} 386 counter.Write(pb) 387 c.Assert(pb.GetCounter().GetValue(), Equals, float64(2)) 388 389 scope := dom.GetScope("status") 390 c.Assert(scope, Equals, variable.DefaultStatusVarScopeFlag) 391 392 // For schemaReplicant check, it tests for getting the result of "ResultUnknown". 393 schemaChecker := NewSchemaChecker(dom, is.SchemaMetaVersion(), nil) 394 originalRetryTime := SchemaOutOfDateRetryTimes 395 originalRetryInterval := SchemaOutOfDateRetryInterval 396 // Make sure it will retry one time and doesn't take a long time. 397 SchemaOutOfDateRetryTimes = 1 398 SchemaOutOfDateRetryInterval = int64(time.Millisecond * 1) 399 defer func() { 400 SchemaOutOfDateRetryTimes = originalRetryTime 401 SchemaOutOfDateRetryInterval = originalRetryInterval 402 }() 403 dom.SchemaValidator.Stop() 404 _, err = schemaChecker.Check(uint64(123456)) 405 c.Assert(err.Error(), Equals, ErrSchemaReplicantExpired.Error()) 406 dom.SchemaValidator.Reset() 407 408 // Test for reporting min start timestamp. 409 infoSyncer := dom.InfoSyncer() 410 sm := &mockStochastikManager{ 411 PS: make([]*soliton.ProcessInfo, 0), 412 } 413 infoSyncer.SetStochastikManager(sm) 414 beforeTS := variable.GoTimeToTS(time.Now()) 415 infoSyncer.ReportMinStartTS(dom.CausetStore()) 416 afterTS := variable.GoTimeToTS(time.Now()) 417 c.Assert(infoSyncer.GetMinStartTS() > beforeTS && infoSyncer.GetMinStartTS() < afterTS, IsFalse) 418 lowerLimit := time.Now().Add(-time.Duration(ekv.MaxTxnTimeUse) * time.Millisecond) 419 validTS := variable.GoTimeToTS(lowerLimit.Add(time.Minute)) 420 sm.PS = []*soliton.ProcessInfo{ 421 {CurTxnStartTS: 0}, 422 {CurTxnStartTS: math.MaxUint64}, 423 {CurTxnStartTS: variable.GoTimeToTS(lowerLimit)}, 424 {CurTxnStartTS: validTS}, 425 } 426 infoSyncer.SetStochastikManager(sm) 427 infoSyncer.ReportMinStartTS(dom.CausetStore()) 428 c.Assert(infoSyncer.GetMinStartTS() == validTS, IsTrue) 429 430 err = causetstore.Close() 431 c.Assert(err, IsNil) 432 isClose := dom.isClose() 433 c.Assert(isClose, IsFalse) 434 dom.Close() 435 isClose = dom.isClose() 436 c.Assert(isClose, IsTrue) 437 } 438 439 type testResource struct { 440 status int 441 } 442 443 func (tr *testResource) Close() { tr.status = 1 } 444 445 func (*testSuite) TestStochastikPool(c *C) { 446 f := func() (pools.Resource, error) { return &testResource{}, nil } 447 pool := newStochastikPool(1, f) 448 tr, err := pool.Get() 449 c.Assert(err, IsNil) 450 tr1, err := pool.Get() 451 c.Assert(err, IsNil) 452 pool.Put(tr) 453 // Capacity is 1, so tr1 is closed. 454 pool.Put(tr1) 455 c.Assert(tr1.(*testResource).status, Equals, 1) 456 pool.Close() 457 458 pool.Close() 459 pool.Put(tr1) 460 tr, err = pool.Get() 461 c.Assert(err.Error(), Equals, "stochastik pool closed") 462 c.Assert(tr, IsNil) 463 } 464 465 func (*testSuite) TestErrorCode(c *C) { 466 c.Assert(int(terror.ToALLEGROSQLError(ErrSchemaReplicantExpired).Code), Equals, errno.ErrSchemaReplicantExpired) 467 c.Assert(int(terror.ToALLEGROSQLError(ErrSchemaReplicantChanged).Code), Equals, errno.ErrSchemaReplicantChanged) 468 }