github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/defcaus.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package dbs 15 16 import ( 17 "fmt" 18 "math" 19 "math/bits" 20 "strings" 21 "sync/atomic" 22 "time" 23 24 "github.com/cznic/mathutil" 25 "github.com/prometheus/client_golang/prometheus" 26 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 27 "github.com/whtcorpsinc/BerolinaSQL/ast" 28 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 29 "github.com/whtcorpsinc/errors" 30 "github.com/whtcorpsinc/failpoint" 31 "github.com/whtcorpsinc/milevadb/blockcodec" 32 "github.com/whtcorpsinc/milevadb/causet" 33 dbsutil "github.com/whtcorpsinc/milevadb/dbs/soliton" 34 "github.com/whtcorpsinc/milevadb/ekv" 35 "github.com/whtcorpsinc/milevadb/metrics" 36 "github.com/whtcorpsinc/milevadb/schemareplicant" 37 "github.com/whtcorpsinc/milevadb/soliton" 38 "github.com/whtcorpsinc/milevadb/soliton/logutil" 39 causetDecoder "github.com/whtcorpsinc/milevadb/soliton/rowCausetDecoder" 40 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 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 50 func adjustDeferredCausetInfoInAddDeferredCauset(tblInfo *perceptron.BlockInfo, offset int) { 51 oldDefCauss := tblInfo.DeferredCausets 52 newDefCauss := make([]*perceptron.DeferredCausetInfo, 0, len(oldDefCauss)) 53 newDefCauss = append(newDefCauss, oldDefCauss[:offset]...) 54 newDefCauss = append(newDefCauss, oldDefCauss[len(oldDefCauss)-1]) 55 newDefCauss = append(newDefCauss, oldDefCauss[offset:len(oldDefCauss)-1]...) 56 // Adjust defCausumn offset. 57 offsetChanged := make(map[int]int, len(newDefCauss)-offset-1) 58 for i := offset + 1; i < len(newDefCauss); i++ { 59 offsetChanged[newDefCauss[i].Offset] = i 60 newDefCauss[i].Offset = i 61 } 62 newDefCauss[offset].Offset = offset 63 // UFIDelate index defCausumn offset info. 64 // TODO: There may be some corner cases for index defCausumn offsets, we may check this later. 65 for _, idx := range tblInfo.Indices { 66 for _, defCaus := range idx.DeferredCausets { 67 newOffset, ok := offsetChanged[defCaus.Offset] 68 if ok { 69 defCaus.Offset = newOffset 70 } 71 } 72 } 73 tblInfo.DeferredCausets = newDefCauss 74 } 75 76 77 func adjustDeferredCausetInfoInDropDeferredCauset(tblInfo *perceptron.BlockInfo, offset int) { 78 oldDefCauss := tblInfo.DeferredCausets 79 // Adjust defCausumn offset. 80 offsetChanged := make(map[int]int, len(oldDefCauss)-offset-1) 81 for i := offset + 1; i < len(oldDefCauss); i++ { 82 offsetChanged[oldDefCauss[i].Offset] = i - 1 83 oldDefCauss[i].Offset = i - 1 84 } 85 oldDefCauss[offset].Offset = len(oldDefCauss) - 1 86 // For memex index, we drop hidden defCausumns and index simultaneously. 87 // So we need to change the offset of memex index. 88 offsetChanged[offset] = len(oldDefCauss) - 1 89 // UFIDelate index defCausumn offset info. 90 // TODO: There may be some corner cases for index defCausumn offsets, we may check this later. 91 for _, idx := range tblInfo.Indices { 92 for _, defCaus := range idx.DeferredCausets { 93 newOffset, ok := offsetChanged[defCaus.Offset] 94 if ok { 95 defCaus.Offset = newOffset 96 } 97 } 98 } 99 newDefCauss := make([]*perceptron.DeferredCausetInfo, 0, len(oldDefCauss)) 100 newDefCauss = append(newDefCauss, oldDefCauss[:offset]...) 101 newDefCauss = append(newDefCauss, oldDefCauss[offset+1:]...) 102 newDefCauss = append(newDefCauss, oldDefCauss[offset]) 103 tblInfo.DeferredCausets = newDefCauss 104 } 105 106 func createDeferredCausetInfo(tblInfo *perceptron.BlockInfo, defCausInfo *perceptron.DeferredCausetInfo, pos *ast.DeferredCausetPosition) (*perceptron.DeferredCausetInfo, *ast.DeferredCausetPosition, int, error) { 107 // Check defCausumn name duplicate. 108 defcaus := tblInfo.DeferredCausets 109 offset := len(defcaus) 110 // Should initialize pos when it is nil. 111 if pos == nil { 112 pos = &ast.DeferredCausetPosition{} 113 } 114 // Get defCausumn offset. 115 if pos.Tp == ast.DeferredCausetPositionFirst { 116 offset = 0 117 } else if pos.Tp == ast.DeferredCausetPositionAfter { 118 c := perceptron.FindDeferredCausetInfo(defcaus, pos.RelativeDeferredCauset.Name.L) 119 if c == nil { 120 return nil, pos, 0, schemareplicant.ErrDeferredCausetNotExists.GenWithStackByArgs(pos.RelativeDeferredCauset, tblInfo.Name) 121 } 122 123 // Insert offset is after the mentioned defCausumn. 124 offset = c.Offset + 1 125 } 126 defCausInfo.ID = allocateDeferredCausetID(tblInfo) 127 defCausInfo.State = perceptron.StateNone 128 // To support add defCausumn asynchronous, we should mark its offset as the last defCausumn. 129 // So that we can use origin defCausumn offset to get value from event. 130 defCausInfo.Offset = len(defcaus) 131 132 // Append the defCausumn info to the end of the tblInfo.DeferredCausets. 133 // It will reorder to the right offset in "DeferredCausets" when it state change to public. 134 tblInfo.DeferredCausets = append(defcaus, defCausInfo) 135 return defCausInfo, pos, offset, nil 136 } 137 138 func checkAddDeferredCauset(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, *perceptron.DeferredCausetInfo, *perceptron.DeferredCausetInfo, *ast.DeferredCausetPosition, int, error) { 139 schemaID := job.SchemaID 140 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 141 if err != nil { 142 return nil, nil, nil, nil, 0, errors.Trace(err) 143 } 144 defCaus := &perceptron.DeferredCausetInfo{} 145 pos := &ast.DeferredCausetPosition{} 146 offset := 0 147 err = job.DecodeArgs(defCaus, pos, &offset) 148 if err != nil { 149 job.State = perceptron.JobStateCancelled 150 return nil, nil, nil, nil, 0, errors.Trace(err) 151 } 152 153 defCausumnInfo := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, defCaus.Name.L) 154 if defCausumnInfo != nil { 155 if defCausumnInfo.State == perceptron.StatePublic { 156 // We already have a defCausumn with the same defCausumn name. 157 job.State = perceptron.JobStateCancelled 158 return nil, nil, nil, nil, 0, schemareplicant.ErrDeferredCausetExists.GenWithStackByArgs(defCaus.Name) 159 } 160 } 161 return tblInfo, defCausumnInfo, defCaus, pos, offset, nil 162 } 163 164 func onAddDeferredCauset(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, err error) { 165 // Handle the rolling back job. 166 if job.IsRollingback() { 167 ver, err = onDropDeferredCauset(t, job) 168 if err != nil { 169 return ver, errors.Trace(err) 170 } 171 return ver, nil 172 } 173 174 failpoint.Inject("errorBeforeDecodeArgs", func(val failpoint.Value) { 175 if val.(bool) { 176 failpoint.Return(ver, errors.New("occur an error before decode args")) 177 } 178 }) 179 180 tblInfo, defCausumnInfo, defCaus, pos, offset, err := checkAddDeferredCauset(t, job) 181 if err != nil { 182 return ver, errors.Trace(err) 183 } 184 if defCausumnInfo == nil { 185 defCausumnInfo, _, offset, err = createDeferredCausetInfo(tblInfo, defCaus, pos) 186 if err != nil { 187 job.State = perceptron.JobStateCancelled 188 return ver, errors.Trace(err) 189 } 190 logutil.BgLogger().Info("[dbs] run add defCausumn job", zap.String("job", job.String()), zap.Reflect("defCausumnInfo", *defCausumnInfo), zap.Int("offset", offset)) 191 // Set offset arg to job. 192 if offset != 0 { 193 job.Args = []interface{}{defCausumnInfo, pos, offset} 194 } 195 if err = checkAddDeferredCausetTooManyDeferredCausets(len(tblInfo.DeferredCausets)); err != nil { 196 job.State = perceptron.JobStateCancelled 197 return ver, errors.Trace(err) 198 } 199 } 200 201 originalState := defCausumnInfo.State 202 switch defCausumnInfo.State { 203 case perceptron.StateNone: 204 // none -> delete only 205 job.SchemaState = perceptron.StateDeleteOnly 206 defCausumnInfo.State = perceptron.StateDeleteOnly 207 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != defCausumnInfo.State) 208 case perceptron.StateDeleteOnly: 209 // delete only -> write only 210 job.SchemaState = perceptron.StateWriteOnly 211 defCausumnInfo.State = perceptron.StateWriteOnly 212 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfo.State) 213 case perceptron.StateWriteOnly: 214 // write only -> reorganization 215 job.SchemaState = perceptron.StateWriteReorganization 216 defCausumnInfo.State = perceptron.StateWriteReorganization 217 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfo.State) 218 case perceptron.StateWriteReorganization: 219 // reorganization -> public 220 // Adjust causet defCausumn offset. 221 adjustDeferredCausetInfoInAddDeferredCauset(tblInfo, offset) 222 defCausumnInfo.State = perceptron.StatePublic 223 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfo.State) 224 if err != nil { 225 return ver, errors.Trace(err) 226 } 227 228 // Finish this job. 229 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 230 asyncNotifyEvent(d, &dbsutil.Event{Tp: perceptron.CausetActionAddDeferredCauset, BlockInfo: tblInfo, DeferredCausetInfos: []*perceptron.DeferredCausetInfo{defCausumnInfo}}) 231 default: 232 err = ErrInvalidDBSState.GenWithStackByArgs("defCausumn", defCausumnInfo.State) 233 } 234 235 return ver, errors.Trace(err) 236 } 237 238 func checkAddDeferredCausets(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, []*perceptron.DeferredCausetInfo, []*perceptron.DeferredCausetInfo, []*ast.DeferredCausetPosition, []int, []bool, error) { 239 schemaID := job.SchemaID 240 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 241 if err != nil { 242 return nil, nil, nil, nil, nil, nil, errors.Trace(err) 243 } 244 defCausumns := []*perceptron.DeferredCausetInfo{} 245 positions := []*ast.DeferredCausetPosition{} 246 offsets := []int{} 247 ifNotExists := []bool{} 248 err = job.DecodeArgs(&defCausumns, &positions, &offsets, &ifNotExists) 249 if err != nil { 250 job.State = perceptron.JobStateCancelled 251 return nil, nil, nil, nil, nil, nil, errors.Trace(err) 252 } 253 254 defCausumnInfos := make([]*perceptron.DeferredCausetInfo, 0, len(defCausumns)) 255 newDeferredCausets := make([]*perceptron.DeferredCausetInfo, 0, len(defCausumns)) 256 newPositions := make([]*ast.DeferredCausetPosition, 0, len(defCausumns)) 257 newOffsets := make([]int, 0, len(defCausumns)) 258 newIfNotExists := make([]bool, 0, len(defCausumns)) 259 for i, defCaus := range defCausumns { 260 defCausumnInfo := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, defCaus.Name.L) 261 if defCausumnInfo != nil { 262 if defCausumnInfo.State == perceptron.StatePublic { 263 // We already have a defCausumn with the same defCausumn name. 264 if ifNotExists[i] { 265 // TODO: Should return a warning. 266 logutil.BgLogger().Warn("[dbs] check add defCausumns, duplicate defCausumn", zap.Stringer("defCaus", defCaus.Name)) 267 continue 268 } 269 job.State = perceptron.JobStateCancelled 270 return nil, nil, nil, nil, nil, nil, schemareplicant.ErrDeferredCausetExists.GenWithStackByArgs(defCaus.Name) 271 } 272 defCausumnInfos = append(defCausumnInfos, defCausumnInfo) 273 } 274 newDeferredCausets = append(newDeferredCausets, defCausumns[i]) 275 newPositions = append(newPositions, positions[i]) 276 newOffsets = append(newOffsets, offsets[i]) 277 newIfNotExists = append(newIfNotExists, ifNotExists[i]) 278 } 279 return tblInfo, defCausumnInfos, newDeferredCausets, newPositions, newOffsets, newIfNotExists, nil 280 } 281 282 func setDeferredCausetsState(defCausumnInfos []*perceptron.DeferredCausetInfo, state perceptron.SchemaState) { 283 for i := range defCausumnInfos { 284 defCausumnInfos[i].State = state 285 } 286 } 287 288 func setIndicesState(indexInfos []*perceptron.IndexInfo, state perceptron.SchemaState) { 289 for _, indexInfo := range indexInfos { 290 indexInfo.State = state 291 } 292 } 293 294 func onAddDeferredCausets(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, err error) { 295 // Handle the rolling back job. 296 if job.IsRollingback() { 297 ver, err = onDropDeferredCausets(t, job) 298 if err != nil { 299 return ver, errors.Trace(err) 300 } 301 return ver, nil 302 } 303 304 failpoint.Inject("errorBeforeDecodeArgs", func(val failpoint.Value) { 305 if val.(bool) { 306 failpoint.Return(ver, errors.New("occur an error before decode args")) 307 } 308 }) 309 310 tblInfo, defCausumnInfos, defCausumns, positions, offsets, ifNotExists, err := checkAddDeferredCausets(t, job) 311 if err != nil { 312 return ver, errors.Trace(err) 313 } 314 if len(defCausumnInfos) == 0 { 315 if len(defCausumns) == 0 { 316 job.State = perceptron.JobStateCancelled 317 return ver, nil 318 } 319 for i := range defCausumns { 320 defCausumnInfo, pos, offset, err := createDeferredCausetInfo(tblInfo, defCausumns[i], positions[i]) 321 if err != nil { 322 job.State = perceptron.JobStateCancelled 323 return ver, errors.Trace(err) 324 } 325 logutil.BgLogger().Info("[dbs] run add defCausumns job", zap.String("job", job.String()), zap.Reflect("defCausumnInfo", *defCausumnInfo), zap.Int("offset", offset)) 326 positions[i] = pos 327 offsets[i] = offset 328 if err = checkAddDeferredCausetTooManyDeferredCausets(len(tblInfo.DeferredCausets)); err != nil { 329 job.State = perceptron.JobStateCancelled 330 return ver, errors.Trace(err) 331 } 332 defCausumnInfos = append(defCausumnInfos, defCausumnInfo) 333 } 334 // Set arg to job. 335 job.Args = []interface{}{defCausumnInfos, positions, offsets, ifNotExists} 336 } 337 338 originalState := defCausumnInfos[0].State 339 switch defCausumnInfos[0].State { 340 case perceptron.StateNone: 341 // none -> delete only 342 job.SchemaState = perceptron.StateDeleteOnly 343 setDeferredCausetsState(defCausumnInfos, perceptron.StateDeleteOnly) 344 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != defCausumnInfos[0].State) 345 case perceptron.StateDeleteOnly: 346 // delete only -> write only 347 job.SchemaState = perceptron.StateWriteOnly 348 setDeferredCausetsState(defCausumnInfos, perceptron.StateWriteOnly) 349 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfos[0].State) 350 case perceptron.StateWriteOnly: 351 // write only -> reorganization 352 job.SchemaState = perceptron.StateWriteReorganization 353 setDeferredCausetsState(defCausumnInfos, perceptron.StateWriteReorganization) 354 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfos[0].State) 355 case perceptron.StateWriteReorganization: 356 // reorganization -> public 357 // Adjust causet defCausumn offsets. 358 oldDefCauss := tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-len(offsets)] 359 newDefCauss := tblInfo.DeferredCausets[len(tblInfo.DeferredCausets)-len(offsets):] 360 tblInfo.DeferredCausets = oldDefCauss 361 for i := range offsets { 362 // For multiple defCausumns with after position, should adjust offsets. 363 // e.g. create causet t(a int); 364 // alter causet t add defCausumn b int after a, add defCausumn c int after a; 365 // alter causet t add defCausumn a1 int after a, add defCausumn b1 int after b, add defCausumn c1 int after c; 366 // alter causet t add defCausumn a1 int after a, add defCausumn b1 int first; 367 if positions[i].Tp == ast.DeferredCausetPositionAfter { 368 for j := 0; j < i; j++ { 369 if (positions[j].Tp == ast.DeferredCausetPositionAfter && offsets[j] < offsets[i]) || positions[j].Tp == ast.DeferredCausetPositionFirst { 370 offsets[i]++ 371 } 372 } 373 } 374 tblInfo.DeferredCausets = append(tblInfo.DeferredCausets, newDefCauss[i]) 375 adjustDeferredCausetInfoInAddDeferredCauset(tblInfo, offsets[i]) 376 } 377 setDeferredCausetsState(defCausumnInfos, perceptron.StatePublic) 378 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausumnInfos[0].State) 379 if err != nil { 380 return ver, errors.Trace(err) 381 } 382 // Finish this job. 383 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 384 asyncNotifyEvent(d, &dbsutil.Event{Tp: perceptron.CausetActionAddDeferredCausets, BlockInfo: tblInfo, DeferredCausetInfos: defCausumnInfos}) 385 default: 386 err = ErrInvalidDBSState.GenWithStackByArgs("defCausumn", defCausumnInfos[0].State) 387 } 388 389 return ver, errors.Trace(err) 390 } 391 392 func onDropDeferredCausets(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 393 tblInfo, defCausInfos, delCount, idxInfos, err := checkDropDeferredCausets(t, job) 394 if err != nil { 395 return ver, errors.Trace(err) 396 } 397 if len(defCausInfos) == 0 { 398 job.State = perceptron.JobStateCancelled 399 return ver, nil 400 } 401 402 originalState := defCausInfos[0].State 403 switch defCausInfos[0].State { 404 case perceptron.StatePublic: 405 // public -> write only 406 job.SchemaState = perceptron.StateWriteOnly 407 setDeferredCausetsState(defCausInfos, perceptron.StateWriteOnly) 408 setIndicesState(idxInfos, perceptron.StateWriteOnly) 409 for _, defCausInfo := range defCausInfos { 410 err = checkDropDeferredCausetForStatePublic(tblInfo, defCausInfo) 411 if err != nil { 412 return ver, errors.Trace(err) 413 } 414 } 415 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != defCausInfos[0].State) 416 case perceptron.StateWriteOnly: 417 // write only -> delete only 418 job.SchemaState = perceptron.StateDeleteOnly 419 setDeferredCausetsState(defCausInfos, perceptron.StateDeleteOnly) 420 setIndicesState(idxInfos, perceptron.StateDeleteOnly) 421 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfos[0].State) 422 case perceptron.StateDeleteOnly: 423 // delete only -> reorganization 424 job.SchemaState = perceptron.StateDeleteReorganization 425 setDeferredCausetsState(defCausInfos, perceptron.StateDeleteReorganization) 426 setIndicesState(idxInfos, perceptron.StateDeleteReorganization) 427 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfos[0].State) 428 case perceptron.StateDeleteReorganization: 429 // reorganization -> absent 430 // All reorganization jobs are done, drop this defCausumn. 431 if len(idxInfos) > 0 { 432 newIndices := make([]*perceptron.IndexInfo, 0, len(tblInfo.Indices)) 433 for _, idx := range tblInfo.Indices { 434 if !indexInfoContains(idx.ID, idxInfos) { 435 newIndices = append(newIndices, idx) 436 } 437 } 438 tblInfo.Indices = newIndices 439 } 440 441 indexIDs := indexInfosToIDList(idxInfos) 442 tblInfo.DeferredCausets = tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-delCount] 443 setDeferredCausetsState(defCausInfos, perceptron.StateNone) 444 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfos[0].State) 445 if err != nil { 446 return ver, errors.Trace(err) 447 } 448 449 // Finish this job. 450 if job.IsRollingback() { 451 job.FinishBlockJob(perceptron.JobStateRollbackDone, perceptron.StateNone, ver, tblInfo) 452 } else { 453 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StateNone, ver, tblInfo) 454 job.Args = append(job.Args, indexIDs, getPartitionIDs(tblInfo)) 455 } 456 default: 457 err = errInvalidDBSJob.GenWithStackByArgs("causet", tblInfo.State) 458 } 459 return ver, errors.Trace(err) 460 } 461 462 func checkDropDeferredCausets(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, []*perceptron.DeferredCausetInfo, int, []*perceptron.IndexInfo, error) { 463 schemaID := job.SchemaID 464 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 465 if err != nil { 466 return nil, nil, 0, nil, errors.Trace(err) 467 } 468 469 var defCausNames []perceptron.CIStr 470 var ifExists []bool 471 err = job.DecodeArgs(&defCausNames, &ifExists) 472 if err != nil { 473 job.State = perceptron.JobStateCancelled 474 return nil, nil, 0, nil, errors.Trace(err) 475 } 476 477 newDefCausNames := make([]perceptron.CIStr, 0, len(defCausNames)) 478 defCausInfos := make([]*perceptron.DeferredCausetInfo, 0, len(defCausNames)) 479 newIfExists := make([]bool, 0, len(defCausNames)) 480 indexInfos := make([]*perceptron.IndexInfo, 0) 481 for i, defCausName := range defCausNames { 482 defCausInfo := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, defCausName.L) 483 if defCausInfo == nil || defCausInfo.Hidden { 484 if ifExists[i] { 485 // TODO: Should return a warning. 486 logutil.BgLogger().Warn(fmt.Sprintf("defCausumn %s doesn't exist", defCausName)) 487 continue 488 } 489 job.State = perceptron.JobStateCancelled 490 return nil, nil, 0, nil, ErrCantDropFieldOrKey.GenWithStack("defCausumn %s doesn't exist", defCausName) 491 } 492 if err = isDroppableDeferredCauset(tblInfo, defCausName); err != nil { 493 job.State = perceptron.JobStateCancelled 494 return nil, nil, 0, nil, errors.Trace(err) 495 } 496 newDefCausNames = append(newDefCausNames, defCausName) 497 newIfExists = append(newIfExists, ifExists[i]) 498 defCausInfos = append(defCausInfos, defCausInfo) 499 idxInfos := listIndicesWithDeferredCauset(defCausName.L, tblInfo.Indices) 500 indexInfos = append(indexInfos, idxInfos...) 501 } 502 job.Args = []interface{}{newDefCausNames, newIfExists} 503 return tblInfo, defCausInfos, len(defCausInfos), indexInfos, nil 504 } 505 506 func checkDropDeferredCausetForStatePublic(tblInfo *perceptron.BlockInfo, defCausInfo *perceptron.DeferredCausetInfo) (err error) { 507 // Set this defCausumn's offset to the last and reset all following defCausumns' offsets. 508 adjustDeferredCausetInfoInDropDeferredCauset(tblInfo, defCausInfo.Offset) 509 // When the dropping defCausumn has not-null flag and it hasn't the default value, we can backfill the defCausumn value like "add defCausumn". 510 // NOTE: If the state of StateWriteOnly can be rollbacked, we'd better reconsider the original default value. 511 // And we need consider the defCausumn without not-null flag. 512 if defCausInfo.OriginDefaultValue == nil && allegrosql.HasNotNullFlag(defCausInfo.Flag) { 513 // If the defCausumn is timestamp default current_timestamp, and DBS tenant is new version MilevaDB that set defCausumn.Version to 1, 514 // then old MilevaDB uFIDelate record in the defCausumn write only stage will uses the wrong default value of the dropping defCausumn. 515 // Because new version of the defCausumn default value is UTC time, but old version MilevaDB will think the default value is the time in system timezone. 516 // But currently will be ok, because we can't cancel the drop defCausumn job when the job is running, 517 // so the defCausumn will be dropped succeed and client will never see the wrong default value of the dropped defCausumn. 518 // More info about this problem, see PR#9115. 519 defCausInfo.OriginDefaultValue, err = generateOriginDefaultValue(defCausInfo) 520 if err != nil { 521 return err 522 } 523 } 524 return nil 525 } 526 527 func onDropDeferredCauset(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 528 tblInfo, defCausInfo, idxInfos, err := checkDropDeferredCauset(t, job) 529 if err != nil { 530 return ver, errors.Trace(err) 531 } 532 533 originalState := defCausInfo.State 534 switch defCausInfo.State { 535 case perceptron.StatePublic: 536 // public -> write only 537 job.SchemaState = perceptron.StateWriteOnly 538 defCausInfo.State = perceptron.StateWriteOnly 539 setIndicesState(idxInfos, perceptron.StateWriteOnly) 540 err = checkDropDeferredCausetForStatePublic(tblInfo, defCausInfo) 541 if err != nil { 542 return ver, errors.Trace(err) 543 } 544 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != defCausInfo.State) 545 case perceptron.StateWriteOnly: 546 // write only -> delete only 547 job.SchemaState = perceptron.StateDeleteOnly 548 defCausInfo.State = perceptron.StateDeleteOnly 549 setIndicesState(idxInfos, perceptron.StateDeleteOnly) 550 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfo.State) 551 case perceptron.StateDeleteOnly: 552 // delete only -> reorganization 553 job.SchemaState = perceptron.StateDeleteReorganization 554 defCausInfo.State = perceptron.StateDeleteReorganization 555 setIndicesState(idxInfos, perceptron.StateDeleteReorganization) 556 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfo.State) 557 case perceptron.StateDeleteReorganization: 558 // reorganization -> absent 559 // All reorganization jobs are done, drop this defCausumn. 560 if len(idxInfos) > 0 { 561 newIndices := make([]*perceptron.IndexInfo, 0, len(tblInfo.Indices)) 562 for _, idx := range tblInfo.Indices { 563 if !indexInfoContains(idx.ID, idxInfos) { 564 newIndices = append(newIndices, idx) 565 } 566 } 567 tblInfo.Indices = newIndices 568 } 569 570 indexIDs := indexInfosToIDList(idxInfos) 571 tblInfo.DeferredCausets = tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-1] 572 defCausInfo.State = perceptron.StateNone 573 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != defCausInfo.State) 574 if err != nil { 575 return ver, errors.Trace(err) 576 } 577 578 // Finish this job. 579 if job.IsRollingback() { 580 job.FinishBlockJob(perceptron.JobStateRollbackDone, perceptron.StateNone, ver, tblInfo) 581 } else { 582 // We should set related index IDs for job 583 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StateNone, ver, tblInfo) 584 job.Args = append(job.Args, indexIDs, getPartitionIDs(tblInfo)) 585 } 586 default: 587 err = errInvalidDBSJob.GenWithStackByArgs("causet", tblInfo.State) 588 } 589 return ver, errors.Trace(err) 590 } 591 592 func checkDropDeferredCauset(t *spacetime.Meta, job *perceptron.Job) (*perceptron.BlockInfo, *perceptron.DeferredCausetInfo, []*perceptron.IndexInfo, error) { 593 schemaID := job.SchemaID 594 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, schemaID) 595 if err != nil { 596 return nil, nil, nil, errors.Trace(err) 597 } 598 599 var defCausName perceptron.CIStr 600 err = job.DecodeArgs(&defCausName) 601 if err != nil { 602 job.State = perceptron.JobStateCancelled 603 return nil, nil, nil, errors.Trace(err) 604 } 605 606 defCausInfo := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, defCausName.L) 607 if defCausInfo == nil || defCausInfo.Hidden { 608 job.State = perceptron.JobStateCancelled 609 return nil, nil, nil, ErrCantDropFieldOrKey.GenWithStack("defCausumn %s doesn't exist", defCausName) 610 } 611 if err = isDroppableDeferredCauset(tblInfo, defCausName); err != nil { 612 job.State = perceptron.JobStateCancelled 613 return nil, nil, nil, errors.Trace(err) 614 } 615 idxInfos := listIndicesWithDeferredCauset(defCausName.L, tblInfo.Indices) 616 if len(idxInfos) > 0 { 617 for _, idxInfo := range idxInfos { 618 err = checkDropIndexOnAutoIncrementDeferredCauset(tblInfo, idxInfo) 619 if err != nil { 620 job.State = perceptron.JobStateCancelled 621 return nil, nil, nil, err 622 } 623 } 624 } 625 return tblInfo, defCausInfo, idxInfos, nil 626 } 627 628 func onSetDefaultValue(t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 629 newDefCaus := &perceptron.DeferredCausetInfo{} 630 err := job.DecodeArgs(newDefCaus) 631 if err != nil { 632 job.State = perceptron.JobStateCancelled 633 return ver, errors.Trace(err) 634 } 635 636 return uFIDelateDeferredCausetDefaultValue(t, job, newDefCaus, &newDefCaus.Name) 637 } 638 639 func needChangeDeferredCausetData(oldDefCaus, newDefCaus *perceptron.DeferredCausetInfo) bool { 640 toUnsigned := allegrosql.HasUnsignedFlag(newDefCaus.Flag) 641 originUnsigned := allegrosql.HasUnsignedFlag(oldDefCaus.Flag) 642 if newDefCaus.Flen > 0 && newDefCaus.Flen < oldDefCaus.Flen || toUnsigned != originUnsigned { 643 return true 644 } 645 646 return false 647 } 648 649 type modifyDeferredCausetJobParameter struct { 650 newDefCaus *perceptron.DeferredCausetInfo 651 oldDefCausName *perceptron.CIStr 652 modifyDeferredCausetTp byte 653 uFIDelatedAutoRandomBits uint64 654 changingDefCaus *perceptron.DeferredCausetInfo 655 changingIdxs []*perceptron.IndexInfo 656 pos *ast.DeferredCausetPosition 657 } 658 659 func getModifyDeferredCausetInfo(t *spacetime.Meta, job *perceptron.Job) (*perceptron.DBInfo, *perceptron.BlockInfo, *perceptron.DeferredCausetInfo, *modifyDeferredCausetJobParameter, error) { 660 jobParam := &modifyDeferredCausetJobParameter{pos: &ast.DeferredCausetPosition{}} 661 err := job.DecodeArgs(&jobParam.newDefCaus, &jobParam.oldDefCausName, jobParam.pos, &jobParam.modifyDeferredCausetTp, &jobParam.uFIDelatedAutoRandomBits, &jobParam.changingDefCaus, &jobParam.changingIdxs) 662 if err != nil { 663 job.State = perceptron.JobStateCancelled 664 return nil, nil, nil, jobParam, errors.Trace(err) 665 } 666 667 dbInfo, err := checkSchemaExistAndCancelNotExistJob(t, job) 668 if err != nil { 669 return nil, nil, nil, jobParam, errors.Trace(err) 670 } 671 672 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 673 if err != nil { 674 return nil, nil, nil, jobParam, errors.Trace(err) 675 } 676 677 oldDefCaus := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, jobParam.oldDefCausName.L) 678 if oldDefCaus == nil || oldDefCaus.State != perceptron.StatePublic { 679 job.State = perceptron.JobStateCancelled 680 return nil, nil, nil, jobParam, errors.Trace(schemareplicant.ErrDeferredCausetNotExists.GenWithStackByArgs(*(jobParam.oldDefCausName), tblInfo.Name)) 681 } 682 683 return dbInfo, tblInfo, oldDefCaus, jobParam, errors.Trace(err) 684 } 685 686 func (w *worker) onModifyDeferredCauset(d *dbsCtx, t *spacetime.Meta, job *perceptron.Job) (ver int64, _ error) { 687 dbInfo, tblInfo, oldDefCaus, jobParam, err := getModifyDeferredCausetInfo(t, job) 688 if err != nil { 689 return ver, err 690 } 691 692 if job.IsRollingback() { 693 // For those defCausumn-type-change jobs which don't reorg the data. 694 if !needChangeDeferredCausetData(oldDefCaus, jobParam.newDefCaus) { 695 return rollbackModifyDeferredCausetJob(t, tblInfo, job, oldDefCaus, jobParam.modifyDeferredCausetTp) 696 } 697 // For those defCausumn-type-change jobs which reorg the data. 698 return rollbackModifyDeferredCausetJobWithData(t, tblInfo, job, oldDefCaus, jobParam) 699 } 700 701 // If we want to rename the defCausumn name, we need to check whether it already exists. 702 if jobParam.newDefCaus.Name.L != jobParam.oldDefCausName.L { 703 c := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, jobParam.newDefCaus.Name.L) 704 if c != nil { 705 job.State = perceptron.JobStateCancelled 706 return ver, errors.Trace(schemareplicant.ErrDeferredCausetExists.GenWithStackByArgs(jobParam.newDefCaus.Name)) 707 } 708 } 709 710 failpoint.Inject("uninitializedOffsetAndState", func(val failpoint.Value) { 711 if val.(bool) { 712 if jobParam.newDefCaus.State != perceptron.StatePublic { 713 failpoint.Return(ver, errors.New("the defCausumn state is wrong")) 714 } 715 } 716 }) 717 718 if jobParam.uFIDelatedAutoRandomBits > 0 { 719 if err := checkAndApplyNewAutoRandomBits(job, t, tblInfo, jobParam.newDefCaus, jobParam.oldDefCausName, jobParam.uFIDelatedAutoRandomBits); err != nil { 720 return ver, errors.Trace(err) 721 } 722 } 723 724 if !needChangeDeferredCausetData(oldDefCaus, jobParam.newDefCaus) { 725 return w.doModifyDeferredCauset(t, job, dbInfo, tblInfo, jobParam.newDefCaus, oldDefCaus, jobParam.pos) 726 } 727 728 if jobParam.changingDefCaus == nil { 729 changingDefCausPos := &ast.DeferredCausetPosition{Tp: ast.DeferredCausetPositionNone} 730 newDefCausName := perceptron.NewCIStr(fmt.Sprintf("%s%s", changingDeferredCausetPrefix, oldDefCaus.Name.O)) 731 if allegrosql.HasPriKeyFlag(oldDefCaus.Flag) { 732 job.State = perceptron.JobStateCancelled 733 msg := "milevadb_enable_change_defCausumn_type is true and this defCausumn has primary key flag" 734 return ver, errUnsupportedModifyDeferredCauset.GenWithStackByArgs(msg) 735 } 736 // TODO: Check whether we need to check OriginDefaultValue. 737 jobParam.changingDefCaus = jobParam.newDefCaus.Clone() 738 jobParam.changingDefCaus.Name = newDefCausName 739 jobParam.changingDefCaus.ChangeStateInfo = &perceptron.ChangeStateInfo{DependencyDeferredCausetOffset: oldDefCaus.Offset} 740 _, _, _, err := createDeferredCausetInfo(tblInfo, jobParam.changingDefCaus, changingDefCausPos) 741 if err != nil { 742 job.State = perceptron.JobStateCancelled 743 return ver, errors.Trace(err) 744 } 745 746 idxInfos, offsets := findIndexesByDefCausName(tblInfo.Indices, oldDefCaus.Name.L) 747 jobParam.changingIdxs = make([]*perceptron.IndexInfo, 0, len(idxInfos)) 748 for i, idxInfo := range idxInfos { 749 newIdxInfo := idxInfo.Clone() 750 newIdxInfo.Name = perceptron.NewCIStr(fmt.Sprintf("%s%s", changingIndexPrefix, newIdxInfo.Name.O)) 751 newIdxInfo.ID = allocateIndexID(tblInfo) 752 newIdxInfo.DeferredCausets[offsets[i]].Name = newDefCausName 753 newIdxInfo.DeferredCausets[offsets[i]].Offset = jobParam.changingDefCaus.Offset 754 jobParam.changingIdxs = append(jobParam.changingIdxs, newIdxInfo) 755 } 756 tblInfo.Indices = append(tblInfo.Indices, jobParam.changingIdxs...) 757 } else { 758 tblInfo.DeferredCausets[len(tblInfo.DeferredCausets)-1] = jobParam.changingDefCaus 759 copy(tblInfo.Indices[len(tblInfo.Indices)-len(jobParam.changingIdxs):], jobParam.changingIdxs) 760 } 761 762 return w.doModifyDeferredCausetTypeWithData(d, t, job, dbInfo, tblInfo, jobParam.changingDefCaus, oldDefCaus, jobParam.newDefCaus.Name, jobParam.pos, jobParam.changingIdxs) 763 } 764 765 // rollbackModifyDeferredCausetJobWithData is used to rollback modify-defCausumn job which need to reorg the data. 766 func rollbackModifyDeferredCausetJobWithData(t *spacetime.Meta, tblInfo *perceptron.BlockInfo, job *perceptron.Job, oldDefCaus *perceptron.DeferredCausetInfo, jobParam *modifyDeferredCausetJobParameter) (ver int64, err error) { 767 // If the not-null change is included, we should clean the flag info in oldDefCaus. 768 if jobParam.modifyDeferredCausetTp == allegrosql.TypeNull { 769 // Reset NotNullFlag flag. 770 tblInfo.DeferredCausets[oldDefCaus.Offset].Flag = oldDefCaus.Flag &^ allegrosql.NotNullFlag 771 // Reset PreventNullInsertFlag flag. 772 tblInfo.DeferredCausets[oldDefCaus.Offset].Flag = oldDefCaus.Flag &^ allegrosql.PreventNullInsertFlag 773 } 774 if jobParam.changingDefCaus != nil { 775 // changingDefCaus isn't nil means the job has been in the mid state. These appended changingDefCaus and changingIndex should 776 // be removed from the blockInfo as well. 777 tblInfo.DeferredCausets = tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-1] 778 tblInfo.Indices = tblInfo.Indices[:len(tblInfo.Indices)-len(jobParam.changingIdxs)] 779 } 780 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, true) 781 if err != nil { 782 return ver, errors.Trace(err) 783 } 784 job.FinishBlockJob(perceptron.JobStateRollbackDone, perceptron.StateNone, ver, tblInfo) 785 // Refactor the job args to add the abandoned temporary index ids into delete range causet. 786 idxIDs := make([]int64, 0, len(jobParam.changingIdxs)) 787 for _, idx := range jobParam.changingIdxs { 788 idxIDs = append(idxIDs, idx.ID) 789 } 790 job.Args = []interface{}{idxIDs, getPartitionIDs(tblInfo)} 791 return ver, nil 792 } 793 794 func (w *worker) doModifyDeferredCausetTypeWithData( 795 d *dbsCtx, t *spacetime.Meta, job *perceptron.Job, 796 dbInfo *perceptron.DBInfo, tblInfo *perceptron.BlockInfo, changingDefCaus, oldDefCaus *perceptron.DeferredCausetInfo, 797 defCausName perceptron.CIStr, pos *ast.DeferredCausetPosition, changingIdxs []*perceptron.IndexInfo) (ver int64, _ error) { 798 var err error 799 originalState := changingDefCaus.State 800 switch changingDefCaus.State { 801 case perceptron.StateNone: 802 // DeferredCauset from null to not null. 803 if !allegrosql.HasNotNullFlag(oldDefCaus.Flag) && allegrosql.HasNotNullFlag(changingDefCaus.Flag) { 804 // Introduce the `allegrosql.PreventNullInsertFlag` flag to prevent users from inserting or uFIDelating null values. 805 err := modifyDefCaussFromNull2NotNull(w, dbInfo, tblInfo, []*perceptron.DeferredCausetInfo{oldDefCaus}, oldDefCaus.Name, oldDefCaus.Tp != changingDefCaus.Tp) 806 if err != nil { 807 if ErrWarnDataTruncated.Equal(err) || errInvalidUseOfNull.Equal(err) { 808 job.State = perceptron.JobStateRollingback 809 } 810 return ver, err 811 } 812 } 813 // none -> delete only 814 uFIDelateChangingInfo(changingDefCaus, changingIdxs, perceptron.StateDeleteOnly) 815 failpoint.Inject("mockInsertValueAfterCheckNull", func(val failpoint.Value) { 816 if valStr, ok := val.(string); ok { 817 var ctx stochastikctx.Context 818 ctx, err := w.sessPool.get() 819 if err != nil { 820 failpoint.Return(ver, err) 821 } 822 defer w.sessPool.put(ctx) 823 824 _, _, err = ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(valStr) 825 if err != nil { 826 job.State = perceptron.JobStateCancelled 827 failpoint.Return(ver, err) 828 } 829 } 830 }) 831 ver, err = uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, originalState != changingDefCaus.State) 832 if err != nil { 833 return ver, errors.Trace(err) 834 } 835 // Make sure job args change after `uFIDelateVersionAndBlockInfoWithCheck`, otherwise, the job args will 836 // be uFIDelated in `uFIDelateDBSJob` even if it meets an error in `uFIDelateVersionAndBlockInfoWithCheck`. 837 job.SchemaState = perceptron.StateDeleteOnly 838 job.Args = append(job.Args, changingDefCaus, changingIdxs) 839 case perceptron.StateDeleteOnly: 840 // DeferredCauset from null to not null. 841 if !allegrosql.HasNotNullFlag(oldDefCaus.Flag) && allegrosql.HasNotNullFlag(changingDefCaus.Flag) { 842 // Introduce the `allegrosql.PreventNullInsertFlag` flag to prevent users from inserting or uFIDelating null values. 843 err := modifyDefCaussFromNull2NotNull(w, dbInfo, tblInfo, []*perceptron.DeferredCausetInfo{oldDefCaus}, oldDefCaus.Name, oldDefCaus.Tp != changingDefCaus.Tp) 844 if err != nil { 845 if ErrWarnDataTruncated.Equal(err) || errInvalidUseOfNull.Equal(err) { 846 job.State = perceptron.JobStateRollingback 847 } 848 return ver, err 849 } 850 } 851 // delete only -> write only 852 uFIDelateChangingInfo(changingDefCaus, changingIdxs, perceptron.StateWriteOnly) 853 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != changingDefCaus.State) 854 if err != nil { 855 return ver, errors.Trace(err) 856 } 857 job.SchemaState = perceptron.StateWriteOnly 858 case perceptron.StateWriteOnly: 859 // write only -> reorganization 860 uFIDelateChangingInfo(changingDefCaus, changingIdxs, perceptron.StateWriteReorganization) 861 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != changingDefCaus.State) 862 if err != nil { 863 return ver, errors.Trace(err) 864 } 865 job.SchemaState = perceptron.StateWriteReorganization 866 case perceptron.StateWriteReorganization: 867 tbl, err := getBlock(d.causetstore, dbInfo.ID, tblInfo) 868 if err != nil { 869 return ver, errors.Trace(err) 870 } 871 reorgInfo, err := getReorgInfo(d, t, job, tbl) 872 if err != nil || reorgInfo.first { 873 // If we run reorg firstly, we should uFIDelate the job snapshot version 874 // and then run the reorg next time. 875 return ver, errors.Trace(err) 876 } 877 878 err = w.runReorgJob(t, reorgInfo, tbl.Meta(), d.lease, func() (addIndexErr error) { 879 defer soliton.Recover(metrics.LabelDBS, "onModifyDeferredCauset", 880 func() { 881 addIndexErr = errCancelledDBSJob.GenWithStack("modify causet `%v` defCausumn `%v` panic", tblInfo.Name, oldDefCaus.Name) 882 }, false) 883 return w.uFIDelateDeferredCausetAndIndexes(tbl, oldDefCaus, changingDefCaus, changingIdxs, reorgInfo) 884 }) 885 if err != nil { 886 if errWaitReorgTimeout.Equal(err) { 887 // If timeout, we should return, check for the tenant and re-wait job done. 888 return ver, nil 889 } 890 if ekv.ErrKeyExists.Equal(err) || errCancelledDBSJob.Equal(err) || errCantDecodeRecord.Equal(err) || types.ErrOverflow.Equal(err) { 891 logutil.BgLogger().Warn("[dbs] run modify defCausumn job failed, convert job to rollback", zap.String("job", job.String()), zap.Error(err)) 892 // When encounter these error above, we change the job to rolling back job directly. 893 job.State = perceptron.JobStateRollingback 894 return ver, errors.Trace(err) 895 } 896 // Clean up the channel of notifyCancelReorgJob. Make sure it can't affect other jobs. 897 w.reorgCtx.cleanNotifyReorgCancel() 898 return ver, errors.Trace(err) 899 } 900 // Clean up the channel of notifyCancelReorgJob. Make sure it can't affect other jobs. 901 w.reorgCtx.cleanNotifyReorgCancel() 902 903 // Remove the old defCausumn and indexes. UFIDelate the relative defCausumn name and index names. 904 oldIdxIDs := make([]int64, 0, len(changingIdxs)) 905 tblInfo.DeferredCausets = tblInfo.DeferredCausets[:len(tblInfo.DeferredCausets)-1] 906 for _, cIdx := range changingIdxs { 907 idxName := strings.TrimPrefix(cIdx.Name.O, changingIndexPrefix) 908 for i, idx := range tblInfo.Indices { 909 if strings.EqualFold(idxName, idx.Name.L) { 910 cIdx.Name = perceptron.NewCIStr(idxName) 911 tblInfo.Indices[i] = cIdx 912 oldIdxIDs = append(oldIdxIDs, idx.ID) 913 break 914 } 915 } 916 } 917 changingDefCaus.Name = defCausName 918 changingDefCaus.ChangeStateInfo = nil 919 tblInfo.Indices = tblInfo.Indices[:len(tblInfo.Indices)-len(changingIdxs)] 920 // Adjust causet defCausumn offset. 921 if err = adjustDeferredCausetInfoInModifyDeferredCauset(job, tblInfo, changingDefCaus, oldDefCaus, pos); err != nil { 922 // TODO: Do rollback. 923 return ver, errors.Trace(err) 924 } 925 uFIDelateChangingInfo(changingDefCaus, changingIdxs, perceptron.StatePublic) 926 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, originalState != changingDefCaus.State) 927 if err != nil { 928 return ver, errors.Trace(err) 929 } 930 931 // Finish this job. 932 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 933 // Refactor the job args to add the old index ids into delete range causet. 934 job.Args = []interface{}{oldIdxIDs, getPartitionIDs(tblInfo)} 935 // TODO: Change defCausumn ID. 936 // asyncNotifyEvent(d, &soliton.Event{Tp: perceptron.CausetActionAddDeferredCauset, BlockInfo: tblInfo, DeferredCausetInfos: []*perceptron.DeferredCausetInfo{changingDefCaus}}) 937 default: 938 err = ErrInvalidDBSState.GenWithStackByArgs("defCausumn", changingDefCaus.State) 939 } 940 941 return ver, errors.Trace(err) 942 } 943 944 func (w *worker) uFIDelatePhysicalBlockRow(t causet.PhysicalBlock, oldDefCausInfo, defCausInfo *perceptron.DeferredCausetInfo, reorgInfo *reorgInfo) error { 945 logutil.BgLogger().Info("[dbs] start to uFIDelate causet event", zap.String("job", reorgInfo.Job.String()), zap.String("reorgInfo", reorgInfo.String())) 946 return w.writePhysicalBlockRecord(t.(causet.PhysicalBlock), typeUFIDelateDeferredCausetWorker, nil, oldDefCausInfo, defCausInfo, reorgInfo) 947 } 948 949 // uFIDelateDeferredCausetAndIndexes handles the modify defCausumn reorganization state for a causet. 950 func (w *worker) uFIDelateDeferredCausetAndIndexes(t causet.Block, oldDefCaus, defCaus *perceptron.DeferredCausetInfo, idxes []*perceptron.IndexInfo, reorgInfo *reorgInfo) error { 951 // TODO: Consider rebuild ReorgInfo key to mDBSJobReorgKey_jobID_elementID(defCausID/idxID). 952 // TODO: Support partition blocks. 953 err := w.uFIDelatePhysicalBlockRow(t.(causet.PhysicalBlock), oldDefCaus, defCaus, reorgInfo) 954 if err != nil { 955 return errors.Trace(err) 956 } 957 958 for _, idx := range idxes { 959 err = w.addBlockIndex(t, idx, reorgInfo) 960 if err != nil { 961 return errors.Trace(err) 962 } 963 } 964 return nil 965 } 966 967 type uFIDelateDeferredCausetWorker struct { 968 *backfillWorker 969 oldDefCausInfo *perceptron.DeferredCausetInfo 970 newDefCausInfo *perceptron.DeferredCausetInfo 971 metricCounter prometheus.Counter 972 973 // The following attributes are used to reduce memory allocation. 974 rowRecords []*rowRecord 975 rowCausetDecoder *causetDecoder.RowCausetDecoder 976 977 rowMap map[int64]types.Causet 978 } 979 980 func newUFIDelateDeferredCausetWorker(sessCtx stochastikctx.Context, worker *worker, id int, t causet.PhysicalBlock, oldDefCaus, newDefCaus *perceptron.DeferredCausetInfo, decodeDefCausMap map[int64]causetDecoder.DeferredCauset) *uFIDelateDeferredCausetWorker { 981 rowCausetDecoder := causetDecoder.NewRowCausetDecoder(t, t.WriblockDefCauss(), decodeDefCausMap) 982 return &uFIDelateDeferredCausetWorker{ 983 backfillWorker: newBackfillWorker(sessCtx, worker, id, t), 984 oldDefCausInfo: oldDefCaus, 985 newDefCausInfo: newDefCaus, 986 metricCounter: metrics.BackfillTotalCounter.WithLabelValues("uFIDelate_defCaus_speed"), 987 rowCausetDecoder: rowCausetDecoder, 988 rowMap: make(map[int64]types.Causet, len(decodeDefCausMap)), 989 } 990 } 991 992 func (w *uFIDelateDeferredCausetWorker) AddMetricInfo(cnt float64) { 993 w.metricCounter.Add(cnt) 994 } 995 996 type rowRecord struct { 997 key []byte // It's used to dagger a record. Record it to reduce the encoding time. 998 vals []byte // It's the record. 999 } 1000 1001 // getNextHandle gets next handle of entry that we are going to process. 1002 func (w *uFIDelateDeferredCausetWorker) getNextHandle(taskRange reorgBackfillTask, taskDone bool, lastAccessedHandle ekv.Handle) (nextHandle ekv.Handle) { 1003 if !taskDone { 1004 // The task is not done. So we need to pick the last processed entry's handle and add one. 1005 return lastAccessedHandle.Next() 1006 } 1007 1008 // The task is done. So we need to choose a handle outside this range. 1009 // Some corner cases should be considered: 1010 // - The end of task range is MaxInt64. 1011 // - The end of the task is excluded in the range. 1012 if (taskRange.endHandle.IsInt() && taskRange.endHandle.IntValue() == math.MaxInt64) || !taskRange.endIncluded { 1013 return taskRange.endHandle 1014 } 1015 1016 return taskRange.endHandle.Next() 1017 } 1018 1019 func (w *uFIDelateDeferredCausetWorker) fetchRowDefCausVals(txn ekv.Transaction, taskRange reorgBackfillTask) ([]*rowRecord, ekv.Handle, bool, error) { 1020 w.rowRecords = w.rowRecords[:0] 1021 startTime := time.Now() 1022 1023 // taskDone means that the added handle is out of taskRange.endHandle. 1024 taskDone := false 1025 var lastAccessedHandle ekv.Handle 1026 oprStartTime := startTime 1027 err := iterateSnapshotRows(w.sessCtx.GetStore(), w.priority, w.causet, txn.StartTS(), taskRange.startHandle, taskRange.endHandle, taskRange.endIncluded, 1028 func(handle ekv.Handle, recordKey ekv.Key, rawRow []byte) (bool, error) { 1029 oprEndTime := time.Now() 1030 logSlowOperations(oprEndTime.Sub(oprStartTime), "iterateSnapshotRows in uFIDelateDeferredCausetWorker fetchRowDefCausVals", 0) 1031 oprStartTime = oprEndTime 1032 1033 if !taskRange.endIncluded { 1034 taskDone = handle.Compare(taskRange.endHandle) >= 0 1035 } else { 1036 taskDone = handle.Compare(taskRange.endHandle) > 0 1037 } 1038 1039 if taskDone || len(w.rowRecords) >= w.batchCnt { 1040 return false, nil 1041 } 1042 1043 if err1 := w.getRowRecord(handle, recordKey, rawRow); err1 != nil { 1044 return false, errors.Trace(err1) 1045 } 1046 lastAccessedHandle = handle 1047 if handle.Equal(taskRange.endHandle) { 1048 // If taskRange.endIncluded == false, we will not reach here when handle == taskRange.endHandle. 1049 taskDone = true 1050 return false, nil 1051 } 1052 return true, nil 1053 }) 1054 1055 if len(w.rowRecords) == 0 { 1056 taskDone = true 1057 } 1058 1059 logutil.BgLogger().Debug("[dbs] txn fetches handle info", zap.Uint64("txnStartTS", txn.StartTS()), zap.String("taskRange", taskRange.String()), zap.Duration("takeTime", time.Since(startTime))) 1060 return w.rowRecords, w.getNextHandle(taskRange, taskDone, lastAccessedHandle), taskDone, errors.Trace(err) 1061 } 1062 1063 func (w *uFIDelateDeferredCausetWorker) getRowRecord(handle ekv.Handle, recordKey []byte, rawRow []byte) error { 1064 _, err := w.rowCausetDecoder.DecodeAndEvalRowWithMap(w.sessCtx, handle, rawRow, time.UTC, timeutil.SystemLocation(), w.rowMap) 1065 if err != nil { 1066 return errors.Trace(errCantDecodeRecord.GenWithStackByArgs("defCausumn", err)) 1067 } 1068 1069 if _, ok := w.rowMap[w.newDefCausInfo.ID]; ok { 1070 // The defCausumn is already added by uFIDelate or insert memex, skip it. 1071 w.cleanRowMap() 1072 return nil 1073 } 1074 1075 newDefCausVal, err := causet.CastValue(w.sessCtx, w.rowMap[w.oldDefCausInfo.ID], w.newDefCausInfo, false, false) 1076 // TODO: Consider sql_mode and the error msg(encounter this error check whether to rollback). 1077 if err != nil { 1078 return errors.Trace(err) 1079 } 1080 w.rowMap[w.newDefCausInfo.ID] = newDefCausVal 1081 newDeferredCausetIDs := make([]int64, 0, len(w.rowMap)) 1082 newRow := make([]types.Causet, 0, len(w.rowMap)) 1083 for defCausID, val := range w.rowMap { 1084 newDeferredCausetIDs = append(newDeferredCausetIDs, defCausID) 1085 newRow = append(newRow, val) 1086 } 1087 sctx, rd := w.sessCtx.GetStochastikVars().StmtCtx, &w.sessCtx.GetStochastikVars().RowCausetEncoder 1088 newRowVal, err := blockcodec.EncodeRow(sctx, newRow, newDeferredCausetIDs, nil, nil, rd) 1089 if err != nil { 1090 return errors.Trace(err) 1091 } 1092 1093 w.rowRecords = append(w.rowRecords, &rowRecord{key: recordKey, vals: newRowVal}) 1094 w.cleanRowMap() 1095 return nil 1096 } 1097 1098 func (w *uFIDelateDeferredCausetWorker) cleanRowMap() { 1099 for id := range w.rowMap { 1100 delete(w.rowMap, id) 1101 } 1102 } 1103 1104 // BackfillDataInTxn will backfill the causet record in a transaction, dagger corresponding rowKey, if the value of rowKey is changed. 1105 func (w *uFIDelateDeferredCausetWorker) BackfillDataInTxn(handleRange reorgBackfillTask) (taskCtx backfillTaskContext, errInTxn error) { 1106 oprStartTime := time.Now() 1107 errInTxn = ekv.RunInNewTxn(w.sessCtx.GetStore(), true, func(txn ekv.Transaction) error { 1108 taskCtx.addedCount = 0 1109 taskCtx.scanCount = 0 1110 txn.SetOption(ekv.Priority, w.priority) 1111 1112 rowRecords, nextHandle, taskDone, err := w.fetchRowDefCausVals(txn, handleRange) 1113 if err != nil { 1114 return errors.Trace(err) 1115 } 1116 taskCtx.nextHandle = nextHandle 1117 taskCtx.done = taskDone 1118 1119 for _, rowRecord := range rowRecords { 1120 taskCtx.scanCount++ 1121 1122 err = txn.Set(rowRecord.key, rowRecord.vals) 1123 if err != nil { 1124 return errors.Trace(err) 1125 } 1126 taskCtx.addedCount++ 1127 } 1128 1129 return nil 1130 }) 1131 logSlowOperations(time.Since(oprStartTime), "BackfillDataInTxn", 3000) 1132 1133 return 1134 } 1135 1136 func uFIDelateChangingInfo(changingDefCaus *perceptron.DeferredCausetInfo, changingIdxs []*perceptron.IndexInfo, schemaState perceptron.SchemaState) { 1137 changingDefCaus.State = schemaState 1138 for _, idx := range changingIdxs { 1139 idx.State = schemaState 1140 } 1141 } 1142 1143 // doModifyDeferredCauset uFIDelates the defCausumn information and reorders all defCausumns. It does not support modifying defCausumn data. 1144 func (w *worker) doModifyDeferredCauset( 1145 t *spacetime.Meta, job *perceptron.Job, dbInfo *perceptron.DBInfo, tblInfo *perceptron.BlockInfo, 1146 newDefCaus, oldDefCaus *perceptron.DeferredCausetInfo, pos *ast.DeferredCausetPosition) (ver int64, _ error) { 1147 // DeferredCauset from null to not null. 1148 if !allegrosql.HasNotNullFlag(oldDefCaus.Flag) && allegrosql.HasNotNullFlag(newDefCaus.Flag) { 1149 noPreventNullFlag := !allegrosql.HasPreventNullInsertFlag(oldDefCaus.Flag) 1150 // Introduce the `allegrosql.PreventNullInsertFlag` flag to prevent users from inserting or uFIDelating null values. 1151 err := modifyDefCaussFromNull2NotNull(w, dbInfo, tblInfo, []*perceptron.DeferredCausetInfo{oldDefCaus}, newDefCaus.Name, oldDefCaus.Tp != newDefCaus.Tp) 1152 if err != nil { 1153 if ErrWarnDataTruncated.Equal(err) || errInvalidUseOfNull.Equal(err) { 1154 job.State = perceptron.JobStateRollingback 1155 } 1156 return ver, err 1157 } 1158 // The defCausumn should get into prevent null status first. 1159 if noPreventNullFlag { 1160 return uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, true) 1161 } 1162 } 1163 1164 if err := adjustDeferredCausetInfoInModifyDeferredCauset(job, tblInfo, newDefCaus, oldDefCaus, pos); err != nil { 1165 return ver, errors.Trace(err) 1166 } 1167 1168 ver, err := uFIDelateVersionAndBlockInfoWithCheck(t, job, tblInfo, true) 1169 if err != nil { 1170 // Modified the type definition of 'null' to 'not null' before this, so rollBack the job when an error occurs. 1171 job.State = perceptron.JobStateRollingback 1172 return ver, errors.Trace(err) 1173 } 1174 1175 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 1176 // For those defCausumn-type-change type which doesn't need reorg data, we should also mock the job args for delete range. 1177 job.Args = []interface{}{[]int64{}, []int64{}} 1178 return ver, nil 1179 } 1180 1181 func adjustDeferredCausetInfoInModifyDeferredCauset( 1182 job *perceptron.Job, tblInfo *perceptron.BlockInfo, newDefCaus, oldDefCaus *perceptron.DeferredCausetInfo, pos *ast.DeferredCausetPosition) error { 1183 // We need the latest defCausumn's offset and state. This information can be obtained from the causetstore. 1184 newDefCaus.Offset = oldDefCaus.Offset 1185 newDefCaus.State = oldDefCaus.State 1186 // Calculate defCausumn's new position. 1187 oldPos, newPos := oldDefCaus.Offset, oldDefCaus.Offset 1188 if pos.Tp == ast.DeferredCausetPositionAfter { 1189 // TODO: The check of "RelativeDeferredCauset" can be checked in advance. When "EnableChangeDeferredCausetType" is true, unnecessary state changes can be reduced. 1190 if oldDefCaus.Name.L == pos.RelativeDeferredCauset.Name.L { 1191 // `alter causet blockName modify defCausumn b int after b` will return ver,ErrDeferredCausetNotExists. 1192 // Modified the type definition of 'null' to 'not null' before this, so rollback the job when an error occurs. 1193 job.State = perceptron.JobStateRollingback 1194 return schemareplicant.ErrDeferredCausetNotExists.GenWithStackByArgs(oldDefCaus.Name, tblInfo.Name) 1195 } 1196 1197 relative := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, pos.RelativeDeferredCauset.Name.L) 1198 if relative == nil || relative.State != perceptron.StatePublic { 1199 job.State = perceptron.JobStateRollingback 1200 return schemareplicant.ErrDeferredCausetNotExists.GenWithStackByArgs(pos.RelativeDeferredCauset, tblInfo.Name) 1201 } 1202 1203 if relative.Offset < oldPos { 1204 newPos = relative.Offset + 1 1205 } else { 1206 newPos = relative.Offset 1207 } 1208 } else if pos.Tp == ast.DeferredCausetPositionFirst { 1209 newPos = 0 1210 } 1211 1212 defCausumnChanged := make(map[string]*perceptron.DeferredCausetInfo) 1213 defCausumnChanged[oldDefCaus.Name.L] = newDefCaus 1214 1215 if newPos == oldPos { 1216 tblInfo.DeferredCausets[newPos] = newDefCaus 1217 } else { 1218 defcaus := tblInfo.DeferredCausets 1219 1220 // Reorder defCausumns in place. 1221 if newPos < oldPos { 1222 // ******** +(new) ****** -(old) ******** 1223 // [newPos:old-1] should shift one step to the right. 1224 copy(defcaus[newPos+1:], defcaus[newPos:oldPos]) 1225 } else { 1226 // ******** -(old) ****** +(new) ******** 1227 // [old+1:newPos] should shift one step to the left. 1228 copy(defcaus[oldPos:], defcaus[oldPos+1:newPos+1]) 1229 } 1230 defcaus[newPos] = newDefCaus 1231 1232 for i, defCaus := range tblInfo.DeferredCausets { 1233 if defCaus.Offset != i { 1234 defCausumnChanged[defCaus.Name.L] = defCaus 1235 defCaus.Offset = i 1236 } 1237 } 1238 } 1239 1240 // Change offset and name in indices. 1241 for _, idx := range tblInfo.Indices { 1242 for _, c := range idx.DeferredCausets { 1243 cName := strings.ToLower(strings.TrimPrefix(c.Name.O, changingDeferredCausetPrefix)) 1244 if newDefCaus, ok := defCausumnChanged[cName]; ok { 1245 c.Name = newDefCaus.Name 1246 c.Offset = newDefCaus.Offset 1247 } 1248 } 1249 } 1250 return nil 1251 } 1252 1253 func checkAndApplyNewAutoRandomBits(job *perceptron.Job, t *spacetime.Meta, tblInfo *perceptron.BlockInfo, 1254 newDefCaus *perceptron.DeferredCausetInfo, oldName *perceptron.CIStr, newAutoRandBits uint64) error { 1255 schemaID := job.SchemaID 1256 newLayout := autoid.NewAutoRandomIDLayout(&newDefCaus.FieldType, newAutoRandBits) 1257 1258 // GenAutoRandomID first to prevent concurrent uFIDelate. 1259 _, err := t.GenAutoRandomID(schemaID, tblInfo.ID, 1) 1260 if err != nil { 1261 return err 1262 } 1263 currentIncBitsVal, err := t.GetAutoRandomID(schemaID, tblInfo.ID) 1264 if err != nil { 1265 return err 1266 } 1267 // Find the max number of available shard bits by 1268 // counting leading zeros in current inc part of auto_random ID. 1269 availableBits := bits.LeadingZeros64(uint64(currentIncBitsVal)) 1270 isOccupyingIncBits := newLayout.TypeBitsLength-newLayout.IncrementalBits > uint64(availableBits) 1271 if isOccupyingIncBits { 1272 availableBits := mathutil.Min(autoid.MaxAutoRandomBits, availableBits) 1273 errMsg := fmt.Sprintf(autoid.AutoRandomOverflowErrMsg, availableBits, newAutoRandBits, oldName.O) 1274 job.State = perceptron.JobStateCancelled 1275 return ErrInvalidAutoRandom.GenWithStackByArgs(errMsg) 1276 } 1277 tblInfo.AutoRandomBits = newAutoRandBits 1278 return nil 1279 } 1280 1281 // checkForNullValue ensure there are no null values of the defCausumn of this causet. 1282 // `isDataTruncated` indicates whether the new field and the old field type are the same, in order to be compatible with allegrosql. 1283 func checkForNullValue(ctx stochastikctx.Context, isDataTruncated bool, schemaReplicant, causet, newDefCaus perceptron.CIStr, oldDefCauss ...*perceptron.DeferredCausetInfo) error { 1284 defcausStr := "" 1285 for i, defCaus := range oldDefCauss { 1286 if i == 0 { 1287 defcausStr += "`" + defCaus.Name.L + "` is null" 1288 } else { 1289 defcausStr += " or `" + defCaus.Name.L + "` is null" 1290 } 1291 } 1292 allegrosql := fmt.Sprintf("select 1 from `%s`.`%s` where %s limit 1;", schemaReplicant.L, causet.L, defcausStr) 1293 rows, _, err := ctx.(sqlexec.RestrictedALLEGROSQLInterlockingDirectorate).InterDircRestrictedALLEGROSQL(allegrosql) 1294 if err != nil { 1295 return errors.Trace(err) 1296 } 1297 rowCount := len(rows) 1298 if rowCount != 0 { 1299 if isDataTruncated { 1300 return ErrWarnDataTruncated.GenWithStackByArgs(newDefCaus.L, rowCount) 1301 } 1302 return errInvalidUseOfNull 1303 } 1304 return nil 1305 } 1306 1307 func uFIDelateDeferredCausetDefaultValue(t *spacetime.Meta, job *perceptron.Job, newDefCaus *perceptron.DeferredCausetInfo, oldDefCausName *perceptron.CIStr) (ver int64, _ error) { 1308 tblInfo, err := getBlockInfoAndCancelFaultJob(t, job, job.SchemaID) 1309 if err != nil { 1310 return ver, errors.Trace(err) 1311 } 1312 oldDefCaus := perceptron.FindDeferredCausetInfo(tblInfo.DeferredCausets, oldDefCausName.L) 1313 if oldDefCaus == nil || oldDefCaus.State != perceptron.StatePublic { 1314 job.State = perceptron.JobStateCancelled 1315 return ver, schemareplicant.ErrDeferredCausetNotExists.GenWithStackByArgs(newDefCaus.Name, tblInfo.Name) 1316 } 1317 // The newDefCaus's offset may be the value of the old schemaReplicant version, so we can't use newDefCaus directly. 1318 oldDefCaus.DefaultValue = newDefCaus.DefaultValue 1319 oldDefCaus.DefaultValueBit = newDefCaus.DefaultValueBit 1320 oldDefCaus.Flag = newDefCaus.Flag 1321 1322 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 1323 if err != nil { 1324 job.State = perceptron.JobStateCancelled 1325 return ver, errors.Trace(err) 1326 } 1327 1328 job.FinishBlockJob(perceptron.JobStateDone, perceptron.StatePublic, ver, tblInfo) 1329 return ver, nil 1330 } 1331 1332 func isDeferredCausetWithIndex(defCausName string, indices []*perceptron.IndexInfo) bool { 1333 for _, indexInfo := range indices { 1334 for _, defCaus := range indexInfo.DeferredCausets { 1335 if defCaus.Name.L == defCausName { 1336 return true 1337 } 1338 } 1339 } 1340 return false 1341 } 1342 1343 func isDeferredCausetCanDropWithIndex(defCausName string, indices []*perceptron.IndexInfo) bool { 1344 for _, indexInfo := range indices { 1345 if indexInfo.Primary || len(indexInfo.DeferredCausets) > 1 { 1346 for _, defCaus := range indexInfo.DeferredCausets { 1347 if defCaus.Name.L == defCausName { 1348 return false 1349 } 1350 } 1351 } 1352 } 1353 return true 1354 } 1355 1356 func listIndicesWithDeferredCauset(defCausName string, indices []*perceptron.IndexInfo) []*perceptron.IndexInfo { 1357 ret := make([]*perceptron.IndexInfo, 0) 1358 for _, indexInfo := range indices { 1359 if len(indexInfo.DeferredCausets) == 1 && defCausName == indexInfo.DeferredCausets[0].Name.L { 1360 ret = append(ret, indexInfo) 1361 } 1362 } 1363 return ret 1364 } 1365 1366 func getDeferredCausetForeignKeyInfo(defCausName string, fkInfos []*perceptron.FKInfo) *perceptron.FKInfo { 1367 for _, fkInfo := range fkInfos { 1368 for _, defCaus := range fkInfo.DefCauss { 1369 if defCaus.L == defCausName { 1370 return fkInfo 1371 } 1372 } 1373 } 1374 return nil 1375 } 1376 1377 func allocateDeferredCausetID(tblInfo *perceptron.BlockInfo) int64 { 1378 tblInfo.MaxDeferredCausetID++ 1379 return tblInfo.MaxDeferredCausetID 1380 } 1381 1382 func checkAddDeferredCausetTooManyDeferredCausets(defCausNum int) error { 1383 if uint32(defCausNum) > atomic.LoadUint32(&BlockDeferredCausetCountLimit) { 1384 return errTooManyFields 1385 } 1386 return nil 1387 } 1388 1389 // rollbackModifyDeferredCausetJob rollbacks the job when an error occurs. 1390 func rollbackModifyDeferredCausetJob(t *spacetime.Meta, tblInfo *perceptron.BlockInfo, job *perceptron.Job, oldDefCaus *perceptron.DeferredCausetInfo, modifyDeferredCausetTp byte) (ver int64, _ error) { 1391 var err error 1392 if modifyDeferredCausetTp == allegrosql.TypeNull { 1393 // field NotNullFlag flag reset. 1394 tblInfo.DeferredCausets[oldDefCaus.Offset].Flag = oldDefCaus.Flag &^ allegrosql.NotNullFlag 1395 // field PreventNullInsertFlag flag reset. 1396 tblInfo.DeferredCausets[oldDefCaus.Offset].Flag = oldDefCaus.Flag &^ allegrosql.PreventNullInsertFlag 1397 ver, err = uFIDelateVersionAndBlockInfo(t, job, tblInfo, true) 1398 if err != nil { 1399 return ver, errors.Trace(err) 1400 } 1401 } 1402 job.FinishBlockJob(perceptron.JobStateRollbackDone, perceptron.StateNone, ver, tblInfo) 1403 // For those defCausumn-type-change type which doesn't need reorg data, we should also mock the job args for delete range. 1404 job.Args = []interface{}{[]int64{}, []int64{}} 1405 return ver, nil 1406 } 1407 1408 // modifyDefCaussFromNull2NotNull modifies the type definitions of 'null' to 'not null'. 1409 // Introduce the `allegrosql.PreventNullInsertFlag` flag to prevent users from inserting or uFIDelating null values. 1410 func modifyDefCaussFromNull2NotNull(w *worker, dbInfo *perceptron.DBInfo, tblInfo *perceptron.BlockInfo, defcaus []*perceptron.DeferredCausetInfo, 1411 newDefCausName perceptron.CIStr, isModifiedType bool) error { 1412 // Get stochastikctx from context resource pool. 1413 var ctx stochastikctx.Context 1414 ctx, err := w.sessPool.get() 1415 if err != nil { 1416 return errors.Trace(err) 1417 } 1418 defer w.sessPool.put(ctx) 1419 1420 skipCheck := false 1421 failpoint.Inject("skipMockContextDoInterDirc", func(val failpoint.Value) { 1422 if val.(bool) { 1423 skipCheck = true 1424 } 1425 }) 1426 if !skipCheck { 1427 // If there is a null value inserted, it cannot be modified and needs to be rollback. 1428 err = checkForNullValue(ctx, isModifiedType, dbInfo.Name, tblInfo.Name, newDefCausName, defcaus...) 1429 if err != nil { 1430 return errors.Trace(err) 1431 } 1432 } 1433 1434 // Prevent this field from inserting null values. 1435 for _, defCaus := range defcaus { 1436 defCaus.Flag |= allegrosql.PreventNullInsertFlag 1437 } 1438 return nil 1439 } 1440 1441 func generateOriginDefaultValue(defCaus *perceptron.DeferredCausetInfo) (interface{}, error) { 1442 var err error 1443 odValue := defCaus.GetDefaultValue() 1444 if odValue == nil && allegrosql.HasNotNullFlag(defCaus.Flag) { 1445 zeroVal := causet.GetZeroValue(defCaus) 1446 odValue, err = zeroVal.ToString() 1447 if err != nil { 1448 return nil, errors.Trace(err) 1449 } 1450 } 1451 1452 if odValue == strings.ToUpper(ast.CurrentTimestamp) { 1453 if defCaus.Tp == allegrosql.TypeTimestamp { 1454 odValue = time.Now().UTC().Format(types.TimeFormat) 1455 } else if defCaus.Tp == allegrosql.TypeDatetime { 1456 odValue = time.Now().Format(types.TimeFormat) 1457 } 1458 } 1459 return odValue, nil 1460 } 1461 1462 func findDeferredCausetInIndexDefCauss(c string, defcaus []*perceptron.IndexDeferredCauset) *perceptron.IndexDeferredCauset { 1463 for _, c1 := range defcaus { 1464 if c == c1.Name.L { 1465 return c1 1466 } 1467 } 1468 return nil 1469 } 1470 1471 func getDeferredCausetInfoByName(tbInfo *perceptron.BlockInfo, defCausumn string) *perceptron.DeferredCausetInfo { 1472 for _, defCausInfo := range tbInfo.DefCauss() { 1473 if defCausInfo.Name.L == defCausumn { 1474 return defCausInfo 1475 } 1476 } 1477 return nil 1478 } 1479 1480 // isVirtualGeneratedDeferredCauset checks the defCausumn if it is virtual. 1481 func isVirtualGeneratedDeferredCauset(defCaus *perceptron.DeferredCausetInfo) bool { 1482 if defCaus.IsGenerated() && !defCaus.GeneratedStored { 1483 return true 1484 } 1485 return false 1486 } 1487 1488 func indexInfoContains(idxID int64, idxInfos []*perceptron.IndexInfo) bool { 1489 for _, idxInfo := range idxInfos { 1490 if idxID == idxInfo.ID { 1491 return true 1492 } 1493 } 1494 return false 1495 } 1496 1497 func indexInfosToIDList(idxInfos []*perceptron.IndexInfo) []int64 { 1498 ids := make([]int64, 0, len(idxInfos)) 1499 for _, idxInfo := range idxInfos { 1500 ids = append(ids, idxInfo.ID) 1501 } 1502 return ids 1503 }