github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/ddl.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 interlock 15 16 import ( 17 "context" 18 "fmt" 19 "strings" 20 21 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 24 "github.com/whtcorpsinc/BerolinaSQL/terror" 25 "github.com/whtcorpsinc/errors" 26 "github.com/whtcorpsinc/milevadb/causet/embedded" 27 "github.com/whtcorpsinc/milevadb/config" 28 "github.com/whtcorpsinc/milevadb/dbs" 29 "github.com/whtcorpsinc/milevadb/petri" 30 "github.com/whtcorpsinc/milevadb/schemareplicant" 31 "github.com/whtcorpsinc/milevadb/soliton/admin" 32 "github.com/whtcorpsinc/milevadb/soliton/chunk" 33 "github.com/whtcorpsinc/milevadb/soliton/gcutil" 34 "github.com/whtcorpsinc/milevadb/soliton/logutil" 35 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 36 "github.com/whtcorpsinc/milevadb/spacetime" 37 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 38 "github.com/whtcorpsinc/milevadb/types" 39 "go.uber.org/zap" 40 ) 41 42 // DBSInterDirc represents a DBS interlock. 43 // It grabs a DBS instance from Petri, calling the DBS methods to do the work. 44 type DBSInterDirc struct { 45 baseInterlockingDirectorate 46 47 stmt ast.StmtNode 48 is schemareplicant.SchemaReplicant 49 done bool 50 } 51 52 // toErr converts the error to the ErrSchemaReplicantChanged when the schemaReplicant is outdated. 53 func (e *DBSInterDirc) toErr(err error) error { 54 // The err may be cause by schemaReplicant changed, here we distinguish the ErrSchemaReplicantChanged error from other errors. 55 dom := petri.GetPetri(e.ctx) 56 checker := petri.NewSchemaChecker(dom, e.is.SchemaMetaVersion(), nil) 57 txn, err1 := e.ctx.Txn(true) 58 if err1 != nil { 59 logutil.BgLogger().Error("active txn failed", zap.Error(err)) 60 return err1 61 } 62 _, schemaInfoErr := checker.Check(txn.StartTS()) 63 if schemaInfoErr != nil { 64 return errors.Trace(schemaInfoErr) 65 } 66 return err 67 } 68 69 // Next implements the InterlockingDirectorate Next interface. 70 func (e *DBSInterDirc) Next(ctx context.Context, req *chunk.Chunk) (err error) { 71 if e.done { 72 return nil 73 } 74 e.done = true 75 76 // For each DBS, we should commit the previous transaction and create a new transaction. 77 if err = e.ctx.NewTxn(ctx); err != nil { 78 return err 79 } 80 defer func() { e.ctx.GetStochastikVars().StmtCtx.IsDBSJobInQueue = false }() 81 82 switch x := e.stmt.(type) { 83 case *ast.AlterDatabaseStmt: 84 err = e.executeAlterDatabase(x) 85 case *ast.AlterBlockStmt: 86 err = e.executeAlterBlock(x) 87 case *ast.CreateIndexStmt: 88 err = e.executeCreateIndex(x) 89 case *ast.CreateDatabaseStmt: 90 err = e.executeCreateDatabase(x) 91 case *ast.CreateBlockStmt: 92 err = e.executeCreateBlock(x) 93 case *ast.CreateViewStmt: 94 err = e.executeCreateView(x) 95 case *ast.DropIndexStmt: 96 err = e.executeDropIndex(x) 97 case *ast.DroFIDelatabaseStmt: 98 err = e.executeDroFIDelatabase(x) 99 case *ast.DropBlockStmt: 100 if x.IsView { 101 err = e.executeDropView(x) 102 } else { 103 err = e.executeDropBlock(x) 104 } 105 case *ast.RecoverBlockStmt: 106 err = e.executeRecoverBlock(x) 107 case *ast.FlashBackBlockStmt: 108 err = e.executeFlashbackBlock(x) 109 case *ast.RenameBlockStmt: 110 err = e.executeRenameBlock(x) 111 case *ast.TruncateBlockStmt: 112 err = e.executeTruncateBlock(x) 113 case *ast.LockBlocksStmt: 114 err = e.executeLockBlocks(x) 115 case *ast.UnlockBlocksStmt: 116 err = e.executeUnlockBlocks(x) 117 case *ast.CleanupBlockLockStmt: 118 err = e.executeCleanupBlockLock(x) 119 case *ast.RepairBlockStmt: 120 err = e.executeRepairBlock(x) 121 case *ast.CreateSequenceStmt: 122 err = e.executeCreateSequence(x) 123 case *ast.DropSequenceStmt: 124 err = e.executeDropSequence(x) 125 126 } 127 if err != nil { 128 // If the tenant return ErrBlockNotExists error when running this DBS, it may be caused by schemaReplicant changed, 129 // otherwise, ErrBlockNotExists can be returned before putting this DBS job to the job queue. 130 if (e.ctx.GetStochastikVars().StmtCtx.IsDBSJobInQueue && schemareplicant.ErrBlockNotExists.Equal(err)) || 131 !e.ctx.GetStochastikVars().StmtCtx.IsDBSJobInQueue { 132 return e.toErr(err) 133 } 134 return err 135 136 } 137 138 dom := petri.GetPetri(e.ctx) 139 // UFIDelate SchemaReplicant in TxnCtx, so it will pass schemaReplicant check. 140 is := dom.SchemaReplicant() 141 txnCtx := e.ctx.GetStochastikVars().TxnCtx 142 txnCtx.SchemaReplicant = is 143 txnCtx.SchemaVersion = is.SchemaMetaVersion() 144 // DBS will force commit old transaction, after DBS, in transaction status should be false. 145 e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, false) 146 return nil 147 } 148 149 func (e *DBSInterDirc) executeTruncateBlock(s *ast.TruncateBlockStmt) error { 150 ident := ast.Ident{Schema: s.Block.Schema, Name: s.Block.Name} 151 err := petri.GetPetri(e.ctx).DBS().TruncateBlock(e.ctx, ident) 152 return err 153 } 154 155 func (e *DBSInterDirc) executeRenameBlock(s *ast.RenameBlockStmt) error { 156 if len(s.BlockToBlocks) != 1 { 157 // Now we only allow one schemaReplicant changing at the same time. 158 return errors.Errorf("can't run multi schemaReplicant change") 159 } 160 oldIdent := ast.Ident{Schema: s.OldBlock.Schema, Name: s.OldBlock.Name} 161 newIdent := ast.Ident{Schema: s.NewBlock.Schema, Name: s.NewBlock.Name} 162 isAlterBlock := false 163 err := petri.GetPetri(e.ctx).DBS().RenameBlock(e.ctx, oldIdent, newIdent, isAlterBlock) 164 return err 165 } 166 167 func (e *DBSInterDirc) executeCreateDatabase(s *ast.CreateDatabaseStmt) error { 168 var opt *ast.CharsetOpt 169 if len(s.Options) != 0 { 170 opt = &ast.CharsetOpt{} 171 for _, val := range s.Options { 172 switch val.Tp { 173 case ast.DatabaseOptionCharset: 174 opt.Chs = val.Value 175 case ast.DatabaseOptionDefCauslate: 176 opt.DefCaus = val.Value 177 } 178 } 179 } 180 err := petri.GetPetri(e.ctx).DBS().CreateSchema(e.ctx, perceptron.NewCIStr(s.Name), opt) 181 if err != nil { 182 if schemareplicant.ErrDatabaseExists.Equal(err) && s.IfNotExists { 183 err = nil 184 } 185 } 186 return err 187 } 188 189 func (e *DBSInterDirc) executeAlterDatabase(s *ast.AlterDatabaseStmt) error { 190 err := petri.GetPetri(e.ctx).DBS().AlterSchema(e.ctx, s) 191 return err 192 } 193 194 func (e *DBSInterDirc) executeCreateBlock(s *ast.CreateBlockStmt) error { 195 err := petri.GetPetri(e.ctx).DBS().CreateBlock(e.ctx, s) 196 return err 197 } 198 199 func (e *DBSInterDirc) executeCreateView(s *ast.CreateViewStmt) error { 200 err := petri.GetPetri(e.ctx).DBS().CreateView(e.ctx, s) 201 return err 202 } 203 204 func (e *DBSInterDirc) executeCreateIndex(s *ast.CreateIndexStmt) error { 205 ident := ast.Ident{Schema: s.Block.Schema, Name: s.Block.Name} 206 err := petri.GetPetri(e.ctx).DBS().CreateIndex(e.ctx, ident, s.KeyType, perceptron.NewCIStr(s.IndexName), 207 s.IndexPartSpecifications, s.IndexOption, s.IfNotExists) 208 return err 209 } 210 211 func (e *DBSInterDirc) executeDroFIDelatabase(s *ast.DroFIDelatabaseStmt) error { 212 dbName := perceptron.NewCIStr(s.Name) 213 214 // Protect important system causet from been dropped by a mistake. 215 // I can hardly find a case that a user really need to do this. 216 if dbName.L == "allegrosql" { 217 return errors.New("Drop 'allegrosql' database is forbidden") 218 } 219 220 err := petri.GetPetri(e.ctx).DBS().DropSchema(e.ctx, dbName) 221 if schemareplicant.ErrDatabaseNotExists.Equal(err) { 222 if s.IfExists { 223 err = nil 224 } else { 225 err = schemareplicant.ErrDatabaseDropExists.GenWithStackByArgs(s.Name) 226 } 227 } 228 stochastikVars := e.ctx.GetStochastikVars() 229 if err == nil && strings.ToLower(stochastikVars.CurrentDB) == dbName.L { 230 stochastikVars.CurrentDB = "" 231 err = variable.SetStochastikSystemVar(stochastikVars, variable.CharsetDatabase, types.NewStringCauset(allegrosql.DefaultCharset)) 232 if err != nil { 233 return err 234 } 235 err = variable.SetStochastikSystemVar(stochastikVars, variable.DefCauslationDatabase, types.NewStringCauset(allegrosql.DefaultDefCauslationName)) 236 if err != nil { 237 return err 238 } 239 } 240 return err 241 } 242 243 // If one drop those blocks by mistake, it's difficult to recover. 244 // In the worst case, the whole MilevaDB cluster fails to bootstrap, so we prevent user from dropping them. 245 var systemBlocks = map[string]struct{}{ 246 "milevadb": {}, 247 "gc_delete_range": {}, 248 "gc_delete_range_done": {}, 249 } 250 251 func isSystemBlock(schemaReplicant, causet string) bool { 252 if schemaReplicant != "allegrosql" { 253 return false 254 } 255 if _, ok := systemBlocks[causet]; ok { 256 return true 257 } 258 return false 259 } 260 261 type objectType int 262 263 const ( 264 blockObject objectType = iota 265 viewObject 266 sequenceObject 267 ) 268 269 func (e *DBSInterDirc) executeDropBlock(s *ast.DropBlockStmt) error { 270 return e.dropBlockObject(s.Blocks, blockObject, s.IfExists) 271 } 272 273 func (e *DBSInterDirc) executeDropView(s *ast.DropBlockStmt) error { 274 return e.dropBlockObject(s.Blocks, viewObject, s.IfExists) 275 } 276 277 func (e *DBSInterDirc) executeDropSequence(s *ast.DropSequenceStmt) error { 278 return e.dropBlockObject(s.Sequences, sequenceObject, s.IfExists) 279 } 280 281 // dropBlockObject actually applies to `blockObject`, `viewObject` and `sequenceObject`. 282 func (e *DBSInterDirc) dropBlockObject(objects []*ast.BlockName, obt objectType, ifExists bool) error { 283 var notExistBlocks []string 284 for _, tn := range objects { 285 fullti := ast.Ident{Schema: tn.Schema, Name: tn.Name} 286 _, ok := e.is.SchemaByName(tn.Schema) 287 if !ok { 288 // TODO: we should return special error for causet not exist, checking "not exist" is not enough, 289 // because some other errors may contain this error string too. 290 notExistBlocks = append(notExistBlocks, fullti.String()) 291 continue 292 } 293 _, err := e.is.BlockByName(tn.Schema, tn.Name) 294 if err != nil && schemareplicant.ErrBlockNotExists.Equal(err) { 295 notExistBlocks = append(notExistBlocks, fullti.String()) 296 continue 297 } else if err != nil { 298 return err 299 } 300 301 // Protect important system causet from been dropped by a mistake. 302 // I can hardly find a case that a user really need to do this. 303 if isSystemBlock(tn.Schema.L, tn.Name.L) { 304 return errors.Errorf("Drop milevadb system causet '%s.%s' is forbidden", tn.Schema.L, tn.Name.L) 305 } 306 307 if obt == blockObject && config.CheckBlockBeforeDrop { 308 logutil.BgLogger().Warn("admin check causet before drop", 309 zap.String("database", fullti.Schema.O), 310 zap.String("causet", fullti.Name.O), 311 ) 312 allegrosql := fmt.Sprintf("admin check causet `%s`.`%s`", fullti.Schema.O, fullti.Name.O) 313 _, _, err = e.ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql) 314 if err != nil { 315 return err 316 } 317 } 318 switch obt { 319 case blockObject: 320 err = petri.GetPetri(e.ctx).DBS().DropBlock(e.ctx, fullti) 321 case viewObject: 322 err = petri.GetPetri(e.ctx).DBS().DropView(e.ctx, fullti) 323 case sequenceObject: 324 err = petri.GetPetri(e.ctx).DBS().DropSequence(e.ctx, fullti, ifExists) 325 } 326 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockNotExists.Equal(err) { 327 notExistBlocks = append(notExistBlocks, fullti.String()) 328 } else if err != nil { 329 return err 330 } 331 } 332 if len(notExistBlocks) > 0 && !ifExists { 333 if obt == sequenceObject { 334 return schemareplicant.ErrSequenceDropExists.GenWithStackByArgs(strings.Join(notExistBlocks, ",")) 335 } 336 return schemareplicant.ErrBlockDropExists.GenWithStackByArgs(strings.Join(notExistBlocks, ",")) 337 } 338 // We need add warning when use if exists. 339 if len(notExistBlocks) > 0 && ifExists { 340 for _, causet := range notExistBlocks { 341 if obt == sequenceObject { 342 e.ctx.GetStochastikVars().StmtCtx.AppendNote(schemareplicant.ErrSequenceDropExists.GenWithStackByArgs(causet)) 343 } else { 344 e.ctx.GetStochastikVars().StmtCtx.AppendNote(schemareplicant.ErrBlockDropExists.GenWithStackByArgs(causet)) 345 } 346 } 347 } 348 return nil 349 } 350 351 func (e *DBSInterDirc) executeDropIndex(s *ast.DropIndexStmt) error { 352 ti := ast.Ident{Schema: s.Block.Schema, Name: s.Block.Name} 353 err := petri.GetPetri(e.ctx).DBS().DropIndex(e.ctx, ti, perceptron.NewCIStr(s.IndexName), s.IfExists) 354 if (schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockNotExists.Equal(err)) && s.IfExists { 355 err = nil 356 } 357 return err 358 } 359 360 func (e *DBSInterDirc) executeAlterBlock(s *ast.AlterBlockStmt) error { 361 ti := ast.Ident{Schema: s.Block.Schema, Name: s.Block.Name} 362 err := petri.GetPetri(e.ctx).DBS().AlterBlock(e.ctx, ti, s.Specs) 363 return err 364 } 365 366 // executeRecoverBlock represents a recover causet interlock. 367 // It is built from "recover causet" memex, 368 // is used to recover the causet that deleted by mistake. 369 func (e *DBSInterDirc) executeRecoverBlock(s *ast.RecoverBlockStmt) error { 370 txn, err := e.ctx.Txn(true) 371 if err != nil { 372 return err 373 } 374 t := spacetime.NewMeta(txn) 375 dom := petri.GetPetri(e.ctx) 376 var job *perceptron.Job 377 var tblInfo *perceptron.BlockInfo 378 if s.JobID != 0 { 379 job, tblInfo, err = e.getRecoverBlockByJobID(s, t, dom) 380 } else { 381 job, tblInfo, err = e.getRecoverBlockByBlockName(s.Block) 382 } 383 if err != nil { 384 return err 385 } 386 // Check the causet ID was not exists. 387 tbl, ok := dom.SchemaReplicant().BlockByID(tblInfo.ID) 388 if ok { 389 return schemareplicant.ErrBlockExists.GenWithStack("Block '%-.192s' already been recover to '%-.192s', can't be recover repeatedly", s.Block.Name.O, tbl.Meta().Name.O) 390 } 391 392 autoIncID, autoRandID, err := e.getBlockAutoIDsFromSnapshot(job) 393 if err != nil { 394 return err 395 } 396 397 recoverInfo := &dbs.RecoverInfo{ 398 SchemaID: job.SchemaID, 399 BlockInfo: tblInfo, 400 DropJobID: job.ID, 401 SnapshotTS: job.StartTS, 402 CurAutoIncID: autoIncID, 403 CurAutoRandID: autoRandID, 404 } 405 // Call DBS RecoverBlock. 406 err = petri.GetPetri(e.ctx).DBS().RecoverBlock(e.ctx, recoverInfo) 407 return err 408 } 409 410 func (e *DBSInterDirc) getBlockAutoIDsFromSnapshot(job *perceptron.Job) (autoIncID, autoRandID int64, err error) { 411 // Get causet original autoIDs before causet drop. 412 dom := petri.GetPetri(e.ctx) 413 m, err := dom.GetSnapshotMeta(job.StartTS) 414 if err != nil { 415 return 0, 0, err 416 } 417 autoIncID, err = m.GetAutoBlockID(job.SchemaID, job.BlockID) 418 if err != nil { 419 return 0, 0, errors.Errorf("recover block_id: %d, get original autoIncID from snapshot spacetime err: %s", job.BlockID, err.Error()) 420 } 421 autoRandID, err = m.GetAutoRandomID(job.SchemaID, job.BlockID) 422 if err != nil { 423 return 0, 0, errors.Errorf("recover block_id: %d, get original autoRandID from snapshot spacetime err: %s", job.BlockID, err.Error()) 424 } 425 return autoIncID, autoRandID, nil 426 } 427 428 func (e *DBSInterDirc) getRecoverBlockByJobID(s *ast.RecoverBlockStmt, t *spacetime.Meta, dom *petri.Petri) (*perceptron.Job, *perceptron.BlockInfo, error) { 429 job, err := t.GetHistoryDBSJob(s.JobID) 430 if err != nil { 431 return nil, nil, err 432 } 433 if job == nil { 434 return nil, nil, admin.ErrDBSJobNotFound.GenWithStackByArgs(s.JobID) 435 } 436 if job.Type != perceptron.CausetActionDropBlock && job.Type != perceptron.CausetActionTruncateBlock { 437 return nil, nil, errors.Errorf("Job %v type is %v, not dropped/truncated causet", job.ID, job.Type) 438 } 439 440 // Check GC safe point for getting snapshot schemaReplicant. 441 err = gcutil.ValidateSnapshot(e.ctx, job.StartTS) 442 if err != nil { 443 return nil, nil, err 444 } 445 446 // Get the snapshot schemaReplicant before drop causet. 447 snapInfo, err := dom.GetSnapshotSchemaReplicant(job.StartTS) 448 if err != nil { 449 return nil, nil, err 450 } 451 // Get causet spacetime from snapshot schemaReplicant. 452 causet, ok := snapInfo.BlockByID(job.BlockID) 453 if !ok { 454 return nil, nil, schemareplicant.ErrBlockNotExists.GenWithStackByArgs( 455 fmt.Sprintf("(Schema ID %d)", job.SchemaID), 456 fmt.Sprintf("(Block ID %d)", job.BlockID), 457 ) 458 } 459 return job, causet.Meta(), nil 460 } 461 462 // GetDropOrTruncateBlockInfoFromJobs gets the dropped/truncated causet information from DBS jobs, 463 // it will use the `start_ts` of DBS job as snapshot to get the dropped/truncated causet information. 464 func GetDropOrTruncateBlockInfoFromJobs(jobs []*perceptron.Job, gcSafePoint uint64, dom *petri.Petri, fn func(*perceptron.Job, *perceptron.BlockInfo) (bool, error)) (bool, error) { 465 for _, job := range jobs { 466 // Check GC safe point for getting snapshot schemaReplicant. 467 err := gcutil.ValidateSnapshotWithGCSafePoint(job.StartTS, gcSafePoint) 468 if err != nil { 469 return false, err 470 } 471 if job.Type != perceptron.CausetActionDropBlock && job.Type != perceptron.CausetActionTruncateBlock { 472 continue 473 } 474 475 snapMeta, err := dom.GetSnapshotMeta(job.StartTS) 476 if err != nil { 477 return false, err 478 } 479 tbl, err := snapMeta.GetBlock(job.SchemaID, job.BlockID) 480 if err != nil { 481 if spacetime.ErrDBNotExists.Equal(err) { 482 // The dropped/truncated DBS maybe execute failed that caused by the parallel DBS execution, 483 // then can't find the causet from the snapshot info-schemaReplicant. Should just ignore error here, 484 // see more in TestParallelDropSchemaAndDropBlock. 485 continue 486 } 487 return false, err 488 } 489 if tbl == nil { 490 // The dropped/truncated DBS maybe execute failed that caused by the parallel DBS execution, 491 // then can't find the causet from the snapshot info-schemaReplicant. Should just ignore error here, 492 // see more in TestParallelDropSchemaAndDropBlock. 493 continue 494 } 495 finish, err := fn(job, tbl) 496 if err != nil || finish { 497 return finish, err 498 } 499 } 500 return false, nil 501 } 502 503 func (e *DBSInterDirc) getRecoverBlockByBlockName(blockName *ast.BlockName) (*perceptron.Job, *perceptron.BlockInfo, error) { 504 txn, err := e.ctx.Txn(true) 505 if err != nil { 506 return nil, nil, err 507 } 508 schemaName := blockName.Schema.L 509 if schemaName == "" { 510 schemaName = strings.ToLower(e.ctx.GetStochastikVars().CurrentDB) 511 } 512 if schemaName == "" { 513 return nil, nil, errors.Trace(embedded.ErrNoDB) 514 } 515 gcSafePoint, err := gcutil.GetGCSafePoint(e.ctx) 516 if err != nil { 517 return nil, nil, err 518 } 519 var jobInfo *perceptron.Job 520 var blockInfo *perceptron.BlockInfo 521 dom := petri.GetPetri(e.ctx) 522 handleJobAndBlockInfo := func(job *perceptron.Job, tblInfo *perceptron.BlockInfo) (bool, error) { 523 if tblInfo.Name.L != blockName.Name.L { 524 return false, nil 525 } 526 schemaReplicant, ok := dom.SchemaReplicant().SchemaByID(job.SchemaID) 527 if !ok { 528 return false, nil 529 } 530 if schemaReplicant.Name.L == schemaName { 531 blockInfo = tblInfo 532 jobInfo = job 533 return true, nil 534 } 535 return false, nil 536 } 537 fn := func(jobs []*perceptron.Job) (bool, error) { 538 return GetDropOrTruncateBlockInfoFromJobs(jobs, gcSafePoint, dom, handleJobAndBlockInfo) 539 } 540 err = admin.IterHistoryDBSJobs(txn, fn) 541 if err != nil { 542 if terror.ErrorEqual(variable.ErrSnapshotTooOld, err) { 543 return nil, nil, errors.Errorf("Can't find dropped/truncated causet '%s' in GC safe point %s", blockName.Name.O, perceptron.TSConvert2Time(gcSafePoint).String()) 544 } 545 return nil, nil, err 546 } 547 if blockInfo == nil || jobInfo == nil { 548 return nil, nil, errors.Errorf("Can't find dropped/truncated causet: %v in DBS history jobs", blockName.Name) 549 } 550 return jobInfo, blockInfo, nil 551 } 552 553 func (e *DBSInterDirc) executeFlashbackBlock(s *ast.FlashBackBlockStmt) error { 554 job, tblInfo, err := e.getRecoverBlockByBlockName(s.Block) 555 if err != nil { 556 return err 557 } 558 if len(s.NewName) != 0 { 559 tblInfo.Name = perceptron.NewCIStr(s.NewName) 560 } 561 // Check the causet ID was not exists. 562 is := petri.GetPetri(e.ctx).SchemaReplicant() 563 tbl, ok := is.BlockByID(tblInfo.ID) 564 if ok { 565 return schemareplicant.ErrBlockExists.GenWithStack("Block '%-.192s' already been flashback to '%-.192s', can't be flashback repeatedly", s.Block.Name.O, tbl.Meta().Name.O) 566 } 567 568 autoIncID, autoRandID, err := e.getBlockAutoIDsFromSnapshot(job) 569 if err != nil { 570 return err 571 } 572 recoverInfo := &dbs.RecoverInfo{ 573 SchemaID: job.SchemaID, 574 BlockInfo: tblInfo, 575 DropJobID: job.ID, 576 SnapshotTS: job.StartTS, 577 CurAutoIncID: autoIncID, 578 CurAutoRandID: autoRandID, 579 } 580 // Call DBS RecoverBlock. 581 err = petri.GetPetri(e.ctx).DBS().RecoverBlock(e.ctx, recoverInfo) 582 return err 583 } 584 585 func (e *DBSInterDirc) executeLockBlocks(s *ast.LockBlocksStmt) error { 586 if !config.BlockLockEnabled() { 587 return nil 588 } 589 return petri.GetPetri(e.ctx).DBS().LockBlocks(e.ctx, s) 590 } 591 592 func (e *DBSInterDirc) executeUnlockBlocks(s *ast.UnlockBlocksStmt) error { 593 if !config.BlockLockEnabled() { 594 return nil 595 } 596 lockedBlocks := e.ctx.GetAllBlockLocks() 597 return petri.GetPetri(e.ctx).DBS().UnlockBlocks(e.ctx, lockedBlocks) 598 } 599 600 func (e *DBSInterDirc) executeCleanupBlockLock(s *ast.CleanupBlockLockStmt) error { 601 return petri.GetPetri(e.ctx).DBS().CleanupBlockLock(e.ctx, s.Blocks) 602 } 603 604 func (e *DBSInterDirc) executeRepairBlock(s *ast.RepairBlockStmt) error { 605 return petri.GetPetri(e.ctx).DBS().RepairBlock(e.ctx, s.Block, s.CreateStmt) 606 } 607 608 func (e *DBSInterDirc) executeCreateSequence(s *ast.CreateSequenceStmt) error { 609 return petri.GetPetri(e.ctx).DBS().CreateSequence(e.ctx, s) 610 }