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  }