github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/index.go (about)

     1  // Copyright 2020 WHTCORPS INC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package dbs
    15  
    16  import (
    17  	"context"
    18  	"math"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/prometheus/client_golang/prometheus"
    23  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    24  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    25  	"github.com/whtcorpsinc/BerolinaSQL/charset"
    26  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    27  	"github.com/whtcorpsinc/errors"
    28  	"github.com/whtcorpsinc/failpoint"
    29  	"github.com/whtcorpsinc/milevadb/blockcodec"
    30  	"github.com/whtcorpsinc/milevadb/causet"
    31  	"github.com/whtcorpsinc/milevadb/causet/blocks"
    32  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    33  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle"
    34  	"github.com/whtcorpsinc/milevadb/config"
    35  	"github.com/whtcorpsinc/milevadb/ekv"
    36  	"github.com/whtcorpsinc/milevadb/metrics"
    37  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    38  	"github.com/whtcorpsinc/milevadb/soliton"
    39  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    40  	causetDecoder "github.com/whtcorpsinc/milevadb/soliton/rowCausetDecoder"
    41  	"github.com/whtcorpsinc/milevadb/soliton/timeutil"
    42  	"github.com/whtcorpsinc/milevadb/spacetime"
    43  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    44  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    45  	"github.com/whtcorpsinc/milevadb/types"
    46  	"go.uber.org/zap"
    47  )
    48  
    49  const (
    50  	// MaxCommentLength is exported for testing.
    51  	MaxCommentLength = 1024
    52  )
    53  
    54  func buildIndexDeferredCausets(columns []*perceptron.DeferredCausetInfo, indexPartSpecifications []*ast.IndexPartSpecification) ([]*perceptron.IndexDeferredCauset, error) {
    55  	// Build offsets.
    56  	idxParts := make([]*perceptron.IndexDeferredCauset, 0, len(indexPartSpecifications))
    57  	var col *perceptron.DeferredCausetInfo
    58  
    59  	// The sum of length of all index columns.
    60  	sumLength := 0
    61  	for _, ip := range indexPartSpecifications {
    62  		col = perceptron.FindDeferredCausetInfo(columns, ip.DeferredCauset.Name.L)
    63  		if col == nil {
    64  			return nil, errKeyDeferredCausetDoesNotExits.GenWithStack("column does not exist: %s", ip.DeferredCauset.Name)
    65  		}
    66  
    67  		if err := checHoTTexDeferredCauset(col, ip); err != nil {
    68  			return nil, err
    69  		}
    70  
    71  		indexDeferredCausetLength, err := getIndexDeferredCausetLength(col, ip.Length)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		sumLength += indexDeferredCausetLength
    76  
    77  		// The sum of all lengths must be shorter than the max length for prefix.
    78  		if sumLength > config.GetGlobalConfig().MaxIndexLength {
    79  			return nil, errTooLongKey.GenWithStackByArgs(config.GetGlobalConfig().MaxIndexLength)
    80  		}
    81  
    82  		idxParts = append(idxParts, &perceptron.IndexDeferredCauset{
    83  			Name:   col.Name,
    84  			Offset: col.Offset,
    85  			Length: ip.Length,
    86  		})
    87  	}
    88  
    89  	return idxParts, nil
    90  }
    91  
    92  func checkPKOnGeneratedDeferredCauset(tblInfo *perceptron.BlockInfo, indexPartSpecifications []*ast.IndexPartSpecification) (*perceptron.DeferredCausetInfo, error) {
    93  	var lastDefCaus *perceptron.DeferredCausetInfo
    94  	for _, colName := range indexPartSpecifications {
    95  		lastDefCaus = getDeferredCausetInfoByName(tblInfo, colName.DeferredCauset.Name.L)
    96  		if lastDefCaus == nil {
    97  			return nil, errKeyDeferredCausetDoesNotExits.GenWithStackByArgs(colName.DeferredCauset.Name)
    98  		}
    99  		// Virtual columns cannot be used in primary key.
   100  		if lastDefCaus.IsGenerated() && !lastDefCaus.GeneratedStored {
   101  			return nil, ErrUnsupportedOnGeneratedDeferredCauset.GenWithStackByArgs("Defining a virtual generated column as primary key")
   102  		}
   103  	}
   104  
   105  	return lastDefCaus, nil
   106  }
   107  
   108  func checHoTTexPrefixLength(columns []*perceptron.DeferredCausetInfo, idxDeferredCausets []*perceptron.IndexDeferredCauset) error {
   109  	// The sum of length of all index columns.
   110  	sumLength := 0
   111  	for _, ic := range idxDeferredCausets {
   112  		col := perceptron.FindDeferredCausetInfo(columns, ic.Name.L)
   113  		if col == nil {
   114  			return errKeyDeferredCausetDoesNotExits.GenWithStack("column does not exist: %s", ic.Name)
   115  		}
   116  
   117  		indexDeferredCausetLength, err := getIndexDeferredCausetLength(col, ic.Length)
   118  		if err != nil {
   119  			return err
   120  		}
   121  		sumLength += indexDeferredCausetLength
   122  		// The sum of all lengths must be shorter than the max length for prefix.
   123  		if sumLength > config.GetGlobalConfig().MaxIndexLength {
   124  			return errTooLongKey.GenWithStackByArgs(config.GetGlobalConfig().MaxIndexLength)
   125  		}
   126  	}
   127  	return nil
   128  }
   129  
   130  func checHoTTexDeferredCauset(col *perceptron.DeferredCausetInfo, ic *ast.IndexPartSpecification) error {
   131  	if col.Flen == 0 && (types.IsTypeChar(col.FieldType.Tp) || types.IsTypeVarchar(col.FieldType.Tp)) {
   132  		return errors.Trace(errWrongKeyDeferredCauset.GenWithStackByArgs(ic.DeferredCauset.Name))
   133  	}
   134  
   135  	// JSON column cannot index.
   136  	if col.FieldType.Tp == allegrosql.TypeJSON {
   137  		return errors.Trace(errJSONUsedAsKey.GenWithStackByArgs(col.Name.O))
   138  	}
   139  
   140  	// Length must be specified and non-zero for BLOB and TEXT column indexes.
   141  	if types.IsTypeBlob(col.FieldType.Tp) {
   142  		if ic.Length == types.UnspecifiedLength {
   143  			return errors.Trace(errBlobKeyWithoutLength.GenWithStackByArgs(col.Name.O))
   144  		}
   145  		if ic.Length == types.ErrorLength {
   146  			return errors.Trace(errKeyPart0.GenWithStackByArgs(col.Name.O))
   147  		}
   148  	}
   149  
   150  	// Length can only be specified for specifiable types.
   151  	if ic.Length != types.UnspecifiedLength && !types.IsTypePrefixable(col.FieldType.Tp) {
   152  		return errors.Trace(errIncorrectPrefixKey)
   153  	}
   154  
   155  	// Key length must be shorter or equal to the column length.
   156  	if ic.Length != types.UnspecifiedLength &&
   157  		types.IsTypeChar(col.FieldType.Tp) {
   158  		if col.Flen < ic.Length {
   159  			return errors.Trace(errIncorrectPrefixKey)
   160  		}
   161  		// Length must be non-zero for char.
   162  		if ic.Length == types.ErrorLength {
   163  			return errors.Trace(errKeyPart0.GenWithStackByArgs(col.Name.O))
   164  		}
   165  	}
   166  
   167  	// Specified length must be shorter than the max length for prefix.
   168  	if ic.Length > config.GetGlobalConfig().MaxIndexLength {
   169  		return errTooLongKey.GenWithStackByArgs(config.GetGlobalConfig().MaxIndexLength)
   170  	}
   171  	return nil
   172  }
   173  
   174  // getIndexDeferredCausetLength calculate the bytes number required in an index column.
   175  func getIndexDeferredCausetLength(col *perceptron.DeferredCausetInfo, colLen int) (int, error) {
   176  	length := types.UnspecifiedLength
   177  	if colLen != types.UnspecifiedLength {
   178  		length = colLen
   179  	} else if col.Flen != types.UnspecifiedLength {
   180  		length = col.Flen
   181  	}
   182  
   183  	switch col.Tp {
   184  	case allegrosql.TypeBit:
   185  		return (length + 7) >> 3, nil
   186  	case allegrosql.TypeVarchar, allegrosql.TypeString:
   187  		// Different charsets occupy different numbers of bytes on each character.
   188  		desc, err := charset.GetCharsetDesc(col.Charset)
   189  		if err != nil {
   190  			return 0, errUnsupportedCharset.GenWithStackByArgs(col.Charset, col.DefCauslate)
   191  		}
   192  		return desc.Maxlen * length, nil
   193  	case allegrosql.TypeTinyBlob, allegrosql.TypeMediumBlob, allegrosql.TypeBlob, allegrosql.TypeLongBlob:
   194  		return length, nil
   195  	case allegrosql.TypeTiny, allegrosql.TypeInt24, allegrosql.TypeLong, allegrosql.TypeLonglong, allegrosql.TypeDouble, allegrosql.TypeShort:
   196  		return allegrosql.DefaultLengthOfMysqlTypes[col.Tp], nil
   197  	case allegrosql.TypeFloat:
   198  		if length <= allegrosql.MaxFloatPrecisionLength {
   199  			return allegrosql.DefaultLengthOfMysqlTypes[allegrosql.TypeFloat], nil
   200  		}
   201  		return allegrosql.DefaultLengthOfMysqlTypes[allegrosql.TypeDouble], nil
   202  	case allegrosql.TypeNewDecimal:
   203  		return calcBytesLengthForDecimal(length), nil
   204  	case allegrosql.TypeYear, allegrosql.TypeDate, allegrosql.TypeDuration, allegrosql.TypeDatetime, allegrosql.TypeTimestamp:
   205  		return allegrosql.DefaultLengthOfMysqlTypes[col.Tp], nil
   206  	default:
   207  		return length, nil
   208  	}
   209  }
   210  
   211  // Decimal using a binary format that packs nine decimal (base 10) digits into four bytes.
   212  func calcBytesLengthForDecimal(m int) int {
   213  	return (m / 9 * 4) + ((m%9)+1)/2
   214  }
   215  
   216  func buildIndexInfo(tblInfo *perceptron.BlockInfo, indexName perceptron.CIStr, indexPartSpecifications []*ast.IndexPartSpecification, state perceptron.SchemaState) (*perceptron.IndexInfo, error) {
   217  	if err := checkTooLongIndex(indexName); err != nil {
   218  		return nil, errors.Trace(err)
   219  	}
   220  
   221  	idxDeferredCausets, err := buildIndexDeferredCausets(tblInfo.DeferredCausets, indexPartSpecifications)
   222  	if err != nil {
   223  		return nil, errors.Trace(err)
   224  	}
   225  
   226  	// Create index info.
   227  	idxInfo := &perceptron.IndexInfo{
   228  		Name:            indexName,
   229  		DeferredCausets: idxDeferredCausets,
   230  		State:           state,
   231  	}
   232  	return idxInfo, nil
   233  }
   234  
   235  func addIndexDeferredCausetFlag(tblInfo *perceptron.BlockInfo, indexInfo *perceptron.IndexInfo) {
   236  	if indexInfo.Primary {
   237  		for _, col := range indexInfo.DeferredCausets {
   238  			tblInfo.DeferredCausets[col.Offset].Flag |= allegrosql.PriKeyFlag
   239  		}
   240  		return
   241  	}
   242  
   243  	col := indexInfo.DeferredCausets[0]
   244  	if indexInfo.Unique && len(indexInfo.DeferredCausets) == 1 {
   245  		tblInfo.DeferredCausets[col.Offset].Flag |= allegrosql.UniqueKeyFlag
   246  	} else {
   247  		tblInfo.DeferredCausets[col.Offset].Flag |= allegrosql.MultipleKeyFlag
   248  	}
   249  }
   250  
   251  func dropIndexDeferredCausetFlag(tblInfo *perceptron.BlockInfo, indexInfo *perceptron.IndexInfo) {
   252  	if indexInfo.Primary {
   253  		for _, col := range indexInfo.DeferredCausets {
   254  			tblInfo.DeferredCausets[col.Offset].Flag &= ^allegrosql.PriKeyFlag
   255  		}
   256  	} else if indexInfo.Unique && len(indexInfo.DeferredCausets) == 1 {
   257  		tblInfo.DeferredCausets[indexInfo.DeferredCausets[0].Offset].Flag &= ^allegrosql.UniqueKeyFlag
   258  	} else {
   259  		tblInfo.DeferredCausets[indexInfo.DeferredCausets[0].Offset].Flag &= ^allegrosql.MultipleKeyFlag
   260  	}
   261  
   262  	col := indexInfo.DeferredCausets[0]
   263  	// other index may still cover this col
   264  	for _, index := range tblInfo.Indices {
   265  		if index.Name.L == indexInfo.Name.L {
   266  			continue
   267  		}
   268  
   269  		if index.DeferredCausets[0].Name.L != col.Name.L {
   270  			continue
   271  		}
   272  
   273  		addIndexDeferredCausetFlag(tblInfo, index)
   274  	}
   275  }
   276  
   277  func validateRenameIndex(from, to perceptron.CIStr, tbl *perceptron.BlockInfo) (ignore bool, err error) {
   278  	if fromIdx := tbl.FindIndexByName(from.L); fromIdx == nil {
   279  		return false, errors.Trace(schemareplicant.ErrKeyNotExists.GenWithStackByArgs(from.O, tbl.Name))
   280  	}
   281  	// Take case-sensitivity into account, if `FromKey` and  `ToKey` are the same, nothing need to be changed
   282  	if from.O == to.O {
   283  		return true, nil
   284  	}
   285  	// If spec.FromKey.L == spec.ToKey.L, we operate on the same index(case-insensitive) and change its name (case-sensitive)
   286  	// e.g: from `inDex` to `IndEX`. Otherwise, we try to rename an index to another different index which already exists,
   287  	// that's illegal by rule.
   288  	if toIdx := tbl.FindIndexByName(to.L); toIdx != nil && from.L != to.L {
   289  		return false, errors.Trace(schemareplicant.ErrKeyNameDuplicate.GenWithStackByArgs(toIdx.Name.O))
   290  	}
   291  	return false, nil
   292  }
   293  
   294  func onRenameIndex(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) {
   295  	tblInfo, from, to, err := checkRenameIndex(t, job)
   296  	if err != nil || tblInfo == nil {
   297  		return ver, errors.Trace(err)
   298  	}
   299  
   300  	idx := tblInfo.FindIndexByName(from.L)
   301  	idx.Name = to
   302  	if ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true); err != nil {
   303  		job.State = perceptron.JobStateCancelled
   304  		return ver, errors.Trace(err)
   305  	}
   306  	job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo)
   307  	return ver, nil
   308  }
   309  
   310  func validateAlterIndexVisibility(indexName perceptron.CIStr, invisible bool, tbl *perceptron.BlockInfo) (bool, error) {
   311  	if idx := tbl.FindIndexByName(indexName.L); idx == nil {
   312  		return false, errors.Trace(schemareplicant.ErrKeyNotExists.GenWithStackByArgs(indexName.O, tbl.Name))
   313  	} else if idx.Invisible == invisible {
   314  		return true, nil
   315  	}
   316  	return false, nil
   317  }
   318  
   319  func onAlterIndexVisibility(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) {
   320  	tblInfo, from, invisible, err := checkAlterIndexVisibility(t, job)
   321  	if err != nil || tblInfo == nil {
   322  		return ver, errors.Trace(err)
   323  	}
   324  	idx := tblInfo.FindIndexByName(from.L)
   325  	idx.Invisible = invisible
   326  	if ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, true); err != nil {
   327  		job.State = perceptron.JobStateCancelled
   328  		return ver, errors.Trace(err)
   329  	}
   330  	job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo)
   331  	return ver, nil
   332  }
   333  
   334  func getNullDefCausInfos(tblInfo *perceptron.BlockInfo, indexInfo *perceptron.IndexInfo) ([]*perceptron.DeferredCausetInfo, error) {
   335  	nullDefCauss := make([]*perceptron.DeferredCausetInfo, 0, len(indexInfo.DeferredCausets))
   336  	for _, colName := range indexInfo.DeferredCausets {
   337  		col := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, colName.Name.L)
   338  		if !allegrosql.HasNotNullFlag(col.Flag) || allegrosql.HasPreventNullInsertFlag(col.Flag) {
   339  			nullDefCauss = append(nullDefCauss, col)
   340  		}
   341  	}
   342  	return nullDefCauss, nil
   343  }
   344  
   345  func checkPrimaryKeyNotNull(w *worker, sqlMode allegrosql.ALLEGROSQLMode, t *spacetime.Meta, job *perceptron.Job,
   346  	tblInfo *perceptron.BlockInfo, indexInfo *perceptron.IndexInfo) (warnings []string, err error) {
   347  	if !indexInfo.Primary {
   348  		return nil, nil
   349  	}
   350  
   351  	dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job)
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  	nullDefCauss, err := getNullDefCausInfos(tblInfo, indexInfo)
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	if len(nullDefCauss) == 0 {
   360  		return nil, nil
   361  	}
   362  
   363  	err = modifyDefCaussFromNull2NotNull(w, dbInfo, tblInfo, nullDefCauss, perceptron.NewCIStr(""), false)
   364  	if err == nil {
   365  		return nil, nil
   366  	}
   367  	_, err = convertAddIdxJob2RollbackJob(t, job, tblInfo, indexInfo, err)
   368  	// TODO: Support non-strict mode.
   369  	// warnings = append(warnings, ErrWarnDataTruncated.GenWithStackByArgs(oldDefCaus.Name.L, 0).Error())
   370  	return nil, err
   371  }
   372  
   373  func uFIDelateHiddenDeferredCausets(tblInfo *perceptron.BlockInfo, idxInfo *perceptron.IndexInfo, state perceptron.SchemaState) {
   374  	for _, col := range idxInfo.DeferredCausets {
   375  		if tblInfo.DeferredCausets[col.Offset].Hidden {
   376  			tblInfo.DeferredCausets[col.Offset].State = state
   377  		}
   378  	}
   379  }
   380  
   381  func (w *worker) onCreateIndex(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job, isPK bool) (ver int64, err error) {
   382  	// Handle the rolling back job.
   383  	if job.IsRollingback() {
   384  		ver, err = onDropIndex(t, job)
   385  		if err != nil {
   386  			return ver, errors.Trace(err)
   387  		}
   388  		return ver, nil
   389  	}
   390  
   391  	// Handle normal job.
   392  	schemaID := job.SchemaID
   393  	tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID)
   394  	if err != nil {
   395  		return ver, errors.Trace(err)
   396  	}
   397  
   398  	var (
   399  		unique                  bool
   400  		global                  bool
   401  		indexName               perceptron.CIStr
   402  		indexPartSpecifications []*ast.IndexPartSpecification
   403  		indexOption             *ast.IndexOption
   404  		sqlMode                 allegrosql.ALLEGROSQLMode
   405  		warnings                []string
   406  		hiddenDefCauss          []*perceptron.DeferredCausetInfo
   407  	)
   408  	if isPK {
   409  		// Notice: sqlMode and warnings is used to support non-strict mode.
   410  		err = job.DecodeArgs(&unique, &indexName, &indexPartSpecifications, &indexOption, &sqlMode, &warnings, &global)
   411  	} else {
   412  		err = job.DecodeArgs(&unique, &indexName, &indexPartSpecifications, &indexOption, &hiddenDefCauss, &global)
   413  	}
   414  	if err != nil {
   415  		job.State = perceptron.JobStateCancelled
   416  		return ver, errors.Trace(err)
   417  	}
   418  
   419  	indexInfo := tblInfo.FindIndexByName(indexName.L)
   420  	if indexInfo != nil && indexInfo.State == perceptron.StatePublic {
   421  		job.State = perceptron.JobStateCancelled
   422  		err = ErrDupKeyName.GenWithStack("index already exist %s", indexName)
   423  		if isPK {
   424  			err = schemareplicant.ErrMultiplePriKey
   425  		}
   426  		return ver, err
   427  	}
   428  	for _, hiddenDefCaus := range hiddenDefCauss {
   429  		columnInfo := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, hiddenDefCaus.Name.L)
   430  		if columnInfo != nil && columnInfo.State == perceptron.StatePublic {
   431  			// We already have a column with the same column name.
   432  			job.State = perceptron.JobStateCancelled
   433  			// TODO: refine the error message
   434  			return ver, schemareplicant.ErrDeferredCausetExists.GenWithStackByArgs(hiddenDefCaus.Name)
   435  		}
   436  	}
   437  
   438  	if indexInfo == nil {
   439  		if len(hiddenDefCauss) > 0 {
   440  			pos := &ast.DeferredCausetPosition{Tp: ast.DeferredCausetPositionNone}
   441  			for _, hiddenDefCaus := range hiddenDefCauss {
   442  				_, _, _, err = createDeferredCausetInfo(tblInfo, hiddenDefCaus, pos)
   443  				if err != nil {
   444  					job.State = perceptron.JobStateCancelled
   445  					return ver, errors.Trace(err)
   446  				}
   447  			}
   448  		}
   449  		if err = checkAddDeferredCausetTooManyDeferredCausets(len(tblInfo.DeferredCausets)); err != nil {
   450  			job.State = perceptron.JobStateCancelled
   451  			return ver, errors.Trace(err)
   452  		}
   453  		indexInfo, err = buildIndexInfo(tblInfo, indexName, indexPartSpecifications, perceptron.StateNone)
   454  		if err != nil {
   455  			job.State = perceptron.JobStateCancelled
   456  			return ver, errors.Trace(err)
   457  		}
   458  		if indexOption != nil {
   459  			indexInfo.Comment = indexOption.Comment
   460  			if indexOption.Visibility == ast.IndexVisibilityInvisible {
   461  				indexInfo.Invisible = true
   462  			}
   463  			if indexOption.Tp == perceptron.IndexTypeInvalid {
   464  				// Use btree as default index type.
   465  				indexInfo.Tp = perceptron.IndexTypeBtree
   466  			} else {
   467  				indexInfo.Tp = indexOption.Tp
   468  			}
   469  		} else {
   470  			// Use btree as default index type.
   471  			indexInfo.Tp = perceptron.IndexTypeBtree
   472  		}
   473  		indexInfo.Primary = false
   474  		if isPK {
   475  			if _, err = checkPKOnGeneratedDeferredCauset(tblInfo, indexPartSpecifications); err != nil {
   476  				job.State = perceptron.JobStateCancelled
   477  				return ver, err
   478  			}
   479  			indexInfo.Primary = true
   480  		}
   481  		indexInfo.Unique = unique
   482  		indexInfo.Global = global
   483  		indexInfo.ID = allocateIndexID(tblInfo)
   484  		tblInfo.Indices = append(tblInfo.Indices, indexInfo)
   485  
   486  		// Here we need do this check before set state to `DeleteOnly`,
   487  		// because if hidden columns has been set to `DeleteOnly`,
   488  		// the `DeleteOnly` columns are missing when we do this check.
   489  		if err := checkInvisibleIndexOnPK(tblInfo); err != nil {
   490  			job.State = perceptron.JobStateCancelled
   491  			return ver, err
   492  		}
   493  		logutil.BgLogger().Info("[dbs] run add index job", zap.String("job", job.String()), zap.Reflect("indexInfo", indexInfo))
   494  	}
   495  	originalState := indexInfo.State
   496  	switch indexInfo.State {
   497  	case perceptron.StateNone:
   498  		// none -> delete only
   499  		indexInfo.State = perceptron.StateDeleteOnly
   500  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StateDeleteOnly)
   501  		ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != indexInfo.State)
   502  		if err != nil {
   503  			return ver, err
   504  		}
   505  		job.SchemaState = perceptron.StateDeleteOnly
   506  		metrics.AddIndexProgress.Set(0)
   507  	case perceptron.StateDeleteOnly:
   508  		// delete only -> write only
   509  		indexInfo.State = perceptron.StateWriteOnly
   510  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StateWriteOnly)
   511  		_, err = checkPrimaryKeyNotNull(w, sqlMode, t, job, tblInfo, indexInfo)
   512  		if err != nil {
   513  			break
   514  		}
   515  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   516  		if err != nil {
   517  			return ver, err
   518  		}
   519  		job.SchemaState = perceptron.StateWriteOnly
   520  	case perceptron.StateWriteOnly:
   521  		// write only -> reorganization
   522  		indexInfo.State = perceptron.StateWriteReorganization
   523  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StateWriteReorganization)
   524  		_, err = checkPrimaryKeyNotNull(w, sqlMode, t, job, tblInfo, indexInfo)
   525  		if err != nil {
   526  			break
   527  		}
   528  		// Initialize SnapshotVer to 0 for later reorganization check.
   529  		job.SnapshotVer = 0
   530  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   531  		if err != nil {
   532  			return ver, err
   533  		}
   534  		job.SchemaState = perceptron.StateWriteReorganization
   535  	case perceptron.StateWriteReorganization:
   536  		// reorganization -> public
   537  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StatePublic)
   538  		tbl, err := getBlock(d.causetstore, schemaID, tblInfo)
   539  		if err != nil {
   540  			return ver, errors.Trace(err)
   541  		}
   542  
   543  		reorgInfo, err := getReorgInfo(d, t, job, tbl)
   544  		if err != nil || reorgInfo.first {
   545  			// If we run reorg firstly, we should uFIDelate the job snapshot version
   546  			// and then run the reorg next time.
   547  			return ver, errors.Trace(err)
   548  		}
   549  
   550  		err = w.runReorgJob(t, reorgInfo, tbl.Meta(), d.lease, func() (addIndexErr error) {
   551  			defer soliton.Recover(metrics.LabelDBS, "onCreateIndex",
   552  				func() {
   553  					addIndexErr = errCancelledDBSJob.GenWithStack("add causet `%v` index `%v` panic", tblInfo.Name, indexInfo.Name)
   554  				}, false)
   555  			return w.addBlockIndex(tbl, indexInfo, reorgInfo)
   556  		})
   557  		if err != nil {
   558  			if errWaitReorgTimeout.Equal(err) {
   559  				// if timeout, we should return, check for the tenant and re-wait job done.
   560  				return ver, nil
   561  			}
   562  			if ekv.ErrKeyExists.Equal(err) || errCancelledDBSJob.Equal(err) || errCantDecodeRecord.Equal(err) {
   563  				logutil.BgLogger().Warn("[dbs] run add index job failed, convert job to rollback", zap.String("job", job.String()), zap.Error(err))
   564  				ver, err = convertAddIdxJob2RollbackJob(t, job, tblInfo, indexInfo, err)
   565  			}
   566  			// Clean up the channel of notifyCancelReorgJob. Make sure it can't affect other jobs.
   567  			w.reorgCtx.cleanNotifyReorgCancel()
   568  			return ver, errors.Trace(err)
   569  		}
   570  		// Clean up the channel of notifyCancelReorgJob. Make sure it can't affect other jobs.
   571  		w.reorgCtx.cleanNotifyReorgCancel()
   572  
   573  		indexInfo.State = perceptron.StatePublic
   574  		// Set column index flag.
   575  		addIndexDeferredCausetFlag(tblInfo, indexInfo)
   576  		if isPK {
   577  			if err = uFIDelateDefCaussNull2NotNull(tblInfo, indexInfo); err != nil {
   578  				return ver, errors.Trace(err)
   579  			}
   580  		}
   581  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   582  		if err != nil {
   583  			return ver, errors.Trace(err)
   584  		}
   585  		// Finish this job.
   586  		job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo)
   587  	default:
   588  		err = ErrInvalidDBSState.GenWithStackByArgs("index", tblInfo.State)
   589  	}
   590  
   591  	return ver, errors.Trace(err)
   592  }
   593  
   594  func onDropIndex(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) {
   595  	tblInfo, indexInfo, err := checkDropIndex(t, job)
   596  	if err != nil {
   597  		return ver, errors.Trace(err)
   598  	}
   599  
   600  	dependentHiddenDefCauss := make([]*perceptron.DeferredCausetInfo, 0)
   601  	for _, indexDeferredCauset := range indexInfo.DeferredCausets {
   602  		if tblInfo.DeferredCausets[indexDeferredCauset.Offset].Hidden {
   603  			dependentHiddenDefCauss = append(dependentHiddenDefCauss, tblInfo.DeferredCausets[indexDeferredCauset.Offset])
   604  		}
   605  	}
   606  
   607  	originalState := indexInfo.State
   608  	switch indexInfo.State {
   609  	case perceptron.StatePublic:
   610  		// public -> write only
   611  		job.SchemaState = perceptron.StateWriteOnly
   612  		indexInfo.State = perceptron.StateWriteOnly
   613  		if len(dependentHiddenDefCauss) > 0 {
   614  			firstHiddenOffset := dependentHiddenDefCauss[0].Offset
   615  			for i := 0; i < len(dependentHiddenDefCauss); i++ {
   616  				tblInfo.DeferredCausets[firstHiddenOffset].State = perceptron.StateWriteOnly
   617  				// Set this column's offset to the last and reset all following columns' offsets.
   618  				adjustDeferredCausetInfoInDropDeferredCauset(tblInfo, firstHiddenOffset)
   619  			}
   620  		}
   621  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   622  	case perceptron.StateWriteOnly:
   623  		// write only -> delete only
   624  		job.SchemaState = perceptron.StateDeleteOnly
   625  		indexInfo.State = perceptron.StateDeleteOnly
   626  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StateDeleteOnly)
   627  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   628  	case perceptron.StateDeleteOnly:
   629  		// delete only -> reorganization
   630  		job.SchemaState = perceptron.StateDeleteReorganization
   631  		indexInfo.State = perceptron.StateDeleteReorganization
   632  		uFIDelateHiddenDeferredCausets(tblInfo, indexInfo, perceptron.StateDeleteReorganization)
   633  		ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != indexInfo.State)
   634  	case perceptron.StateDeleteReorganization:
   635  		// reorganization -> absent
   636  		newIndices := make([]*perceptron.IndexInfo, 0, len(tblInfo.Indices))
   637  		for _, idx := range tblInfo.Indices {
   638  			if idx.Name.L != indexInfo.Name.L {
   639  				newIndices = append(newIndices, idx)
   640  			}
   641  		}
   642  		tblInfo.Indices = newIndices
   643  		// Set column index flag.
   644  		dropIndexDeferredCausetFlag(tblInfo, indexInfo)
   645  
   646  		tblInfo.DeferredCausets = tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-len(dependentHiddenDefCauss)]
   647  
   648  		ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != perceptron.StateNone)
   649  		if err != nil {
   650  			return ver, errors.Trace(err)
   651  		}
   652  
   653  		// Finish this job.
   654  		if job.IsRollingback() {
   655  			job.FinishBlockJob(perceptron.JobStateRollbackDone, perceptron.StateNone, ver, tblInfo)
   656  			job.Args[0] = indexInfo.ID
   657  			// the partition ids were append by convertAddIdxJob2RollbackJob, it is weird, but for the compatibility,
   658  			// we should keep appending the partitions in the convertAddIdxJob2RollbackJob.
   659  		} else {
   660  			job.FinishBlockJob(perceptron.JobStateDone, perceptron.StateNone, ver, tblInfo)
   661  			job.Args = append(job.Args, indexInfo.ID, getPartitionIDs(tblInfo))
   662  		}
   663  	default:
   664  		err = ErrInvalidDBSState.GenWithStackByArgs("index", indexInfo.State)
   665  	}
   666  	return ver, errors.Trace(err)
   667  }
   668  
   669  func checkDropIndex(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, *perceptron.IndexInfo, error) {
   670  	schemaID := job.SchemaID
   671  	tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID)
   672  	if err != nil {
   673  		return nil, nil, errors.Trace(err)
   674  	}
   675  
   676  	var indexName perceptron.CIStr
   677  	if err = job.DecodeArgs(&indexName); err != nil {
   678  		job.State = perceptron.JobStateCancelled
   679  		return nil, nil, errors.Trace(err)
   680  	}
   681  
   682  	indexInfo := tblInfo.FindIndexByName(indexName.L)
   683  	if indexInfo == nil {
   684  		job.State = perceptron.JobStateCancelled
   685  		return nil, nil, ErrCantDropFieldOrKey.GenWithStack("index %s doesn't exist", indexName)
   686  	}
   687  
   688  	// Double check for drop index on auto_increment column.
   689  	err = checkDropIndexOnAutoIncrementDeferredCauset(tblInfo, indexInfo)
   690  	if err != nil {
   691  		job.State = perceptron.JobStateCancelled
   692  		return nil, nil, autoid.ErrWrongAutoKey
   693  	}
   694  
   695  	// Check that drop primary index will not cause invisible implicit primary index.
   696  	newIndices := make([]*perceptron.IndexInfo, 0, len(tblInfo.Indices))
   697  	for _, idx := range tblInfo.Indices {
   698  		if idx.Name.L != indexInfo.Name.L {
   699  			newIndices = append(newIndices, idx)
   700  		}
   701  	}
   702  	newTbl := tblInfo.Clone()
   703  	newTbl.Indices = newIndices
   704  	err = checkInvisibleIndexOnPK(newTbl)
   705  	if err != nil {
   706  		job.State = perceptron.JobStateCancelled
   707  		return nil, nil, errors.Trace(err)
   708  	}
   709  
   710  	return tblInfo, indexInfo, nil
   711  }
   712  
   713  func checkDropIndexOnAutoIncrementDeferredCauset(tblInfo *perceptron.BlockInfo, indexInfo *perceptron.IndexInfo) error {
   714  	defcaus := tblInfo.DeferredCausets
   715  	for _, idxDefCaus := range indexInfo.DeferredCausets {
   716  		flag := defcaus[idxDefCaus.Offset].Flag
   717  		if !allegrosql.HasAutoIncrementFlag(flag) {
   718  			continue
   719  		}
   720  		// check the count of index on auto_increment column.
   721  		count := 0
   722  		for _, idx := range tblInfo.Indices {
   723  			for _, c := range idx.DeferredCausets {
   724  				if c.Name.L == idxDefCaus.Name.L {
   725  					count++
   726  					break
   727  				}
   728  			}
   729  		}
   730  		if tblInfo.PKIsHandle && allegrosql.HasPriKeyFlag(flag) {
   731  			count++
   732  		}
   733  		if count < 2 {
   734  			return autoid.ErrWrongAutoKey
   735  		}
   736  	}
   737  	return nil
   738  }
   739  
   740  func checkRenameIndex(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, perceptron.CIStr, perceptron.CIStr, error) {
   741  	var from, to perceptron.CIStr
   742  	schemaID := job.SchemaID
   743  	tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID)
   744  	if err != nil {
   745  		return nil, from, to, errors.Trace(err)
   746  	}
   747  
   748  	if err := job.DecodeArgs(&from, &to); err != nil {
   749  		job.State = perceptron.JobStateCancelled
   750  		return nil, from, to, errors.Trace(err)
   751  	}
   752  
   753  	// Double check. See function `RenameIndex` in dbs_api.go
   754  	duplicate, err := validateRenameIndex(from, to, tblInfo)
   755  	if duplicate {
   756  		return nil, from, to, nil
   757  	}
   758  	if err != nil {
   759  		job.State = perceptron.JobStateCancelled
   760  		return nil, from, to, errors.Trace(err)
   761  	}
   762  	return tblInfo, from, to, errors.Trace(err)
   763  }
   764  
   765  func checkAlterIndexVisibility(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, perceptron.CIStr, bool, error) {
   766  	var (
   767  		indexName perceptron.CIStr
   768  		invisible bool
   769  	)
   770  
   771  	schemaID := job.SchemaID
   772  	tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID)
   773  	if err != nil {
   774  		return nil, indexName, invisible, errors.Trace(err)
   775  	}
   776  
   777  	if err := job.DecodeArgs(&indexName, &invisible); err != nil {
   778  		job.State = perceptron.JobStateCancelled
   779  		return nil, indexName, invisible, errors.Trace(err)
   780  	}
   781  
   782  	skip, err := validateAlterIndexVisibility(indexName, invisible, tblInfo)
   783  	if err != nil {
   784  		job.State = perceptron.JobStateCancelled
   785  		return nil, indexName, invisible, errors.Trace(err)
   786  	}
   787  	if skip {
   788  		return nil, indexName, invisible, nil
   789  	}
   790  	return tblInfo, indexName, invisible, nil
   791  }
   792  
   793  // indexRecord is the record information of an index.
   794  type indexRecord struct {
   795  	handle ekv.Handle
   796  	key    []byte         // It's used to dagger a record. Record it to reduce the encoding time.
   797  	vals   []types.Causet // It's the index values.
   798  	skip   bool           // skip indicates that the index key is already exists, we should not add it.
   799  }
   800  
   801  type addIndexWorker struct {
   802  	*backfillWorker
   803  	index         causet.Index
   804  	metricCounter prometheus.Counter
   805  
   806  	// The following attributes are used to reduce memory allocation.
   807  	defaultVals        []types.Causet
   808  	idxRecords         []*indexRecord
   809  	rowMap             map[int64]types.Causet
   810  	rowCausetDecoder   *causetDecoder.RowCausetDecoder
   811  	idxKeyBufs         [][]byte
   812  	batchCheckKeys     []ekv.Key
   813  	distinctCheckFlags []bool
   814  }
   815  
   816  func newAddIndexWorker(sessCtx stochastikctx.Context, worker *worker, id int, t causet.PhysicalBlock, indexInfo *perceptron.IndexInfo, decodeDefCausMap map[int64]causetDecoder.DeferredCauset) *addIndexWorker {
   817  	index := blocks.NewIndex(t.GetPhysicalID(), t.Meta(), indexInfo)
   818  	rowCausetDecoder := causetDecoder.NewRowCausetDecoder(t, t.WriblockDefCauss(), decodeDefCausMap)
   819  	return &addIndexWorker{
   820  		backfillWorker:   newBackfillWorker(sessCtx, worker, id, t),
   821  		index:            index,
   822  		metricCounter:    metrics.BackfillTotalCounter.WithLabelValues("add_idx_speed"),
   823  		rowCausetDecoder: rowCausetDecoder,
   824  		defaultVals:      make([]types.Causet, len(t.WriblockDefCauss())),
   825  		rowMap:           make(map[int64]types.Causet, len(decodeDefCausMap)),
   826  	}
   827  }
   828  
   829  func (w *addIndexWorker) AddMetricInfo(cnt float64) {
   830  	w.metricCounter.Add(cnt)
   831  }
   832  
   833  // getIndexRecord gets index columns values from raw binary value event.
   834  func (w *addIndexWorker) getIndexRecord(handle ekv.Handle, recordKey []byte, rawRecord []byte) (*indexRecord, error) {
   835  	t := w.causet
   836  	defcaus := t.WriblockDefCauss()
   837  	idxInfo := w.index.Meta()
   838  	sysZone := timeutil.SystemLocation()
   839  	_, err := w.rowCausetDecoder.DecodeAndEvalRowWithMap(w.sessCtx, handle, rawRecord, time.UTC, sysZone, w.rowMap)
   840  	if err != nil {
   841  		return nil, errors.Trace(errCantDecodeRecord.GenWithStackByArgs("index", err))
   842  	}
   843  	idxVal := make([]types.Causet, len(idxInfo.DeferredCausets))
   844  	for j, v := range idxInfo.DeferredCausets {
   845  		col := defcaus[v.Offset]
   846  		idxDeferredCausetVal, ok := w.rowMap[col.ID]
   847  		if ok {
   848  			idxVal[j] = idxDeferredCausetVal
   849  			continue
   850  		}
   851  		idxDeferredCausetVal, err = blocks.GetDefCausDefaultValue(w.sessCtx, col, w.defaultVals)
   852  		if err != nil {
   853  			return nil, errors.Trace(err)
   854  		}
   855  
   856  		if idxDeferredCausetVal.HoTT() == types.HoTTMysqlTime {
   857  			t := idxDeferredCausetVal.GetMysqlTime()
   858  			if t.Type() == allegrosql.TypeTimestamp && sysZone != time.UTC {
   859  				err := t.ConvertTimeZone(sysZone, time.UTC)
   860  				if err != nil {
   861  					return nil, errors.Trace(err)
   862  				}
   863  				idxDeferredCausetVal.SetMysqlTime(t)
   864  			}
   865  		}
   866  		idxVal[j] = idxDeferredCausetVal
   867  	}
   868  	// If there are generated column, rowCausetDecoder will use column value that not in idxInfo.DeferredCausets to calculate
   869  	// the generated value, so we need to clear up the reusing map.
   870  	w.cleanRowMap()
   871  	idxRecord := &indexRecord{handle: handle, key: recordKey, vals: idxVal}
   872  	return idxRecord, nil
   873  }
   874  
   875  func (w *addIndexWorker) cleanRowMap() {
   876  	for id := range w.rowMap {
   877  		delete(w.rowMap, id)
   878  	}
   879  }
   880  
   881  // getNextHandle gets next handle of entry that we are going to process.
   882  func (w *addIndexWorker) getNextHandle(taskRange reorgBackfillTask, taskDone bool) (nextHandle ekv.Handle) {
   883  	if !taskDone {
   884  		// The task is not done. So we need to pick the last processed entry's handle and add one.
   885  		return w.idxRecords[len(w.idxRecords)-1].handle.Next()
   886  	}
   887  
   888  	// The task is done. So we need to choose a handle outside this range.
   889  	// Some corner cases should be considered:
   890  	// - The end of task range is MaxInt64.
   891  	// - The end of the task is excluded in the range.
   892  	if (taskRange.endHandle.IsInt() && taskRange.endHandle.IntValue() == math.MaxInt64) || !taskRange.endIncluded {
   893  		return taskRange.endHandle
   894  	}
   895  
   896  	return taskRange.endHandle.Next()
   897  }
   898  
   899  // fetchRowDefCausVals fetch w.batchCnt count rows that need to backfill indices, and build the corresponding indexRecord slice.
   900  // fetchRowDefCausVals returns:
   901  // 1. The corresponding indexRecord slice.
   902  // 2. Next handle of entry that we need to process.
   903  // 3. Boolean indicates whether the task is done.
   904  // 4. error occurs in fetchRowDefCausVals. nil if no error occurs.
   905  func (w *addIndexWorker) fetchRowDefCausVals(txn ekv.Transaction, taskRange reorgBackfillTask) ([]*indexRecord, ekv.Handle, bool, error) {
   906  	// TODO: use blockScan to prune columns.
   907  	w.idxRecords = w.idxRecords[:0]
   908  	startTime := time.Now()
   909  
   910  	// taskDone means that the added handle is out of taskRange.endHandle.
   911  	taskDone := false
   912  	oprStartTime := startTime
   913  	err := iterateSnapshotRows(w.sessCtx.GetStore(), w.priority, w.causet, txn.StartTS(), taskRange.startHandle, taskRange.endHandle, taskRange.endIncluded,
   914  		func(handle ekv.Handle, recordKey ekv.Key, rawRow []byte) (bool, error) {
   915  			oprEndTime := time.Now()
   916  			logSlowOperations(oprEndTime.Sub(oprStartTime), "iterateSnapshotRows in addIndexWorker fetchRowDefCausVals", 0)
   917  			oprStartTime = oprEndTime
   918  
   919  			if !taskRange.endIncluded {
   920  				taskDone = handle.Compare(taskRange.endHandle) >= 0
   921  			} else {
   922  				taskDone = handle.Compare(taskRange.endHandle) > 0
   923  			}
   924  
   925  			if taskDone || len(w.idxRecords) >= w.batchCnt {
   926  				return false, nil
   927  			}
   928  
   929  			idxRecord, err1 := w.getIndexRecord(handle, recordKey, rawRow)
   930  			if err1 != nil {
   931  				return false, errors.Trace(err1)
   932  			}
   933  
   934  			w.idxRecords = append(w.idxRecords, idxRecord)
   935  			if handle.Equal(taskRange.endHandle) {
   936  				// If taskRange.endIncluded == false, we will not reach here when handle == taskRange.endHandle
   937  				taskDone = true
   938  				return false, nil
   939  			}
   940  			return true, nil
   941  		})
   942  
   943  	if len(w.idxRecords) == 0 {
   944  		taskDone = true
   945  	}
   946  
   947  	logutil.BgLogger().Debug("[dbs] txn fetches handle info", zap.Uint64("txnStartTS", txn.StartTS()), zap.String("taskRange", taskRange.String()), zap.Duration("takeTime", time.Since(startTime)))
   948  	return w.idxRecords, w.getNextHandle(taskRange, taskDone), taskDone, errors.Trace(err)
   949  }
   950  
   951  func (w *addIndexWorker) initBatchCheckBufs(batchCount int) {
   952  	if len(w.idxKeyBufs) < batchCount {
   953  		w.idxKeyBufs = make([][]byte, batchCount)
   954  	}
   955  
   956  	w.batchCheckKeys = w.batchCheckKeys[:0]
   957  	w.distinctCheckFlags = w.distinctCheckFlags[:0]
   958  }
   959  
   960  func (w *addIndexWorker) batchCheckUniqueKey(txn ekv.Transaction, idxRecords []*indexRecord) error {
   961  	idxInfo := w.index.Meta()
   962  	if !idxInfo.Unique {
   963  		// non-unique key need not to check, just overwrite it,
   964  		// because in most case, backfilling indices is not exists.
   965  		return nil
   966  	}
   967  
   968  	w.initBatchCheckBufs(len(idxRecords))
   969  	stmtCtx := w.sessCtx.GetStochastikVars().StmtCtx
   970  	for i, record := range idxRecords {
   971  		idxKey, distinct, err := w.index.GenIndexKey(stmtCtx, record.vals, record.handle, w.idxKeyBufs[i])
   972  		if err != nil {
   973  			return errors.Trace(err)
   974  		}
   975  		// save the buffer to reduce memory allocations.
   976  		w.idxKeyBufs[i] = idxKey
   977  
   978  		w.batchCheckKeys = append(w.batchCheckKeys, idxKey)
   979  		w.distinctCheckFlags = append(w.distinctCheckFlags, distinct)
   980  	}
   981  
   982  	batchVals, err := txn.BatchGet(context.Background(), w.batchCheckKeys)
   983  	if err != nil {
   984  		return errors.Trace(err)
   985  	}
   986  
   987  	// 1. unique-key/primary-key is duplicate and the handle is equal, skip it.
   988  	// 2. unique-key/primary-key is duplicate and the handle is not equal, return duplicate error.
   989  	// 3. non-unique-key is duplicate, skip it.
   990  	for i, key := range w.batchCheckKeys {
   991  		if val, found := batchVals[string(key)]; found {
   992  			if w.distinctCheckFlags[i] {
   993  				handle, err1 := blockcodec.DecodeHandleInUniqueIndexValue(val, w.causet.Meta().IsCommonHandle)
   994  				if err1 != nil {
   995  					return errors.Trace(err1)
   996  				}
   997  
   998  				if handle != idxRecords[i].handle {
   999  					return errors.Trace(ekv.ErrKeyExists)
  1000  				}
  1001  			}
  1002  			idxRecords[i].skip = true
  1003  		} else {
  1004  			// The keys in w.batchCheckKeys also maybe duplicate,
  1005  			// so we need to backfill the not found key into `batchVals` map.
  1006  			if w.distinctCheckFlags[i] {
  1007  				batchVals[string(key)] = blockcodec.EncodeHandleInUniqueIndexValue(idxRecords[i].handle, false)
  1008  			}
  1009  		}
  1010  	}
  1011  	// Constrains is already checked.
  1012  	stmtCtx.BatchCheck = true
  1013  	return nil
  1014  }
  1015  
  1016  // BackfillDataInTxn will backfill causet index in a transaction, dagger corresponding rowKey, if the value of rowKey is changed,
  1017  // indicate that index columns values may changed, index is not allowed to be added, so the txn will rollback and retry.
  1018  // BackfillDataInTxn will add w.batchCnt indices once, default value of w.batchCnt is 128.
  1019  // TODO: make w.batchCnt can be modified by system variable.
  1020  func (w *addIndexWorker) BackfillDataInTxn(handleRange reorgBackfillTask) (taskCtx backfillTaskContext, errInTxn error) {
  1021  	failpoint.Inject("errorMockPanic", func(val failpoint.Value) {
  1022  		if val.(bool) {
  1023  			panic("panic test")
  1024  		}
  1025  	})
  1026  
  1027  	oprStartTime := time.Now()
  1028  	errInTxn = ekv.RunInNewTxn(w.sessCtx.GetStore(), true, func(txn ekv.Transaction) error {
  1029  		taskCtx.addedCount = 0
  1030  		taskCtx.scanCount = 0
  1031  		txn.SetOption(ekv.Priority, w.priority)
  1032  
  1033  		idxRecords, nextHandle, taskDone, err := w.fetchRowDefCausVals(txn, handleRange)
  1034  		if err != nil {
  1035  			return errors.Trace(err)
  1036  		}
  1037  		taskCtx.nextHandle = nextHandle
  1038  		taskCtx.done = taskDone
  1039  
  1040  		err = w.batchCheckUniqueKey(txn, idxRecords)
  1041  		if err != nil {
  1042  			return errors.Trace(err)
  1043  		}
  1044  
  1045  		for _, idxRecord := range idxRecords {
  1046  			taskCtx.scanCount++
  1047  			// The index is already exists, we skip it, no needs to backfill it.
  1048  			// The following uFIDelate, delete, insert on these rows, MilevaDB can handle it correctly.
  1049  			if idxRecord.skip {
  1050  				continue
  1051  			}
  1052  
  1053  			// Lock the event key to notify us that someone delete or uFIDelate the event,
  1054  			// then we should not backfill the index of it, otherwise the adding index is redundant.
  1055  			err := txn.LockKeys(context.Background(), new(ekv.LockCtx), idxRecord.key)
  1056  			if err != nil {
  1057  				return errors.Trace(err)
  1058  			}
  1059  
  1060  			// Create the index.
  1061  			handle, err := w.index.Create(w.sessCtx, txn.GetUnionStore(), idxRecord.vals, idxRecord.handle)
  1062  			if err != nil {
  1063  				if ekv.ErrKeyExists.Equal(err) && idxRecord.handle.Equal(handle) {
  1064  					// Index already exists, skip it.
  1065  					continue
  1066  				}
  1067  
  1068  				return errors.Trace(err)
  1069  			}
  1070  			taskCtx.addedCount++
  1071  		}
  1072  
  1073  		return nil
  1074  	})
  1075  	logSlowOperations(time.Since(oprStartTime), "AddIndexBackfillDataInTxn", 3000)
  1076  
  1077  	return
  1078  }
  1079  
  1080  func (w *worker) addPhysicalBlockIndex(t causet.PhysicalBlock, indexInfo *perceptron.IndexInfo, reorgInfo *reorgInfo) error {
  1081  	logutil.BgLogger().Info("[dbs] start to add causet index", zap.String("job", reorgInfo.Job.String()), zap.String("reorgInfo", reorgInfo.String()))
  1082  	return w.writePhysicalBlockRecord(t.(causet.PhysicalBlock), typeAddIndexWorker, indexInfo, nil, nil, reorgInfo)
  1083  }
  1084  
  1085  // addBlockIndex handles the add index reorganization state for a causet.
  1086  func (w *worker) addBlockIndex(t causet.Block, idx *perceptron.IndexInfo, reorgInfo *reorgInfo) error {
  1087  	var err error
  1088  	if tbl, ok := t.(causet.PartitionedBlock); ok {
  1089  		var finish bool
  1090  		for !finish {
  1091  			p := tbl.GetPartition(reorgInfo.PhysicalBlockID)
  1092  			if p == nil {
  1093  				return errCancelledDBSJob.GenWithStack("Can not find partition id %d for causet %d", reorgInfo.PhysicalBlockID, t.Meta().ID)
  1094  			}
  1095  			err = w.addPhysicalBlockIndex(p, idx, reorgInfo)
  1096  			if err != nil {
  1097  				break
  1098  			}
  1099  			finish, err = w.uFIDelateReorgInfo(tbl, reorgInfo)
  1100  			if err != nil {
  1101  				return errors.Trace(err)
  1102  			}
  1103  		}
  1104  	} else {
  1105  		err = w.addPhysicalBlockIndex(t.(causet.PhysicalBlock), idx, reorgInfo)
  1106  	}
  1107  	return errors.Trace(err)
  1108  }
  1109  
  1110  // uFIDelateReorgInfo will find the next partition according to current reorgInfo.
  1111  // If no more partitions, or causet t is not a partitioned causet, returns true to
  1112  // indicate that the reorganize work is finished.
  1113  func (w *worker) uFIDelateReorgInfo(t causet.PartitionedBlock, reorg *reorgInfo) (bool, error) {
  1114  	pi := t.Meta().GetPartitionInfo()
  1115  	if pi == nil {
  1116  		return true, nil
  1117  	}
  1118  
  1119  	pid, err := findNextPartitionID(reorg.PhysicalBlockID, pi.Definitions)
  1120  	if err != nil {
  1121  		// Fatal error, should not run here.
  1122  		logutil.BgLogger().Error("[dbs] find next partition ID failed", zap.Reflect("causet", t), zap.Error(err))
  1123  		return false, errors.Trace(err)
  1124  	}
  1125  	if pid == 0 {
  1126  		// Next partition does not exist, all the job done.
  1127  		return true, nil
  1128  	}
  1129  
  1130  	failpoint.Inject("mockUFIDelateCachedSafePoint", func(val failpoint.Value) {
  1131  		if val.(bool) {
  1132  			// 18 is for the logical time.
  1133  			ts := oracle.GetPhysical(time.Now()) << 18
  1134  			s := reorg.d.causetstore.(einsteindb.CausetStorage)
  1135  			s.UFIDelateSPCache(uint64(ts), time.Now())
  1136  			time.Sleep(time.Millisecond * 3)
  1137  		}
  1138  	})
  1139  	currentVer, err := getValidCurrentVersion(reorg.d.causetstore)
  1140  	if err != nil {
  1141  		return false, errors.Trace(err)
  1142  	}
  1143  	start, end, err := getBlockRange(reorg.d, t.GetPartition(pid), currentVer.Ver, reorg.Job.Priority)
  1144  	if err != nil {
  1145  		return false, errors.Trace(err)
  1146  	}
  1147  	reorg.StartHandle, reorg.EndHandle, reorg.PhysicalBlockID = start, end, pid
  1148  
  1149  	// Write the reorg info to causetstore so the whole reorganize process can recover from panic.
  1150  	err = ekv.RunInNewTxn(reorg.d.causetstore, true, func(txn ekv.Transaction) error {
  1151  		return errors.Trace(reorg.UFIDelateReorgMeta(txn, reorg.StartHandle, reorg.EndHandle, reorg.PhysicalBlockID))
  1152  	})
  1153  	logutil.BgLogger().Info("[dbs] job uFIDelate reorgInfo", zap.Int64("jobID", reorg.Job.ID),
  1154  		zap.Int64("partitionBlockID", pid), zap.String("startHandle", toString(start)),
  1155  		zap.String("endHandle", toString(end)), zap.Error(err))
  1156  	return false, errors.Trace(err)
  1157  }
  1158  
  1159  // findNextPartitionID finds the next partition ID in the PartitionDefinition array.
  1160  // Returns 0 if current partition is already the last one.
  1161  func findNextPartitionID(currentPartition int64, defs []perceptron.PartitionDefinition) (int64, error) {
  1162  	for i, def := range defs {
  1163  		if currentPartition == def.ID {
  1164  			if i == len(defs)-1 {
  1165  				return 0, nil
  1166  			}
  1167  			return defs[i+1].ID, nil
  1168  		}
  1169  	}
  1170  	return 0, errors.Errorf("partition id not found %d", currentPartition)
  1171  }
  1172  
  1173  func allocateIndexID(tblInfo *perceptron.BlockInfo) int64 {
  1174  	tblInfo.MaxIndexID++
  1175  	return tblInfo.MaxIndexID
  1176  }
  1177  
  1178  func getIndexInfoByNameAndDeferredCauset(oldBlockInfo *perceptron.BlockInfo, newOne *perceptron.IndexInfo) *perceptron.IndexInfo {
  1179  	for _, oldOne := range oldBlockInfo.Indices {
  1180  		if newOne.Name.L == oldOne.Name.L && indexDeferredCausetSliceEqual(newOne.DeferredCausets, oldOne.DeferredCausets) {
  1181  			return oldOne
  1182  		}
  1183  	}
  1184  	return nil
  1185  }
  1186  
  1187  func indexDeferredCausetSliceEqual(a, b []*perceptron.IndexDeferredCauset) bool {
  1188  	if len(a) != len(b) {
  1189  		return false
  1190  	}
  1191  	if len(a) == 0 {
  1192  		logutil.BgLogger().Warn("[dbs] admin repair causet : index's columns length equal to 0")
  1193  		return true
  1194  	}
  1195  	// Accelerate the compare by eliminate index bound check.
  1196  	b = b[:len(a)]
  1197  	for i, v := range a {
  1198  		if v.Name.L != b[i].Name.L {
  1199  			return false
  1200  		}
  1201  	}
  1202  	return true
  1203  }
  1204  
  1205  func findIndexesByDefCausName(indexes []*perceptron.IndexInfo, colName string) ([]*perceptron.IndexInfo, []int) {
  1206  	idxInfos := make([]*perceptron.IndexInfo, 0, len(indexes))
  1207  	offsets := make([]int, 0, len(indexes))
  1208  	for _, idxInfo := range indexes {
  1209  		for i, c := range idxInfo.DeferredCausets {
  1210  			if strings.EqualFold(colName, c.Name.L) {
  1211  				idxInfos = append(idxInfos, idxInfo)
  1212  				offsets = append(offsets, i)
  1213  				break
  1214  			}
  1215  		}
  1216  	}
  1217  	return idxInfos, offsets
  1218  }