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 }