github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/table.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 "fmt" 18 "strconv" 19 "sync/atomic" 20 "time" 21 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/BerolinaSQL/charset" 24 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 25 field_types "github.com/whtcorpsinc/BerolinaSQL/types" 26 "github.com/whtcorpsinc/errors" 27 "github.com/whtcorpsinc/failpoint" 28 "github.com/whtcorpsinc/milevadb/blockcodec" 29 "github.com/whtcorpsinc/milevadb/causet" 30 "github.com/whtcorpsinc/milevadb/causet/blocks" 31 "github.com/whtcorpsinc/milevadb/dbs/soliton" 32 "github.com/whtcorpsinc/milevadb/ekv" 33 "github.com/whtcorpsinc/milevadb/schemareplicant" 34 "github.com/whtcorpsinc/milevadb/soliton/gcutil" 35 "github.com/whtcorpsinc/milevadb/spacetime" 36 "github.com/whtcorpsinc/milevadb/spacetime/autoid" 37 ) 38 39 const tiflashCheckMilevaDBHTTPAPIHalfInterval = 2500 * time.Millisecond 40 41 func onCreateBlock(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 42 failpoint.Inject("mockExceedErrorLimit", func(val failpoint.Value) { 43 if val.(bool) { 44 failpoint.Return(ver, errors.New("mock do job error")) 45 } 46 }) 47 48 schemaID := job.SchemaID 49 tbInfo := &perceptron.BlockInfo{} 50 if err := job.DecodeArgs(tbInfo); err != nil { 51 // Invalid arguments, cancel this job. 52 job.State = perceptron.JobStateCancelled 53 return ver, errors.Trace(err) 54 } 55 56 tbInfo.State = perceptron.StateNone 57 err := checkBlockNotExists(d, t, schemaID, tbInfo.Name.L) 58 if err != nil { 59 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockExists.Equal(err) { 60 job.State = perceptron.JobStateCancelled 61 } 62 return ver, errors.Trace(err) 63 } 64 65 ver, err = uFIDelateSchemaVersion(t, job) 66 if err != nil { 67 return ver, errors.Trace(err) 68 } 69 70 switch tbInfo.State { 71 case perceptron.StateNone: 72 // none -> public 73 tbInfo.State = perceptron.StatePublic 74 tbInfo.UFIDelateTS = t.StartTS 75 err = createBlockOrViewWithCheck(t, job, schemaID, tbInfo) 76 if err != nil { 77 return ver, errors.Trace(err) 78 } 79 80 failpoint.Inject("checkTenantCheckAllVersionsWaitTime", func(val failpoint.Value) { 81 if val.(bool) { 82 failpoint.Return(ver, errors.New("mock create causet error")) 83 } 84 }) 85 86 // Finish this job. 87 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tbInfo) 88 asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionCreateBlock, BlockInfo: tbInfo}) 89 return ver, nil 90 default: 91 return ver, ErrInvalidDBSState.GenWithStackByArgs("causet", tbInfo.State) 92 } 93 } 94 95 func createBlockOrViewWithCheck(t *spacetime.Meta, job *perceptron.Job, schemaID int64, tbInfo *perceptron.BlockInfo) error { 96 err := checkBlockInfoValid(tbInfo) 97 if err != nil { 98 job.State = perceptron.JobStateCancelled 99 return errors.Trace(err) 100 } 101 return t.CreateBlockOrView(schemaID, tbInfo) 102 } 103 104 func repairBlockOrViewWithCheck(t *spacetime.Meta, job *perceptron.Job, schemaID int64, tbInfo *perceptron.BlockInfo) error { 105 err := checkBlockInfoValid(tbInfo) 106 if err != nil { 107 job.State = perceptron.JobStateCancelled 108 return errors.Trace(err) 109 } 110 return t.UFIDelateBlock(schemaID, tbInfo) 111 } 112 113 func onCreateView(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 114 schemaID := job.SchemaID 115 tbInfo := &perceptron.BlockInfo{} 116 var orReplace bool 117 var oldTbInfoID int64 118 if err := job.DecodeArgs(tbInfo, &orReplace, &oldTbInfoID); err != nil { 119 // Invalid arguments, cancel this job. 120 job.State = perceptron.JobStateCancelled 121 return ver, errors.Trace(err) 122 } 123 tbInfo.State = perceptron.StateNone 124 err := checkBlockNotExists(d, t, schemaID, tbInfo.Name.L) 125 if err != nil { 126 if schemareplicant.ErrDatabaseNotExists.Equal(err) { 127 job.State = perceptron.JobStateCancelled 128 return ver, errors.Trace(err) 129 } else if schemareplicant.ErrBlockExists.Equal(err) { 130 if !orReplace { 131 job.State = perceptron.JobStateCancelled 132 return ver, errors.Trace(err) 133 } 134 } else { 135 return ver, errors.Trace(err) 136 } 137 } 138 ver, err = uFIDelateSchemaVersion(t, job) 139 if err != nil { 140 return ver, errors.Trace(err) 141 } 142 switch tbInfo.State { 143 case perceptron.StateNone: 144 // none -> public 145 tbInfo.State = perceptron.StatePublic 146 tbInfo.UFIDelateTS = t.StartTS 147 if oldTbInfoID > 0 && orReplace { 148 err = t.DropBlockOrView(schemaID, oldTbInfoID, true) 149 if err != nil { 150 return ver, errors.Trace(err) 151 } 152 } 153 err = createBlockOrViewWithCheck(t, job, schemaID, tbInfo) 154 if err != nil { 155 return ver, errors.Trace(err) 156 } 157 // Finish this job. 158 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tbInfo) 159 asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionCreateView, BlockInfo: tbInfo}) 160 return ver, nil 161 default: 162 return ver, ErrInvalidDBSState.GenWithStackByArgs("causet", tbInfo.State) 163 } 164 } 165 166 func onDropBlockOrView(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 167 tblInfo, err := checkBlockExistAndCancelNonExistJob(t, job, job.SchemaID) 168 if err != nil { 169 return ver, errors.Trace(err) 170 } 171 172 originalState := job.SchemaState 173 switch tblInfo.State { 174 case perceptron.StatePublic: 175 // public -> write only 176 job.SchemaState = perceptron.StateWriteOnly 177 tblInfo.State = perceptron.StateWriteOnly 178 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != tblInfo.State) 179 case perceptron.StateWriteOnly: 180 // write only -> delete only 181 job.SchemaState = perceptron.StateDeleteOnly 182 tblInfo.State = perceptron.StateDeleteOnly 183 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != tblInfo.State) 184 case perceptron.StateDeleteOnly: 185 tblInfo.State = perceptron.StateNone 186 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != tblInfo.State) 187 if err != nil { 188 return ver, errors.Trace(err) 189 } 190 if tblInfo.IsSequence() { 191 if err = t.DropSequence(job.SchemaID, job.BlockID, true); err != nil { 192 break 193 } 194 } else { 195 if err = t.DropBlockOrView(job.SchemaID, job.BlockID, true); err != nil { 196 break 197 } 198 } 199 // Finish this job. 200 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StateNone, ver, tblInfo) 201 startKey := blockcodec.EncodeBlockPrefix(job.BlockID) 202 job.Args = append(job.Args, startKey, getPartitionIDs(tblInfo)) 203 default: 204 err = ErrInvalidDBSState.GenWithStackByArgs("causet", tblInfo.State) 205 } 206 207 return ver, errors.Trace(err) 208 } 209 210 const ( 211 recoverBlockCheckFlagNone int64 = iota 212 recoverBlockCheckFlagEnableGC 213 recoverBlockCheckFlagDisableGC 214 ) 215 216 func (w *worker) onRecoverBlock(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, err error) { 217 schemaID := job.SchemaID 218 tblInfo := &perceptron.BlockInfo{} 219 var autoIncID, autoRandID, dropJobID, recoverBlockCheckFlag int64 220 var snapshotTS uint64 221 const checkFlagIndexInJobArgs = 4 // The index of `recoverBlockCheckFlag` in job arg list. 222 if err = job.DecodeArgs(tblInfo, &autoIncID, &dropJobID, &snapshotTS, &recoverBlockCheckFlag, &autoRandID); err != nil { 223 // Invalid arguments, cancel this job. 224 job.State = perceptron.JobStateCancelled 225 return ver, errors.Trace(err) 226 } 227 228 // check GC and safe point 229 gcEnable, err := checkGCEnable(w) 230 if err != nil { 231 job.State = perceptron.JobStateCancelled 232 return ver, errors.Trace(err) 233 } 234 235 err = checkBlockNotExists(d, t, schemaID, tblInfo.Name.L) 236 if err != nil { 237 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockExists.Equal(err) { 238 job.State = perceptron.JobStateCancelled 239 } 240 return ver, errors.Trace(err) 241 } 242 243 err = checkBlockIDNotExists(t, schemaID, tblInfo.ID) 244 if err != nil { 245 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockExists.Equal(err) { 246 job.State = perceptron.JobStateCancelled 247 } 248 return ver, errors.Trace(err) 249 } 250 251 // Recover causet divide into 2 steps: 252 // 1. Check GC enable status, to decided whether enable GC after recover causet. 253 // a. Why not disable GC before put the job to DBS job queue? 254 // Think about concurrency problem. If a recover job-1 is doing and already disabled GC, 255 // then, another recover causet job-2 check GC enable will get disable before into the job queue. 256 // then, after recover causet job-2 finished, the GC will be disabled. 257 // b. Why split into 2 steps? 1 step also can finish this job: check GC -> disable GC -> recover causet -> finish job. 258 // What if the transaction commit failed? then, the job will retry, but the GC already disabled when first running. 259 // So, after this job retry succeed, the GC will be disabled. 260 // 2. Do recover causet job. 261 // a. Check whether GC enabled, if enabled, disable GC first. 262 // b. Check GC safe point. If drop causet time if after safe point time, then can do recover. 263 // otherwise, can't recover causet, because the records of the causet may already delete by gc. 264 // c. Remove GC task of the causet from gc_delete_range causet. 265 // d. Create causet and rebase causet auto ID. 266 // e. Finish. 267 switch tblInfo.State { 268 case perceptron.StateNone: 269 // none -> write only 270 // check GC enable and uFIDelate flag. 271 if gcEnable { 272 job.Args[checkFlagIndexInJobArgs] = recoverBlockCheckFlagEnableGC 273 } else { 274 job.Args[checkFlagIndexInJobArgs] = recoverBlockCheckFlagDisableGC 275 } 276 277 job.SchemaState = perceptron.StateWriteOnly 278 tblInfo.State = perceptron.StateWriteOnly 279 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, false) 280 if err != nil { 281 return ver, errors.Trace(err) 282 } 283 case perceptron.StateWriteOnly: 284 // write only -> public 285 // do recover causet. 286 if gcEnable { 287 err = disableGC(w) 288 if err != nil { 289 job.State = perceptron.JobStateCancelled 290 return ver, errors.Errorf("disable gc failed, try again later. err: %v", err) 291 } 292 } 293 // check GC safe point 294 err = checkSafePoint(w, snapshotTS) 295 if err != nil { 296 job.State = perceptron.JobStateCancelled 297 return ver, errors.Trace(err) 298 } 299 // Remove dropped causet DBS job from gc_delete_range causet. 300 var tids []int64 301 if tblInfo.GetPartitionInfo() != nil { 302 tids = getPartitionIDs(tblInfo) 303 } else { 304 tids = []int64{tblInfo.ID} 305 } 306 err = w.delRangeManager.removeFromGCDeleteRange(dropJobID, tids) 307 if err != nil { 308 return ver, errors.Trace(err) 309 } 310 311 tblInfo.State = perceptron.StatePublic 312 tblInfo.UFIDelateTS = t.StartTS 313 err = t.CreateBlockAndSetAutoID(schemaID, tblInfo, autoIncID, autoRandID) 314 if err != nil { 315 return ver, errors.Trace(err) 316 } 317 318 failpoint.Inject("mockRecoverBlockCommitErr", func(val failpoint.Value) { 319 if val.(bool) && atomic.CompareAndSwapUint32(&mockRecoverBlockCommitErrOnce, 0, 1) { 320 ekv.MockCommitErrorEnable() 321 } 322 }) 323 324 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 325 if err != nil { 326 return ver, errors.Trace(err) 327 } 328 329 // Finish this job. 330 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 331 default: 332 return ver, ErrInvalidDBSState.GenWithStackByArgs("causet", tblInfo.State) 333 } 334 return ver, nil 335 } 336 337 // mockRecoverBlockCommitErrOnce uses to make sure 338 // `mockRecoverBlockCommitErr` only mock error once. 339 var mockRecoverBlockCommitErrOnce uint32 340 341 func enableGC(w *worker) error { 342 ctx, err := w.sessPool.get() 343 if err != nil { 344 return errors.Trace(err) 345 } 346 defer w.sessPool.put(ctx) 347 348 return gcutil.EnableGC(ctx) 349 } 350 351 func disableGC(w *worker) error { 352 ctx, err := w.sessPool.get() 353 if err != nil { 354 return errors.Trace(err) 355 } 356 defer w.sessPool.put(ctx) 357 358 return gcutil.DisableGC(ctx) 359 } 360 361 func checkGCEnable(w *worker) (enable bool, err error) { 362 ctx, err := w.sessPool.get() 363 if err != nil { 364 return false, errors.Trace(err) 365 } 366 defer w.sessPool.put(ctx) 367 368 return gcutil.CheckGCEnable(ctx) 369 } 370 371 func checkSafePoint(w *worker, snapshotTS uint64) error { 372 ctx, err := w.sessPool.get() 373 if err != nil { 374 return errors.Trace(err) 375 } 376 defer w.sessPool.put(ctx) 377 378 return gcutil.ValidateSnapshot(ctx, snapshotTS) 379 } 380 381 func getBlock(causetstore ekv.CausetStorage, schemaID int64, tblInfo *perceptron.BlockInfo) (causet.Block, error) { 382 allocs := autoid.NewSlabPredictorsFromTblInfo(causetstore, schemaID, tblInfo) 383 tbl, err := causet.BlockFromMeta(allocs, tblInfo) 384 return tbl, errors.Trace(err) 385 } 386 387 func getBlockInfoAndCancelFaultJob(t *spacetime.Meta, job *perceptron.Job, schemaID int64) (*perceptron.BlockInfo, error) { 388 tblInfo, err := checkBlockExistAndCancelNonExistJob(t, job, schemaID) 389 if err != nil { 390 return nil, errors.Trace(err) 391 } 392 393 if tblInfo.State != perceptron.StatePublic { 394 job.State = perceptron.JobStateCancelled 395 return nil, ErrInvalidDBSState.GenWithStack("causet %s is not in public, but %s", tblInfo.Name, tblInfo.State) 396 } 397 398 return tblInfo, nil 399 } 400 401 func checkBlockExistAndCancelNonExistJob(t *spacetime.Meta, job *perceptron.Job, schemaID int64) (*perceptron.BlockInfo, error) { 402 tblInfo, err := getBlockInfo(t, job.BlockID, schemaID) 403 if err == nil { 404 return tblInfo, nil 405 } 406 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockNotExists.Equal(err) { 407 job.State = perceptron.JobStateCancelled 408 } 409 return nil, err 410 } 411 412 func getBlockInfo(t *spacetime.Meta, blockID, schemaID int64) (*perceptron.BlockInfo, error) { 413 // Check this causet's database. 414 tblInfo, err := t.GetBlock(schemaID, blockID) 415 if err != nil { 416 if spacetime.ErrDBNotExists.Equal(err) { 417 return nil, errors.Trace(schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs( 418 fmt.Sprintf("(Schema ID %d)", schemaID), 419 )) 420 } 421 return nil, errors.Trace(err) 422 } 423 424 // Check the causet. 425 if tblInfo == nil { 426 return nil, errors.Trace(schemareplicant.ErrBlockNotExists.GenWithStackByArgs( 427 fmt.Sprintf("(Schema ID %d)", schemaID), 428 fmt.Sprintf("(Block ID %d)", blockID), 429 )) 430 } 431 return tblInfo, nil 432 } 433 434 // onTruncateBlock delete old causet spacetime, and creates a new causet identical to old causet except for causet ID. 435 // As all the old data is encoded with old causet ID, it can not be accessed any more. 436 // A background job will be created to delete old data. 437 func onTruncateBlock(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 438 schemaID := job.SchemaID 439 blockID := job.BlockID 440 var newBlockID int64 441 err := job.DecodeArgs(&newBlockID) 442 if err != nil { 443 job.State = perceptron.JobStateCancelled 444 return ver, errors.Trace(err) 445 } 446 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 447 if err != nil { 448 return ver, errors.Trace(err) 449 } 450 if tblInfo.IsView() || tblInfo.IsSequence() { 451 job.State = perceptron.JobStateCancelled 452 return ver, schemareplicant.ErrBlockNotExists.GenWithStackByArgs(job.SchemaName, tblInfo.Name.O) 453 } 454 455 err = t.DropBlockOrView(schemaID, tblInfo.ID, true) 456 if err != nil { 457 job.State = perceptron.JobStateCancelled 458 return ver, errors.Trace(err) 459 } 460 failpoint.Inject("truncateBlockErr", func(val failpoint.Value) { 461 if val.(bool) { 462 job.State = perceptron.JobStateCancelled 463 failpoint.Return(ver, errors.New("occur an error after dropping causet")) 464 } 465 }) 466 467 var oldPartitionIDs []int64 468 if tblInfo.GetPartitionInfo() != nil { 469 oldPartitionIDs = getPartitionIDs(tblInfo) 470 // We use the new partition ID because all the old data is encoded with the old partition ID, it can not be accessed anymore. 471 err = truncateBlockByReassignPartitionIDs(t, tblInfo) 472 if err != nil { 473 return ver, errors.Trace(err) 474 } 475 } 476 477 // Clear the tiflash replica available status. 478 if tblInfo.TiFlashReplica != nil { 479 tblInfo.TiFlashReplica.AvailablePartitionIDs = nil 480 tblInfo.TiFlashReplica.Available = false 481 } 482 483 tblInfo.ID = newBlockID 484 err = t.CreateBlockOrView(schemaID, tblInfo) 485 if err != nil { 486 job.State = perceptron.JobStateCancelled 487 return ver, errors.Trace(err) 488 } 489 490 failpoint.Inject("mockTruncateBlockUFIDelateVersionError", func(val failpoint.Value) { 491 if val.(bool) { 492 failpoint.Return(ver, errors.New("mock uFIDelate version error")) 493 } 494 }) 495 496 ver, err = uFIDelateSchemaVersion(t, job) 497 if err != nil { 498 return ver, errors.Trace(err) 499 } 500 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 501 asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionTruncateBlock, BlockInfo: tblInfo}) 502 startKey := blockcodec.EncodeBlockPrefix(blockID) 503 job.Args = []interface{}{startKey, oldPartitionIDs} 504 return ver, nil 505 } 506 507 func onRebaseRowIDType(causetstore ekv.CausetStorage, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 508 return onRebaseAutoID(causetstore, t, job, autoid.RowIDAllocType) 509 } 510 511 func onRebaseAutoRandomType(causetstore ekv.CausetStorage, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 512 return onRebaseAutoID(causetstore, t, job, autoid.AutoRandomType) 513 } 514 515 func onRebaseAutoID(causetstore ekv.CausetStorage, t *spacetime.Meta, job *perceptron.Job, tp autoid.SlabPredictorType) (ver int64, _ error) { 516 schemaID := job.SchemaID 517 var newBase int64 518 err := job.DecodeArgs(&newBase) 519 if err != nil { 520 job.State = perceptron.JobStateCancelled 521 return ver, errors.Trace(err) 522 } 523 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 524 if err != nil { 525 job.State = perceptron.JobStateCancelled 526 return ver, errors.Trace(err) 527 } 528 // No need to check `newBase` again, because `RebaseAutoID` will do this check. 529 if tp == autoid.RowIDAllocType { 530 tblInfo.AutoIncID = newBase 531 } else { 532 tblInfo.AutoRandID = newBase 533 } 534 535 tbl, err := getBlock(causetstore, schemaID, tblInfo) 536 if err != nil { 537 job.State = perceptron.JobStateCancelled 538 return ver, errors.Trace(err) 539 } 540 if alloc := tbl.SlabPredictors(nil).Get(tp); alloc != nil { 541 // The next value to allocate is `newBase`. 542 newEnd := newBase - 1 543 err = alloc.Rebase(tblInfo.ID, newEnd, false) 544 if err != nil { 545 return ver, errors.Trace(err) 546 } 547 } 548 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 549 if err != nil { 550 return ver, errors.Trace(err) 551 } 552 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 553 return ver, nil 554 } 555 556 func onModifyBlockAutoIDCache(t *spacetime.Meta, job *perceptron.Job) (int64, error) { 557 var cache int64 558 if err := job.DecodeArgs(&cache); err != nil { 559 job.State = perceptron.JobStateCancelled 560 return 0, errors.Trace(err) 561 } 562 563 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 564 if err != nil { 565 return 0, errors.Trace(err) 566 } 567 568 tblInfo.AutoIdCache = cache 569 ver, err := uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 570 if err != nil { 571 return ver, errors.Trace(err) 572 } 573 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 574 return ver, nil 575 } 576 577 func (w *worker) onShardRowID(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 578 var shardRowIDBits uint64 579 err := job.DecodeArgs(&shardRowIDBits) 580 if err != nil { 581 job.State = perceptron.JobStateCancelled 582 return ver, errors.Trace(err) 583 } 584 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 585 if err != nil { 586 job.State = perceptron.JobStateCancelled 587 return ver, errors.Trace(err) 588 } 589 if shardRowIDBits < tblInfo.ShardRowIDBits { 590 tblInfo.ShardRowIDBits = shardRowIDBits 591 } else { 592 tbl, err := getBlock(d.causetstore, job.SchemaID, tblInfo) 593 if err != nil { 594 return ver, errors.Trace(err) 595 } 596 err = verifyNoOverflowShardBits(w.sessPool, tbl, shardRowIDBits) 597 if err != nil { 598 job.State = perceptron.JobStateCancelled 599 return ver, err 600 } 601 tblInfo.ShardRowIDBits = shardRowIDBits 602 // MaxShardRowIDBits use to check the overflow of auto ID. 603 tblInfo.MaxShardRowIDBits = shardRowIDBits 604 } 605 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 606 if err != nil { 607 job.State = perceptron.JobStateCancelled 608 return ver, errors.Trace(err) 609 } 610 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 611 return ver, nil 612 } 613 614 func verifyNoOverflowShardBits(s *stochastikPool, tbl causet.Block, shardRowIDBits uint64) error { 615 ctx, err := s.get() 616 if err != nil { 617 return errors.Trace(err) 618 } 619 defer s.put(ctx) 620 621 // Check next global max auto ID first. 622 autoIncID, err := tbl.SlabPredictors(ctx).Get(autoid.RowIDAllocType).NextGlobalAutoID(tbl.Meta().ID) 623 if err != nil { 624 return errors.Trace(err) 625 } 626 if blocks.OverflowShardBits(autoIncID, shardRowIDBits, autoid.RowIDBitLength, true) { 627 return autoid.ErrAutoincReadFailed.GenWithStack("shard_row_id_bits %d will cause next global auto ID %v overflow", shardRowIDBits, autoIncID) 628 } 629 return nil 630 } 631 632 func onRenameBlock(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 633 var oldSchemaID int64 634 var blockName perceptron.CIStr 635 if err := job.DecodeArgs(&oldSchemaID, &blockName); err != nil { 636 // Invalid arguments, cancel this job. 637 job.State = perceptron.JobStateCancelled 638 return ver, errors.Trace(err) 639 } 640 641 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, oldSchemaID) 642 if err != nil { 643 return ver, errors.Trace(err) 644 } 645 newSchemaID := job.SchemaID 646 err = checkBlockNotExists(d, t, newSchemaID, blockName.L) 647 if err != nil { 648 if schemareplicant.ErrDatabaseNotExists.Equal(err) || schemareplicant.ErrBlockExists.Equal(err) { 649 job.State = perceptron.JobStateCancelled 650 } 651 return ver, errors.Trace(err) 652 } 653 654 var autoBlockID int64 655 var autoRandID int64 656 shouldDelAutoID := false 657 if newSchemaID != oldSchemaID { 658 shouldDelAutoID = true 659 autoBlockID, err = t.GetAutoBlockID(tblInfo.GetDBID(oldSchemaID), tblInfo.ID) 660 if err != nil { 661 job.State = perceptron.JobStateCancelled 662 return ver, errors.Trace(err) 663 } 664 autoRandID, err = t.GetAutoRandomID(tblInfo.GetDBID(oldSchemaID), tblInfo.ID) 665 if err != nil { 666 job.State = perceptron.JobStateCancelled 667 return ver, errors.Trace(err) 668 } 669 // It's compatible with old version. 670 // TODO: Remove it. 671 tblInfo.OldSchemaID = 0 672 } 673 674 err = t.DropBlockOrView(oldSchemaID, tblInfo.ID, shouldDelAutoID) 675 if err != nil { 676 job.State = perceptron.JobStateCancelled 677 return ver, errors.Trace(err) 678 } 679 680 failpoint.Inject("renameBlockErr", func(val failpoint.Value) { 681 if val.(bool) { 682 job.State = perceptron.JobStateCancelled 683 failpoint.Return(ver, errors.New("occur an error after renaming causet")) 684 } 685 }) 686 687 tblInfo.Name = blockName 688 err = t.CreateBlockOrView(newSchemaID, tblInfo) 689 if err != nil { 690 job.State = perceptron.JobStateCancelled 691 return ver, errors.Trace(err) 692 } 693 // UFIDelate the causet's auto-increment ID. 694 if newSchemaID != oldSchemaID { 695 _, err = t.GenAutoBlockID(newSchemaID, tblInfo.ID, autoBlockID) 696 if err != nil { 697 job.State = perceptron.JobStateCancelled 698 return ver, errors.Trace(err) 699 } 700 _, err = t.GenAutoRandomID(newSchemaID, tblInfo.ID, autoRandID) 701 if err != nil { 702 job.State = perceptron.JobStateCancelled 703 return ver, errors.Trace(err) 704 } 705 } 706 707 ver, err = uFIDelateSchemaVersion(t, job) 708 if err != nil { 709 return ver, errors.Trace(err) 710 } 711 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 712 return ver, nil 713 } 714 715 func onModifyBlockComment(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 716 var comment string 717 if err := job.DecodeArgs(&comment); err != nil { 718 job.State = perceptron.JobStateCancelled 719 return ver, errors.Trace(err) 720 } 721 722 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 723 if err != nil { 724 return ver, errors.Trace(err) 725 } 726 727 tblInfo.Comment = comment 728 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 729 if err != nil { 730 return ver, errors.Trace(err) 731 } 732 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 733 return ver, nil 734 } 735 736 func onModifyBlockCharsetAndDefCauslate(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 737 var toCharset, toDefCauslate string 738 var needsOverwriteDefCauss bool 739 if err := job.DecodeArgs(&toCharset, &toDefCauslate, &needsOverwriteDefCauss); err != nil { 740 job.State = perceptron.JobStateCancelled 741 return ver, errors.Trace(err) 742 } 743 744 dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job) 745 if err != nil { 746 return ver, errors.Trace(err) 747 } 748 749 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 750 if err != nil { 751 return ver, errors.Trace(err) 752 } 753 754 // double check. 755 _, err = checkAlterBlockCharset(tblInfo, dbInfo, toCharset, toDefCauslate, needsOverwriteDefCauss) 756 if err != nil { 757 job.State = perceptron.JobStateCancelled 758 return ver, errors.Trace(err) 759 } 760 761 tblInfo.Charset = toCharset 762 tblInfo.DefCauslate = toDefCauslate 763 764 if needsOverwriteDefCauss { 765 // uFIDelate defCausumn charset. 766 for _, defCaus := range tblInfo.DeferredCausets { 767 if field_types.HasCharset(&defCaus.FieldType) { 768 defCaus.Charset = toCharset 769 defCaus.DefCauslate = toDefCauslate 770 } else { 771 defCaus.Charset = charset.CharsetBin 772 defCaus.DefCauslate = charset.CharsetBin 773 } 774 } 775 } 776 777 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 778 if err != nil { 779 return ver, errors.Trace(err) 780 } 781 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 782 return ver, nil 783 } 784 785 func (w *worker) onSetBlockFlashReplica(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 786 var replicaInfo ast.TiFlashReplicaSpec 787 if err := job.DecodeArgs(&replicaInfo); err != nil { 788 job.State = perceptron.JobStateCancelled 789 return ver, errors.Trace(err) 790 } 791 792 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 793 if err != nil { 794 return ver, errors.Trace(err) 795 } 796 797 err = w.checkTiFlashReplicaCount(replicaInfo.Count) 798 if err != nil { 799 job.State = perceptron.JobStateCancelled 800 return ver, errors.Trace(err) 801 } 802 803 if replicaInfo.Count > 0 { 804 tblInfo.TiFlashReplica = &perceptron.TiFlashReplicaInfo{ 805 Count: replicaInfo.Count, 806 LocationLabels: replicaInfo.Labels, 807 } 808 } else { 809 tblInfo.TiFlashReplica = nil 810 } 811 812 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 813 if err != nil { 814 return ver, errors.Trace(err) 815 } 816 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 817 return ver, nil 818 } 819 820 func (w *worker) checkTiFlashReplicaCount(replicaCount uint64) error { 821 ctx, err := w.sessPool.get() 822 if err != nil { 823 return errors.Trace(err) 824 } 825 defer w.sessPool.put(ctx) 826 827 return checkTiFlashReplicaCount(ctx, replicaCount) 828 } 829 830 func onUFIDelateFlashReplicaStatus(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 831 var available bool 832 var physicalID int64 833 if err := job.DecodeArgs(&available, &physicalID); err != nil { 834 job.State = perceptron.JobStateCancelled 835 return ver, errors.Trace(err) 836 } 837 838 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 839 if err != nil { 840 return ver, errors.Trace(err) 841 } 842 if tblInfo.TiFlashReplica == nil || (tblInfo.ID == physicalID && tblInfo.TiFlashReplica.Available == available) || 843 (tblInfo.ID != physicalID && available == tblInfo.TiFlashReplica.IsPartitionAvailable(physicalID)) { 844 job.State = perceptron.JobStateCancelled 845 return ver, errors.Errorf("the replica available status of causet %s is already uFIDelated", tblInfo.Name.String()) 846 } 847 848 if tblInfo.ID == physicalID { 849 tblInfo.TiFlashReplica.Available = available 850 } else if pi := tblInfo.GetPartitionInfo(); pi != nil { 851 // Partition replica become available. 852 if available { 853 allAvailable := true 854 for _, p := range pi.Definitions { 855 if p.ID == physicalID { 856 tblInfo.TiFlashReplica.AvailablePartitionIDs = append(tblInfo.TiFlashReplica.AvailablePartitionIDs, physicalID) 857 } 858 allAvailable = allAvailable && tblInfo.TiFlashReplica.IsPartitionAvailable(p.ID) 859 } 860 tblInfo.TiFlashReplica.Available = allAvailable 861 } else { 862 // Partition replica become unavailable. 863 for i, id := range tblInfo.TiFlashReplica.AvailablePartitionIDs { 864 if id == physicalID { 865 newIDs := tblInfo.TiFlashReplica.AvailablePartitionIDs[:i] 866 newIDs = append(newIDs, tblInfo.TiFlashReplica.AvailablePartitionIDs[i+1:]...) 867 tblInfo.TiFlashReplica.AvailablePartitionIDs = newIDs 868 tblInfo.TiFlashReplica.Available = false 869 break 870 } 871 } 872 } 873 } else { 874 job.State = perceptron.JobStateCancelled 875 return ver, errors.Errorf("unknown physical ID %v in causet %v", physicalID, tblInfo.Name.O) 876 } 877 878 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 879 if err != nil { 880 return ver, errors.Trace(err) 881 } 882 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 883 return ver, nil 884 } 885 886 func checkBlockNotExists(d *dbsCtx, t *spacetime.Meta, schemaID int64, blockName string) error { 887 // d.infoHandle maybe nil in some test. 888 if d.infoHandle == nil || !d.infoHandle.IsValid() { 889 return checkBlockNotExistsFromStore(t, schemaID, blockName) 890 } 891 // Try to use memory schemaReplicant info to check first. 892 currVer, err := t.GetSchemaVersion() 893 if err != nil { 894 return err 895 } 896 is := d.infoHandle.Get() 897 if is.SchemaMetaVersion() == currVer { 898 return checkBlockNotExistsFromSchemaReplicant(is, schemaID, blockName) 899 } 900 901 return checkBlockNotExistsFromStore(t, schemaID, blockName) 902 } 903 904 func checkBlockIDNotExists(t *spacetime.Meta, schemaID, blockID int64) error { 905 tbl, err := t.GetBlock(schemaID, blockID) 906 if err != nil { 907 if spacetime.ErrDBNotExists.Equal(err) { 908 return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs("") 909 } 910 return errors.Trace(err) 911 } 912 if tbl != nil { 913 return schemareplicant.ErrBlockExists.GenWithStackByArgs(tbl.Name) 914 } 915 return nil 916 } 917 918 func checkBlockNotExistsFromSchemaReplicant(is schemareplicant.SchemaReplicant, schemaID int64, blockName string) error { 919 // Check this causet's database. 920 schemaReplicant, ok := is.SchemaByID(schemaID) 921 if !ok { 922 return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs("") 923 } 924 if is.BlockExists(schemaReplicant.Name, perceptron.NewCIStr(blockName)) { 925 return schemareplicant.ErrBlockExists.GenWithStackByArgs(blockName) 926 } 927 return nil 928 } 929 930 func checkBlockNotExistsFromStore(t *spacetime.Meta, schemaID int64, blockName string) error { 931 // Check this causet's database. 932 blocks, err := t.ListBlocks(schemaID) 933 if err != nil { 934 if spacetime.ErrDBNotExists.Equal(err) { 935 return schemareplicant.ErrDatabaseNotExists.GenWithStackByArgs("") 936 } 937 return errors.Trace(err) 938 } 939 940 // Check the causet. 941 for _, tbl := range blocks { 942 if tbl.Name.L == blockName { 943 return schemareplicant.ErrBlockExists.GenWithStackByArgs(tbl.Name) 944 } 945 } 946 947 return nil 948 } 949 950 // uFIDelateVersionAndBlockInfoWithCheck checks causet info validate and uFIDelates the schemaReplicant version and the causet information 951 func uFIDelateVersionAndBlockInfoWithCheck(t *spacetime.Meta, job *perceptron.Job, tblInfo *perceptron.BlockInfo, shouldUFIDelateVer bool) ( 952 ver int64, err error) { 953 err = checkBlockInfoValid(tblInfo) 954 if err != nil { 955 job.State = perceptron.JobStateCancelled 956 return ver, errors.Trace(err) 957 } 958 return uFIDelateVersionAndBlockInfo(t, job, tblInfo, shouldUFIDelateVer) 959 } 960 961 // uFIDelateVersionAndBlockInfo uFIDelates the schemaReplicant version and the causet information. 962 func uFIDelateVersionAndBlockInfo(t *spacetime.Meta, job *perceptron.Job, tblInfo *perceptron.BlockInfo, shouldUFIDelateVer bool) ( 963 ver int64, err error) { 964 failpoint.Inject("mockUFIDelateVersionAndBlockInfoErr", func(val failpoint.Value) { 965 switch val.(int) { 966 case 1: 967 failpoint.Return(ver, errors.New("mock uFIDelate version and blockInfo error")) 968 case 2: 969 // We change it cancelled directly here, because we want to get the original error with the job id appended. 970 // The job ID will be used to get the job from history queue and we will assert it's args. 971 job.State = perceptron.JobStateCancelled 972 failpoint.Return(ver, errors.New("mock uFIDelate version and blockInfo error, jobID="+strconv.Itoa(int(job.ID)))) 973 default: 974 } 975 }) 976 if shouldUFIDelateVer { 977 ver, err = uFIDelateSchemaVersion(t, job) 978 if err != nil { 979 return 0, errors.Trace(err) 980 } 981 } 982 983 if tblInfo.State == perceptron.StatePublic { 984 tblInfo.UFIDelateTS = t.StartTS 985 } 986 return ver, t.UFIDelateBlock(job.SchemaID, tblInfo) 987 } 988 989 func onRepairBlock(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 990 schemaID := job.SchemaID 991 tblInfo := &perceptron.BlockInfo{} 992 993 if err := job.DecodeArgs(tblInfo); err != nil { 994 // Invalid arguments, cancel this job. 995 job.State = perceptron.JobStateCancelled 996 return ver, errors.Trace(err) 997 } 998 999 tblInfo.State = perceptron.StateNone 1000 1001 // Check the old EDB and old causet exist. 1002 _, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 1003 if err != nil { 1004 return ver, errors.Trace(err) 1005 } 1006 1007 // When in repair mode, the repaired causet in a server is not access to user, 1008 // the causet after repairing will be removed from repair list. Other server left 1009 // behind alive may need to restart to get the latest schemaReplicant version. 1010 ver, err = uFIDelateSchemaVersion(t, job) 1011 if err != nil { 1012 return ver, errors.Trace(err) 1013 } 1014 switch tblInfo.State { 1015 case perceptron.StateNone: 1016 // none -> public 1017 tblInfo.State = perceptron.StatePublic 1018 tblInfo.UFIDelateTS = t.StartTS 1019 err = repairBlockOrViewWithCheck(t, job, schemaID, tblInfo) 1020 if err != nil { 1021 return ver, errors.Trace(err) 1022 } 1023 // Finish this job. 1024 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 1025 asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionRepairBlock, BlockInfo: tblInfo}) 1026 return ver, nil 1027 default: 1028 return ver, ErrInvalidDBSState.GenWithStackByArgs("causet", tblInfo.State) 1029 } 1030 }