github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/index_change_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 dbs 15 16 import ( 17 "context" 18 "time" 19 20 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 21 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 22 . "github.com/whtcorpsinc/check" 23 "github.com/whtcorpsinc/errors" 24 "github.com/whtcorpsinc/milevadb/causet" 25 "github.com/whtcorpsinc/milevadb/ekv" 26 "github.com/whtcorpsinc/milevadb/spacetime" 27 "github.com/whtcorpsinc/milevadb/stochastikctx" 28 "github.com/whtcorpsinc/milevadb/types" 29 ) 30 31 var _ = Suite(&testIndexChangeSuite{}) 32 33 type testIndexChangeSuite struct { 34 causetstore ekv.CausetStorage 35 dbInfo *perceptron.DBInfo 36 } 37 38 func (s *testIndexChangeSuite) SetUpSuite(c *C) { 39 s.causetstore = testCreateStore(c, "test_index_change") 40 s.dbInfo = &perceptron.DBInfo{ 41 Name: perceptron.NewCIStr("test_index_change"), 42 ID: 1, 43 } 44 err := ekv.RunInNewTxn(s.causetstore, true, func(txn ekv.Transaction) error { 45 t := spacetime.NewMeta(txn) 46 return errors.Trace(t.CreateDatabase(s.dbInfo)) 47 }) 48 c.Check(err, IsNil, Commentf("err %v", errors.ErrorStack(err))) 49 } 50 51 func (s *testIndexChangeSuite) TearDownSuite(c *C) { 52 s.causetstore.Close() 53 } 54 55 func (s *testIndexChangeSuite) TestIndexChange(c *C) { 56 d := testNewDBSAndStart( 57 context.Background(), 58 c, 59 WithStore(s.causetstore), 60 WithLease(testLease), 61 ) 62 defer d.Stop() 63 // create causet t (c1 int primary key, c2 int); 64 tblInfo := testBlockInfo(c, d, "t", 2) 65 tblInfo.DeferredCausets[0].Flag = allegrosql.PriKeyFlag | allegrosql.NotNullFlag 66 tblInfo.PKIsHandle = true 67 ctx := testNewContext(d) 68 err := ctx.NewTxn(context.Background()) 69 c.Assert(err, IsNil) 70 testCreateBlock(c, ctx, d, s.dbInfo, tblInfo) 71 originBlock := testGetBlock(c, d, s.dbInfo.ID, tblInfo.ID) 72 73 // insert t values (1, 1), (2, 2), (3, 3) 74 _, err = originBlock.AddRecord(ctx, types.MakeCausets(1, 1)) 75 c.Assert(err, IsNil) 76 _, err = originBlock.AddRecord(ctx, types.MakeCausets(2, 2)) 77 c.Assert(err, IsNil) 78 _, err = originBlock.AddRecord(ctx, types.MakeCausets(3, 3)) 79 c.Assert(err, IsNil) 80 81 txn, err := ctx.Txn(true) 82 c.Assert(err, IsNil) 83 err = txn.Commit(context.Background()) 84 c.Assert(err, IsNil) 85 86 tc := &TestDBSCallback{} 87 // set up hook 88 prevState := perceptron.StateNone 89 addIndexDone := false 90 var ( 91 deleteOnlyBlock causet.Block 92 writeOnlyBlock causet.Block 93 publicBlock causet.Block 94 checkErr error 95 ) 96 tc.onJobUFIDelated = func(job *perceptron.Job) { 97 if job.SchemaState == prevState { 98 return 99 } 100 ctx1 := testNewContext(d) 101 prevState = job.SchemaState 102 switch job.SchemaState { 103 case perceptron.StateDeleteOnly: 104 deleteOnlyBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 105 if err != nil { 106 checkErr = errors.Trace(err) 107 } 108 case perceptron.StateWriteOnly: 109 writeOnlyBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 110 if err != nil { 111 checkErr = errors.Trace(err) 112 } 113 err = s.checkAddWriteOnly(d, ctx1, deleteOnlyBlock, writeOnlyBlock) 114 if err != nil { 115 checkErr = errors.Trace(err) 116 } 117 case perceptron.StatePublic: 118 if job.GetRowCount() != 3 { 119 checkErr = errors.Errorf("job's event count %d != 3", job.GetRowCount()) 120 } 121 publicBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 122 if err != nil { 123 checkErr = errors.Trace(err) 124 } 125 err = s.checkAddPublic(d, ctx1, writeOnlyBlock, publicBlock) 126 if err != nil { 127 checkErr = errors.Trace(err) 128 } 129 if job.State == perceptron.JobStateSynced { 130 addIndexDone = true 131 } 132 } 133 } 134 d.SetHook(tc) 135 testCreateIndex(c, ctx, d, s.dbInfo, originBlock.Meta(), false, "c2", "c2") 136 // We need to make sure onJobUFIDelated is called in the first hook. 137 // After testCreateIndex(), onJobUFIDelated() may not be called when job.state is Sync. 138 // If we skip this check, prevState may wrongly set to StatePublic. 139 for i := 0; i <= 10; i++ { 140 if addIndexDone { 141 break 142 } 143 time.Sleep(50 * time.Millisecond) 144 } 145 c.Check(errors.ErrorStack(checkErr), Equals, "") 146 txn, err = ctx.Txn(true) 147 c.Assert(err, IsNil) 148 c.Assert(txn.Commit(context.Background()), IsNil) 149 prevState = perceptron.StateNone 150 var noneBlock causet.Block 151 tc.onJobUFIDelated = func(job *perceptron.Job) { 152 if job.SchemaState == prevState { 153 return 154 } 155 prevState = job.SchemaState 156 var err error 157 ctx1 := testNewContext(d) 158 switch job.SchemaState { 159 case perceptron.StateWriteOnly: 160 writeOnlyBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 161 if err != nil { 162 checkErr = errors.Trace(err) 163 } 164 err = s.checkDropWriteOnly(d, ctx1, publicBlock, writeOnlyBlock) 165 if err != nil { 166 checkErr = errors.Trace(err) 167 } 168 case perceptron.StateDeleteOnly: 169 deleteOnlyBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 170 if err != nil { 171 checkErr = errors.Trace(err) 172 } 173 err = s.checkDroFIDeleleteOnly(d, ctx1, writeOnlyBlock, deleteOnlyBlock) 174 if err != nil { 175 checkErr = errors.Trace(err) 176 } 177 case perceptron.StateNone: 178 noneBlock, err = getCurrentBlock(d, s.dbInfo.ID, tblInfo.ID) 179 if err != nil { 180 checkErr = errors.Trace(err) 181 } 182 if len(noneBlock.Indices()) != 0 { 183 checkErr = errors.New("index should have been dropped") 184 } 185 } 186 } 187 testDropIndex(c, ctx, d, s.dbInfo, publicBlock.Meta(), "c2") 188 c.Check(errors.ErrorStack(checkErr), Equals, "") 189 } 190 191 func checHoTTexExists(ctx stochastikctx.Context, tbl causet.Block, indexValue interface{}, handle int64, exists bool) error { 192 idx := tbl.Indices()[0] 193 txn, err := ctx.Txn(true) 194 if err != nil { 195 return errors.Trace(err) 196 } 197 doesExist, _, err := idx.Exist(ctx.GetStochastikVars().StmtCtx, txn.GetUnionStore(), types.MakeCausets(indexValue), ekv.IntHandle(handle)) 198 if err != nil { 199 return errors.Trace(err) 200 } 201 if exists != doesExist { 202 if exists { 203 return errors.New("index should exists") 204 } 205 return errors.New("index should not exists") 206 } 207 return nil 208 } 209 210 func (s *testIndexChangeSuite) checkAddWriteOnly(d *dbs, ctx stochastikctx.Context, delOnlyTbl, writeOnlyTbl causet.Block) error { 211 // DeleteOnlyBlock: insert t values (4, 4); 212 err := ctx.NewTxn(context.Background()) 213 if err != nil { 214 return errors.Trace(err) 215 } 216 _, err = delOnlyTbl.AddRecord(ctx, types.MakeCausets(4, 4)) 217 if err != nil { 218 return errors.Trace(err) 219 } 220 err = checHoTTexExists(ctx, writeOnlyTbl, 4, 4, false) 221 if err != nil { 222 return errors.Trace(err) 223 } 224 225 // WriteOnlyBlock: insert t values (5, 5); 226 _, err = writeOnlyTbl.AddRecord(ctx, types.MakeCausets(5, 5)) 227 if err != nil { 228 return errors.Trace(err) 229 } 230 err = checHoTTexExists(ctx, writeOnlyTbl, 5, 5, true) 231 if err != nil { 232 return errors.Trace(err) 233 } 234 235 // WriteOnlyBlock: uFIDelate t set c2 = 1 where c1 = 4 and c2 = 4 236 err = writeOnlyTbl.UFIDelateRecord(context.Background(), ctx, ekv.IntHandle(4), types.MakeCausets(4, 4), types.MakeCausets(4, 1), touchedSlice(writeOnlyTbl)) 237 if err != nil { 238 return errors.Trace(err) 239 } 240 err = checHoTTexExists(ctx, writeOnlyTbl, 1, 4, true) 241 if err != nil { 242 return errors.Trace(err) 243 } 244 245 // DeleteOnlyBlock: uFIDelate t set c2 = 3 where c1 = 4 and c2 = 1 246 err = delOnlyTbl.UFIDelateRecord(context.Background(), ctx, ekv.IntHandle(4), types.MakeCausets(4, 1), types.MakeCausets(4, 3), touchedSlice(writeOnlyTbl)) 247 if err != nil { 248 return errors.Trace(err) 249 } 250 // old value index not exists. 251 err = checHoTTexExists(ctx, writeOnlyTbl, 1, 4, false) 252 if err != nil { 253 return errors.Trace(err) 254 } 255 // new value index not exists. 256 err = checHoTTexExists(ctx, writeOnlyTbl, 3, 4, false) 257 if err != nil { 258 return errors.Trace(err) 259 } 260 261 // WriteOnlyBlock: delete t where c1 = 4 and c2 = 3 262 err = writeOnlyTbl.RemoveRecord(ctx, ekv.IntHandle(4), types.MakeCausets(4, 3)) 263 if err != nil { 264 return errors.Trace(err) 265 } 266 err = checHoTTexExists(ctx, writeOnlyTbl, 3, 4, false) 267 if err != nil { 268 return errors.Trace(err) 269 } 270 271 // DeleteOnlyBlock: delete t where c1 = 5 272 err = delOnlyTbl.RemoveRecord(ctx, ekv.IntHandle(5), types.MakeCausets(5, 5)) 273 if err != nil { 274 return errors.Trace(err) 275 } 276 err = checHoTTexExists(ctx, writeOnlyTbl, 5, 5, false) 277 if err != nil { 278 return errors.Trace(err) 279 } 280 return nil 281 } 282 283 func (s *testIndexChangeSuite) checkAddPublic(d *dbs, ctx stochastikctx.Context, writeTbl, publicTbl causet.Block) error { 284 // WriteOnlyBlock: insert t values (6, 6) 285 err := ctx.NewTxn(context.Background()) 286 if err != nil { 287 return errors.Trace(err) 288 } 289 _, err = writeTbl.AddRecord(ctx, types.MakeCausets(6, 6)) 290 if err != nil { 291 return errors.Trace(err) 292 } 293 err = checHoTTexExists(ctx, publicTbl, 6, 6, true) 294 if err != nil { 295 return errors.Trace(err) 296 } 297 // PublicBlock: insert t values (7, 7) 298 _, err = publicTbl.AddRecord(ctx, types.MakeCausets(7, 7)) 299 if err != nil { 300 return errors.Trace(err) 301 } 302 err = checHoTTexExists(ctx, publicTbl, 7, 7, true) 303 if err != nil { 304 return errors.Trace(err) 305 } 306 307 // WriteOnlyBlock: uFIDelate t set c2 = 5 where c1 = 7 and c2 = 7 308 err = writeTbl.UFIDelateRecord(context.Background(), ctx, ekv.IntHandle(7), types.MakeCausets(7, 7), types.MakeCausets(7, 5), touchedSlice(writeTbl)) 309 if err != nil { 310 return errors.Trace(err) 311 } 312 err = checHoTTexExists(ctx, publicTbl, 5, 7, true) 313 if err != nil { 314 return errors.Trace(err) 315 } 316 err = checHoTTexExists(ctx, publicTbl, 7, 7, false) 317 if err != nil { 318 return errors.Trace(err) 319 } 320 // WriteOnlyBlock: delete t where c1 = 6 321 err = writeTbl.RemoveRecord(ctx, ekv.IntHandle(6), types.MakeCausets(6, 6)) 322 if err != nil { 323 return errors.Trace(err) 324 } 325 err = checHoTTexExists(ctx, publicTbl, 6, 6, false) 326 if err != nil { 327 return errors.Trace(err) 328 } 329 330 var rows [][]types.Causet 331 publicTbl.IterRecords(ctx, publicTbl.FirstKey(), publicTbl.DefCauss(), 332 func(_ ekv.Handle, data []types.Causet, defcaus []*causet.DeferredCauset) (bool, error) { 333 rows = append(rows, data) 334 return true, nil 335 }) 336 if len(rows) == 0 { 337 return errors.New("causet is empty") 338 } 339 for _, event := range rows { 340 idxVal := event[1].GetInt64() 341 handle := event[0].GetInt64() 342 err = checHoTTexExists(ctx, publicTbl, idxVal, handle, true) 343 if err != nil { 344 return errors.Trace(err) 345 } 346 } 347 txn, err := ctx.Txn(true) 348 if err != nil { 349 return errors.Trace(err) 350 } 351 return txn.Commit(context.Background()) 352 } 353 354 func (s *testIndexChangeSuite) checkDropWriteOnly(d *dbs, ctx stochastikctx.Context, publicTbl, writeTbl causet.Block) error { 355 // WriteOnlyBlock insert t values (8, 8) 356 err := ctx.NewTxn(context.Background()) 357 if err != nil { 358 return errors.Trace(err) 359 } 360 _, err = writeTbl.AddRecord(ctx, types.MakeCausets(8, 8)) 361 if err != nil { 362 return errors.Trace(err) 363 } 364 365 err = checHoTTexExists(ctx, publicTbl, 8, 8, true) 366 if err != nil { 367 return errors.Trace(err) 368 } 369 370 // WriteOnlyBlock uFIDelate t set c2 = 7 where c1 = 8 and c2 = 8 371 err = writeTbl.UFIDelateRecord(context.Background(), ctx, ekv.IntHandle(8), types.MakeCausets(8, 8), types.MakeCausets(8, 7), touchedSlice(writeTbl)) 372 if err != nil { 373 return errors.Trace(err) 374 } 375 376 err = checHoTTexExists(ctx, publicTbl, 7, 8, true) 377 if err != nil { 378 return errors.Trace(err) 379 } 380 381 // WriteOnlyBlock delete t where c1 = 8 382 err = writeTbl.RemoveRecord(ctx, ekv.IntHandle(8), types.MakeCausets(8, 7)) 383 if err != nil { 384 return errors.Trace(err) 385 } 386 387 err = checHoTTexExists(ctx, publicTbl, 7, 8, false) 388 if err != nil { 389 return errors.Trace(err) 390 } 391 txn, err := ctx.Txn(true) 392 if err != nil { 393 return errors.Trace(err) 394 } 395 return txn.Commit(context.Background()) 396 } 397 398 func (s *testIndexChangeSuite) checkDroFIDeleleteOnly(d *dbs, ctx stochastikctx.Context, writeTbl, delTbl causet.Block) error { 399 // WriteOnlyBlock insert t values (9, 9) 400 err := ctx.NewTxn(context.Background()) 401 if err != nil { 402 return errors.Trace(err) 403 } 404 _, err = writeTbl.AddRecord(ctx, types.MakeCausets(9, 9)) 405 if err != nil { 406 return errors.Trace(err) 407 } 408 409 err = checHoTTexExists(ctx, writeTbl, 9, 9, true) 410 if err != nil { 411 return errors.Trace(err) 412 } 413 414 // DeleteOnlyBlock insert t values (10, 10) 415 _, err = delTbl.AddRecord(ctx, types.MakeCausets(10, 10)) 416 if err != nil { 417 return errors.Trace(err) 418 } 419 420 err = checHoTTexExists(ctx, writeTbl, 10, 10, false) 421 if err != nil { 422 return errors.Trace(err) 423 } 424 425 // DeleteOnlyBlock uFIDelate t set c2 = 10 where c1 = 9 426 err = delTbl.UFIDelateRecord(context.Background(), ctx, ekv.IntHandle(9), types.MakeCausets(9, 9), types.MakeCausets(9, 10), touchedSlice(delTbl)) 427 if err != nil { 428 return errors.Trace(err) 429 } 430 431 err = checHoTTexExists(ctx, writeTbl, 9, 9, false) 432 if err != nil { 433 return errors.Trace(err) 434 } 435 436 err = checHoTTexExists(ctx, writeTbl, 10, 9, false) 437 if err != nil { 438 return errors.Trace(err) 439 } 440 txn, err := ctx.Txn(true) 441 if err != nil { 442 return errors.Trace(err) 443 } 444 return txn.Commit(context.Background()) 445 }