github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/split.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 interlock 15 16 import ( 17 "bytes" 18 "context" 19 "encoding/binary" 20 "fmt" 21 "math" 22 "time" 23 24 "github.com/cznic/mathutil" 25 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 26 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 27 "github.com/whtcorpsinc/ekvproto/pkg/spacetimepb" 28 "github.com/whtcorpsinc/errors" 29 "github.com/whtcorpsinc/milevadb/blockcodec" 30 "github.com/whtcorpsinc/milevadb/causet/blocks" 31 "github.com/whtcorpsinc/milevadb/causet/embedded" 32 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 33 "github.com/whtcorpsinc/milevadb/causetstore/helper" 34 "github.com/whtcorpsinc/milevadb/ekv" 35 "github.com/whtcorpsinc/milevadb/soliton/chunk" 36 "github.com/whtcorpsinc/milevadb/soliton/codec" 37 "github.com/whtcorpsinc/milevadb/soliton/logutil" 38 "github.com/whtcorpsinc/milevadb/stochastikctx" 39 "github.com/whtcorpsinc/milevadb/types" 40 "go.uber.org/zap" 41 ) 42 43 // SplitIndexRegionInterDirc represents a split index regions interlock. 44 type SplitIndexRegionInterDirc struct { 45 baseInterlockingDirectorate 46 47 blockInfo *perceptron.BlockInfo 48 partitionNames []perceptron.CIStr 49 indexInfo *perceptron.IndexInfo 50 lower []types.Causet 51 upper []types.Causet 52 num int 53 handleDefCauss embedded.HandleDefCauss 54 valueLists [][]types.Causet 55 splitIdxKeys [][]byte 56 57 done bool 58 splitRegionResult 59 } 60 61 type splitRegionResult struct { 62 splitRegions int 63 finishScatterNum int 64 } 65 66 // Open implements the InterlockingDirectorate Open interface. 67 func (e *SplitIndexRegionInterDirc) Open(ctx context.Context) (err error) { 68 e.splitIdxKeys, err = e.getSplitIdxKeys() 69 return err 70 } 71 72 // Next implements the InterlockingDirectorate Next interface. 73 func (e *SplitIndexRegionInterDirc) Next(ctx context.Context, chk *chunk.Chunk) error { 74 chk.Reset() 75 if e.done { 76 return nil 77 } 78 e.done = true 79 if err := e.splitIndexRegion(ctx); err != nil { 80 return err 81 } 82 83 appendSplitRegionResultToChunk(chk, e.splitRegions, e.finishScatterNum) 84 return nil 85 } 86 87 // checkScatterRegionFinishBackOff is the back off time that used to check if a region has finished scattering before split region timeout. 88 const checkScatterRegionFinishBackOff = 50 89 90 // splitIndexRegion is used to split index regions. 91 func (e *SplitIndexRegionInterDirc) splitIndexRegion(ctx context.Context) error { 92 causetstore := e.ctx.GetStore() 93 s, ok := causetstore.(ekv.SplitblockStore) 94 if !ok { 95 return nil 96 } 97 98 start := time.Now() 99 ctxWithTimeout, cancel := context.WithTimeout(ctx, e.ctx.GetStochastikVars().GetSplitRegionTimeout()) 100 defer cancel() 101 regionIDs, err := s.SplitRegions(ctxWithTimeout, e.splitIdxKeys, true, &e.blockInfo.ID) 102 if err != nil { 103 logutil.BgLogger().Warn("split causet index region failed", 104 zap.String("causet", e.blockInfo.Name.L), 105 zap.String("index", e.indexInfo.Name.L), 106 zap.Error(err)) 107 } 108 e.splitRegions = len(regionIDs) 109 if e.splitRegions == 0 { 110 return nil 111 } 112 113 if !e.ctx.GetStochastikVars().WaitSplitRegionFinish { 114 return nil 115 } 116 e.finishScatterNum = waitScatterRegionFinish(ctxWithTimeout, e.ctx, start, s, regionIDs, e.blockInfo.Name.L, e.indexInfo.Name.L) 117 return nil 118 } 119 120 func (e *SplitIndexRegionInterDirc) getSplitIdxKeys() ([][]byte, error) { 121 // Split index regions by user specified value lists. 122 if len(e.valueLists) > 0 { 123 return e.getSplitIdxKeysFromValueList() 124 } 125 126 return e.getSplitIdxKeysFromBound() 127 } 128 129 func (e *SplitIndexRegionInterDirc) getSplitIdxKeysFromValueList() (keys [][]byte, err error) { 130 pi := e.blockInfo.GetPartitionInfo() 131 if pi == nil { 132 keys = make([][]byte, 0, len(e.valueLists)+1) 133 return e.getSplitIdxPhysicalKeysFromValueList(e.blockInfo.ID, keys) 134 } 135 136 // Split for all causet partitions. 137 if len(e.partitionNames) == 0 { 138 keys = make([][]byte, 0, (len(e.valueLists)+1)*len(pi.Definitions)) 139 for _, p := range pi.Definitions { 140 keys, err = e.getSplitIdxPhysicalKeysFromValueList(p.ID, keys) 141 if err != nil { 142 return nil, err 143 } 144 } 145 return keys, nil 146 } 147 148 // Split for specified causet partitions. 149 keys = make([][]byte, 0, (len(e.valueLists)+1)*len(e.partitionNames)) 150 for _, name := range e.partitionNames { 151 pid, err := blocks.FindPartitionByName(e.blockInfo, name.L) 152 if err != nil { 153 return nil, err 154 } 155 keys, err = e.getSplitIdxPhysicalKeysFromValueList(pid, keys) 156 if err != nil { 157 return nil, err 158 } 159 } 160 return keys, nil 161 } 162 163 func (e *SplitIndexRegionInterDirc) getSplitIdxPhysicalKeysFromValueList(physicalID int64, keys [][]byte) ([][]byte, error) { 164 keys = e.getSplitIdxPhysicalStartAndOtherIdxKeys(physicalID, keys) 165 index := blocks.NewIndex(physicalID, e.blockInfo, e.indexInfo) 166 for _, v := range e.valueLists { 167 idxKey, _, err := index.GenIndexKey(e.ctx.GetStochastikVars().StmtCtx, v, ekv.IntHandle(math.MinInt64), nil) 168 if err != nil { 169 return nil, err 170 } 171 keys = append(keys, idxKey) 172 } 173 return keys, nil 174 } 175 176 func (e *SplitIndexRegionInterDirc) getSplitIdxPhysicalStartAndOtherIdxKeys(physicalID int64, keys [][]byte) [][]byte { 177 // 1. Split in the start key for the index if the index is not the first index. 178 // For the first index, splitting the start key can produce the region [tid, tid_i_1), which is useless. 179 if len(e.blockInfo.Indices) > 0 && e.blockInfo.Indices[0].ID != e.indexInfo.ID { 180 startKey := blockcodec.EncodeBlockIndexPrefix(physicalID, e.indexInfo.ID) 181 keys = append(keys, startKey) 182 } 183 184 // 2. Split in the end key. 185 endKey := blockcodec.EncodeBlockIndexPrefix(physicalID, e.indexInfo.ID+1) 186 keys = append(keys, endKey) 187 return keys 188 } 189 190 func (e *SplitIndexRegionInterDirc) getSplitIdxKeysFromBound() (keys [][]byte, err error) { 191 pi := e.blockInfo.GetPartitionInfo() 192 if pi == nil { 193 keys = make([][]byte, 0, e.num) 194 return e.getSplitIdxPhysicalKeysFromBound(e.blockInfo.ID, keys) 195 } 196 197 // Split for all causet partitions. 198 if len(e.partitionNames) == 0 { 199 keys = make([][]byte, 0, e.num*len(pi.Definitions)) 200 for _, p := range pi.Definitions { 201 keys, err = e.getSplitIdxPhysicalKeysFromBound(p.ID, keys) 202 if err != nil { 203 return nil, err 204 } 205 } 206 return keys, nil 207 } 208 209 // Split for specified causet partitions. 210 keys = make([][]byte, 0, e.num*len(e.partitionNames)) 211 for _, name := range e.partitionNames { 212 pid, err := blocks.FindPartitionByName(e.blockInfo, name.L) 213 if err != nil { 214 return nil, err 215 } 216 keys, err = e.getSplitIdxPhysicalKeysFromBound(pid, keys) 217 if err != nil { 218 return nil, err 219 } 220 } 221 return keys, nil 222 } 223 224 func (e *SplitIndexRegionInterDirc) getSplitIdxPhysicalKeysFromBound(physicalID int64, keys [][]byte) ([][]byte, error) { 225 keys = e.getSplitIdxPhysicalStartAndOtherIdxKeys(physicalID, keys) 226 index := blocks.NewIndex(physicalID, e.blockInfo, e.indexInfo) 227 // Split index regions by lower, upper value and calculate the step by (upper - lower)/num. 228 lowerIdxKey, _, err := index.GenIndexKey(e.ctx.GetStochastikVars().StmtCtx, e.lower, ekv.IntHandle(math.MinInt64), nil) 229 if err != nil { 230 return nil, err 231 } 232 // Use math.MinInt64 as handle_id for the upper index key to avoid affecting calculate split point. 233 // If use math.MaxInt64 here, test of `TestSplitIndex` will report error. 234 upperIdxKey, _, err := index.GenIndexKey(e.ctx.GetStochastikVars().StmtCtx, e.upper, ekv.IntHandle(math.MinInt64), nil) 235 if err != nil { 236 return nil, err 237 } 238 239 if bytes.Compare(lowerIdxKey, upperIdxKey) >= 0 { 240 lowerStr, err1 := datumSliceToString(e.lower) 241 upperStr, err2 := datumSliceToString(e.upper) 242 if err1 != nil || err2 != nil { 243 return nil, errors.Errorf("Split index `%v` region lower value %v should less than the upper value %v", e.indexInfo.Name, e.lower, e.upper) 244 } 245 return nil, errors.Errorf("Split index `%v` region lower value %v should less than the upper value %v", e.indexInfo.Name, lowerStr, upperStr) 246 } 247 return getValuesList(lowerIdxKey, upperIdxKey, e.num, keys), nil 248 } 249 250 // getValuesList is used to get `num` values between lower and upper value. 251 // To Simplify the explain, suppose lower and upper value type is int64, and lower=0, upper=100, num=10, 252 // then calculate the step=(upper-lower)/num=10, then the function should return 0+10, 10+10, 20+10... all together 9 (num-1) values. 253 // Then the function will return [10,20,30,40,50,60,70,80,90]. 254 // The difference is the value type of upper, lower is []byte, So I use getUint64FromBytes to convert []byte to uint64. 255 func getValuesList(lower, upper []byte, num int, valuesList [][]byte) [][]byte { 256 commonPrefixIdx := longestCommonPrefixLen(lower, upper) 257 step := getStepValue(lower[commonPrefixIdx:], upper[commonPrefixIdx:], num) 258 startV := getUint64FromBytes(lower[commonPrefixIdx:], 0) 259 // To get `num` regions, only need to split `num-1` idx keys. 260 buf := make([]byte, 8) 261 for i := 0; i < num-1; i++ { 262 value := make([]byte, 0, commonPrefixIdx+8) 263 value = append(value, lower[:commonPrefixIdx]...) 264 startV += step 265 binary.BigEndian.PutUint64(buf, startV) 266 value = append(value, buf...) 267 valuesList = append(valuesList, value) 268 } 269 return valuesList 270 } 271 272 // longestCommonPrefixLen gets the longest common prefix byte length. 273 func longestCommonPrefixLen(s1, s2 []byte) int { 274 l := mathutil.Min(len(s1), len(s2)) 275 i := 0 276 for ; i < l; i++ { 277 if s1[i] != s2[i] { 278 break 279 } 280 } 281 return i 282 } 283 284 // getStepValue gets the step of between the lower and upper value. step = (upper-lower)/num. 285 // Convert byte slice to uint64 first. 286 func getStepValue(lower, upper []byte, num int) uint64 { 287 lowerUint := getUint64FromBytes(lower, 0) 288 upperUint := getUint64FromBytes(upper, 0xff) 289 return (upperUint - lowerUint) / uint64(num) 290 } 291 292 // getUint64FromBytes gets a uint64 from the `bs` byte slice. 293 // If len(bs) < 8, then padding with `pad`. 294 func getUint64FromBytes(bs []byte, pad byte) uint64 { 295 buf := bs 296 if len(buf) < 8 { 297 buf = make([]byte, 0, 8) 298 buf = append(buf, bs...) 299 for i := len(buf); i < 8; i++ { 300 buf = append(buf, pad) 301 } 302 } 303 return binary.BigEndian.Uint64(buf) 304 } 305 306 func datumSliceToString(ds []types.Causet) (string, error) { 307 str := "(" 308 for i, d := range ds { 309 s, err := d.ToString() 310 if err != nil { 311 return str, err 312 } 313 if i > 0 { 314 str += "," 315 } 316 str += s 317 } 318 str += ")" 319 return str, nil 320 } 321 322 // SplitBlockRegionInterDirc represents a split causet regions interlock. 323 type SplitBlockRegionInterDirc struct { 324 baseInterlockingDirectorate 325 326 blockInfo *perceptron.BlockInfo 327 partitionNames []perceptron.CIStr 328 lower []types.Causet 329 upper []types.Causet 330 num int 331 handleDefCauss embedded.HandleDefCauss 332 valueLists [][]types.Causet 333 splitKeys [][]byte 334 335 done bool 336 splitRegionResult 337 } 338 339 // Open implements the InterlockingDirectorate Open interface. 340 func (e *SplitBlockRegionInterDirc) Open(ctx context.Context) (err error) { 341 e.splitKeys, err = e.getSplitBlockKeys() 342 return err 343 } 344 345 // Next implements the InterlockingDirectorate Next interface. 346 func (e *SplitBlockRegionInterDirc) Next(ctx context.Context, chk *chunk.Chunk) error { 347 chk.Reset() 348 if e.done { 349 return nil 350 } 351 e.done = true 352 353 if err := e.splitBlockRegion(ctx); err != nil { 354 return err 355 } 356 appendSplitRegionResultToChunk(chk, e.splitRegions, e.finishScatterNum) 357 return nil 358 } 359 360 func (e *SplitBlockRegionInterDirc) splitBlockRegion(ctx context.Context) error { 361 causetstore := e.ctx.GetStore() 362 s, ok := causetstore.(ekv.SplitblockStore) 363 if !ok { 364 return nil 365 } 366 367 start := time.Now() 368 ctxWithTimeout, cancel := context.WithTimeout(ctx, e.ctx.GetStochastikVars().GetSplitRegionTimeout()) 369 defer cancel() 370 371 regionIDs, err := s.SplitRegions(ctxWithTimeout, e.splitKeys, true, &e.blockInfo.ID) 372 if err != nil { 373 logutil.BgLogger().Warn("split causet region failed", 374 zap.String("causet", e.blockInfo.Name.L), 375 zap.Error(err)) 376 } 377 e.splitRegions = len(regionIDs) 378 if e.splitRegions == 0 { 379 return nil 380 } 381 382 if !e.ctx.GetStochastikVars().WaitSplitRegionFinish { 383 return nil 384 } 385 386 e.finishScatterNum = waitScatterRegionFinish(ctxWithTimeout, e.ctx, start, s, regionIDs, e.blockInfo.Name.L, "") 387 return nil 388 } 389 390 func waitScatterRegionFinish(ctxWithTimeout context.Context, sctx stochastikctx.Context, startTime time.Time, causetstore ekv.SplitblockStore, regionIDs []uint64, blockName, indexName string) int { 391 remainMillisecond := 0 392 finishScatterNum := 0 393 for _, regionID := range regionIDs { 394 if isCtxDone(ctxWithTimeout) { 395 // Do not break here for checking remain regions scatter finished with a very short backoff time. 396 // Consider this situation - Regions 1, 2, and 3 are to be split. 397 // Region 1 times out before scattering finishes, while Region 2 and Region 3 have finished scattering. 398 // In this case, we should return 2 Regions, instead of 0, have finished scattering. 399 remainMillisecond = checkScatterRegionFinishBackOff 400 } else { 401 remainMillisecond = int((sctx.GetStochastikVars().GetSplitRegionTimeout().Seconds() - time.Since(startTime).Seconds()) * 1000) 402 } 403 404 err := causetstore.WaitScatterRegionFinish(ctxWithTimeout, regionID, remainMillisecond) 405 if err == nil { 406 finishScatterNum++ 407 } else { 408 if len(indexName) == 0 { 409 logutil.BgLogger().Warn("wait scatter region failed", 410 zap.Uint64("regionID", regionID), 411 zap.String("causet", blockName), 412 zap.Error(err)) 413 } else { 414 logutil.BgLogger().Warn("wait scatter region failed", 415 zap.Uint64("regionID", regionID), 416 zap.String("causet", blockName), 417 zap.String("index", indexName), 418 zap.Error(err)) 419 } 420 } 421 } 422 return finishScatterNum 423 } 424 425 func appendSplitRegionResultToChunk(chk *chunk.Chunk, totalRegions, finishScatterNum int) { 426 chk.AppendInt64(0, int64(totalRegions)) 427 if finishScatterNum > 0 && totalRegions > 0 { 428 chk.AppendFloat64(1, float64(finishScatterNum)/float64(totalRegions)) 429 } else { 430 chk.AppendFloat64(1, float64(0)) 431 } 432 } 433 434 func isCtxDone(ctx context.Context) bool { 435 select { 436 case <-ctx.Done(): 437 return true 438 default: 439 return false 440 } 441 } 442 443 var minRegionStepValue = int64(1000) 444 445 func (e *SplitBlockRegionInterDirc) getSplitBlockKeys() ([][]byte, error) { 446 if len(e.valueLists) > 0 { 447 return e.getSplitBlockKeysFromValueList() 448 } 449 450 return e.getSplitBlockKeysFromBound() 451 } 452 453 func (e *SplitBlockRegionInterDirc) getSplitBlockKeysFromValueList() ([][]byte, error) { 454 var keys [][]byte 455 pi := e.blockInfo.GetPartitionInfo() 456 if pi == nil { 457 keys = make([][]byte, 0, len(e.valueLists)) 458 return e.getSplitBlockPhysicalKeysFromValueList(e.blockInfo.ID, keys) 459 } 460 461 // Split for all causet partitions. 462 if len(e.partitionNames) == 0 { 463 keys = make([][]byte, 0, len(e.valueLists)*len(pi.Definitions)) 464 for _, p := range pi.Definitions { 465 var err error 466 keys, err = e.getSplitBlockPhysicalKeysFromValueList(p.ID, keys) 467 if err != nil { 468 return nil, err 469 } 470 } 471 return keys, nil 472 } 473 474 // Split for specified causet partitions. 475 keys = make([][]byte, 0, len(e.valueLists)*len(e.partitionNames)) 476 for _, name := range e.partitionNames { 477 pid, err := blocks.FindPartitionByName(e.blockInfo, name.L) 478 if err != nil { 479 return nil, err 480 } 481 keys, err = e.getSplitBlockPhysicalKeysFromValueList(pid, keys) 482 if err != nil { 483 return nil, err 484 } 485 } 486 return keys, nil 487 } 488 489 func (e *SplitBlockRegionInterDirc) getSplitBlockPhysicalKeysFromValueList(physicalID int64, keys [][]byte) ([][]byte, error) { 490 recordPrefix := blockcodec.GenBlockRecordPrefix(physicalID) 491 for _, v := range e.valueLists { 492 handle, err := e.handleDefCauss.BuildHandleByCausets(v) 493 if err != nil { 494 return nil, err 495 } 496 key := blockcodec.EncodeRecordKey(recordPrefix, handle) 497 keys = append(keys, key) 498 } 499 return keys, nil 500 } 501 502 func (e *SplitBlockRegionInterDirc) getSplitBlockKeysFromBound() ([][]byte, error) { 503 var keys [][]byte 504 pi := e.blockInfo.GetPartitionInfo() 505 if pi == nil { 506 keys = make([][]byte, 0, e.num) 507 return e.getSplitBlockPhysicalKeysFromBound(e.blockInfo.ID, keys) 508 } 509 510 // Split for all causet partitions. 511 if len(e.partitionNames) == 0 { 512 keys = make([][]byte, 0, e.num*len(pi.Definitions)) 513 for _, p := range pi.Definitions { 514 var err error 515 keys, err = e.getSplitBlockPhysicalKeysFromBound(p.ID, keys) 516 if err != nil { 517 return nil, err 518 } 519 } 520 return keys, nil 521 } 522 523 // Split for specified causet partitions. 524 keys = make([][]byte, 0, e.num*len(e.partitionNames)) 525 for _, name := range e.partitionNames { 526 pid, err := blocks.FindPartitionByName(e.blockInfo, name.L) 527 if err != nil { 528 return nil, err 529 } 530 keys, err = e.getSplitBlockPhysicalKeysFromBound(pid, keys) 531 if err != nil { 532 return nil, err 533 } 534 } 535 return keys, nil 536 } 537 538 func (e *SplitBlockRegionInterDirc) calculateIntBoundValue() (lowerValue int64, step int64, err error) { 539 isUnsigned := false 540 if e.blockInfo.PKIsHandle { 541 if pkDefCaus := e.blockInfo.GetPkDefCausInfo(); pkDefCaus != nil { 542 isUnsigned = allegrosql.HasUnsignedFlag(pkDefCaus.Flag) 543 } 544 } 545 if isUnsigned { 546 lowerRecordID := e.lower[0].GetUint64() 547 upperRecordID := e.upper[0].GetUint64() 548 if upperRecordID <= lowerRecordID { 549 return 0, 0, errors.Errorf("Split causet `%s` region lower value %v should less than the upper value %v", e.blockInfo.Name, lowerRecordID, upperRecordID) 550 } 551 step = int64((upperRecordID - lowerRecordID) / uint64(e.num)) 552 lowerValue = int64(lowerRecordID) 553 } else { 554 lowerRecordID := e.lower[0].GetInt64() 555 upperRecordID := e.upper[0].GetInt64() 556 if upperRecordID <= lowerRecordID { 557 return 0, 0, errors.Errorf("Split causet `%s` region lower value %v should less than the upper value %v", e.blockInfo.Name, lowerRecordID, upperRecordID) 558 } 559 step = (upperRecordID - lowerRecordID) / int64(e.num) 560 lowerValue = lowerRecordID 561 } 562 if step < minRegionStepValue { 563 return 0, 0, errors.Errorf("Split causet `%s` region step value should more than %v, step %v is invalid", e.blockInfo.Name, minRegionStepValue, step) 564 } 565 return lowerValue, step, nil 566 } 567 568 func (e *SplitBlockRegionInterDirc) getSplitBlockPhysicalKeysFromBound(physicalID int64, keys [][]byte) ([][]byte, error) { 569 recordPrefix := blockcodec.GenBlockRecordPrefix(physicalID) 570 // Split a separate region for index. 571 containsIndex := len(e.blockInfo.Indices) > 0 && !(e.blockInfo.IsCommonHandle && len(e.blockInfo.Indices) == 1) 572 if containsIndex { 573 keys = append(keys, recordPrefix) 574 } 575 576 if e.handleDefCauss.IsInt() { 577 low, step, err := e.calculateIntBoundValue() 578 if err != nil { 579 return nil, err 580 } 581 recordID := low 582 for i := 1; i < e.num; i++ { 583 recordID += step 584 key := blockcodec.EncodeRecordKey(recordPrefix, ekv.IntHandle(recordID)) 585 keys = append(keys, key) 586 } 587 return keys, nil 588 } 589 lowerHandle, err := e.handleDefCauss.BuildHandleByCausets(e.lower) 590 if err != nil { 591 return nil, err 592 } 593 upperHandle, err := e.handleDefCauss.BuildHandleByCausets(e.upper) 594 if err != nil { 595 return nil, err 596 } 597 if lowerHandle.Compare(upperHandle) >= 0 { 598 lowerStr, err1 := datumSliceToString(e.lower) 599 upperStr, err2 := datumSliceToString(e.upper) 600 if err1 != nil || err2 != nil { 601 return nil, errors.Errorf("Split causet `%v` region lower value %v should less than the upper value %v", 602 e.blockInfo.Name.O, e.lower, e.upper) 603 } 604 return nil, errors.Errorf("Split causet `%v` region lower value %v should less than the upper value %v", 605 e.blockInfo.Name.O, lowerStr, upperStr) 606 } 607 low := blockcodec.EncodeRecordKey(recordPrefix, lowerHandle) 608 up := blockcodec.EncodeRecordKey(recordPrefix, upperHandle) 609 return getValuesList(low, up, e.num, keys), nil 610 } 611 612 // RegionMeta contains a region's peer detail 613 type regionMeta struct { 614 region *spacetimepb.Region 615 leaderID uint64 616 storeID uint64 // storeID is the causetstore ID of the leader region. 617 start string 618 end string 619 scattering bool 620 writtenBytes int64 621 readBytes int64 622 approximateSize int64 623 approximateKeys int64 624 } 625 626 func getPhysicalBlockRegions(physicalBlockID int64, blockInfo *perceptron.BlockInfo, einsteindbStore einsteindb.CausetStorage, s ekv.SplitblockStore, uniqueRegionMap map[uint64]struct{}) ([]regionMeta, error) { 627 if uniqueRegionMap == nil { 628 uniqueRegionMap = make(map[uint64]struct{}) 629 } 630 // for record 631 startKey, endKey := blockcodec.GetBlockHandleKeyRange(physicalBlockID) 632 regionCache := einsteindbStore.GetRegionCache() 633 recordRegionMetas, err := regionCache.LoadRegionsInKeyRange(einsteindb.NewBackofferWithVars(context.Background(), 20000, nil), startKey, endKey) 634 if err != nil { 635 return nil, err 636 } 637 recordPrefix := blockcodec.GenBlockRecordPrefix(physicalBlockID) 638 blockPrefix := blockcodec.GenBlockPrefix(physicalBlockID) 639 recordRegions, err := getRegionMeta(einsteindbStore, recordRegionMetas, uniqueRegionMap, blockPrefix, recordPrefix, nil, physicalBlockID, 0) 640 if err != nil { 641 return nil, err 642 } 643 644 regions := recordRegions 645 // for indices 646 for _, index := range blockInfo.Indices { 647 if index.State != perceptron.StatePublic { 648 continue 649 } 650 startKey, endKey := blockcodec.GetBlockIndexKeyRange(physicalBlockID, index.ID) 651 regionMetas, err := regionCache.LoadRegionsInKeyRange(einsteindb.NewBackofferWithVars(context.Background(), 20000, nil), startKey, endKey) 652 if err != nil { 653 return nil, err 654 } 655 indexPrefix := blockcodec.EncodeBlockIndexPrefix(physicalBlockID, index.ID) 656 indexRegions, err := getRegionMeta(einsteindbStore, regionMetas, uniqueRegionMap, blockPrefix, recordPrefix, indexPrefix, physicalBlockID, index.ID) 657 if err != nil { 658 return nil, err 659 } 660 regions = append(regions, indexRegions...) 661 } 662 err = checkRegionsStatus(s, regions) 663 if err != nil { 664 return nil, err 665 } 666 return regions, nil 667 } 668 669 func getPhysicalIndexRegions(physicalBlockID int64, indexInfo *perceptron.IndexInfo, einsteindbStore einsteindb.CausetStorage, s ekv.SplitblockStore, uniqueRegionMap map[uint64]struct{}) ([]regionMeta, error) { 670 if uniqueRegionMap == nil { 671 uniqueRegionMap = make(map[uint64]struct{}) 672 } 673 674 startKey, endKey := blockcodec.GetBlockIndexKeyRange(physicalBlockID, indexInfo.ID) 675 regionCache := einsteindbStore.GetRegionCache() 676 regions, err := regionCache.LoadRegionsInKeyRange(einsteindb.NewBackofferWithVars(context.Background(), 20000, nil), startKey, endKey) 677 if err != nil { 678 return nil, err 679 } 680 recordPrefix := blockcodec.GenBlockRecordPrefix(physicalBlockID) 681 blockPrefix := blockcodec.GenBlockPrefix(physicalBlockID) 682 indexPrefix := blockcodec.EncodeBlockIndexPrefix(physicalBlockID, indexInfo.ID) 683 indexRegions, err := getRegionMeta(einsteindbStore, regions, uniqueRegionMap, blockPrefix, recordPrefix, indexPrefix, physicalBlockID, indexInfo.ID) 684 if err != nil { 685 return nil, err 686 } 687 err = checkRegionsStatus(s, indexRegions) 688 if err != nil { 689 return nil, err 690 } 691 return indexRegions, nil 692 } 693 694 func checkRegionsStatus(causetstore ekv.SplitblockStore, regions []regionMeta) error { 695 for i := range regions { 696 scattering, err := causetstore.CheckRegionInScattering(regions[i].region.Id) 697 if err != nil { 698 return err 699 } 700 regions[i].scattering = scattering 701 } 702 return nil 703 } 704 705 func decodeRegionsKey(regions []regionMeta, blockPrefix, recordPrefix, indexPrefix []byte, physicalBlockID, indexID int64) { 706 d := ®ionKeyCausetDecoder{ 707 physicalBlockID: physicalBlockID, 708 blockPrefix: blockPrefix, 709 recordPrefix: recordPrefix, 710 indexPrefix: indexPrefix, 711 indexID: indexID, 712 } 713 for i := range regions { 714 regions[i].start = d.decodeRegionKey(regions[i].region.StartKey) 715 regions[i].end = d.decodeRegionKey(regions[i].region.EndKey) 716 } 717 } 718 719 type regionKeyCausetDecoder struct { 720 physicalBlockID int64 721 blockPrefix []byte 722 recordPrefix []byte 723 indexPrefix []byte 724 indexID int64 725 } 726 727 func (d *regionKeyCausetDecoder) decodeRegionKey(key []byte) string { 728 if len(d.indexPrefix) > 0 && bytes.HasPrefix(key, d.indexPrefix) { 729 return fmt.Sprintf("t_%d_i_%d_%x", d.physicalBlockID, d.indexID, key[len(d.indexPrefix):]) 730 } else if len(d.recordPrefix) > 0 && bytes.HasPrefix(key, d.recordPrefix) { 731 if len(d.recordPrefix) == len(key) { 732 return fmt.Sprintf("t_%d_r", d.physicalBlockID) 733 } 734 isIntHandle := len(key)-len(d.recordPrefix) == 8 735 if isIntHandle { 736 _, handle, err := codec.DecodeInt(key[len(d.recordPrefix):]) 737 if err == nil { 738 return fmt.Sprintf("t_%d_r_%d", d.physicalBlockID, handle) 739 } 740 } 741 return fmt.Sprintf("t_%d_r_%x", d.physicalBlockID, key[len(d.recordPrefix):]) 742 } 743 if len(d.blockPrefix) > 0 && bytes.HasPrefix(key, d.blockPrefix) { 744 key = key[len(d.blockPrefix):] 745 // Has index prefix. 746 if !bytes.HasPrefix(key, []byte("_i")) { 747 return fmt.Sprintf("t_%d_%x", d.physicalBlockID, key) 748 } 749 key = key[2:] 750 // try to decode index ID. 751 if _, indexID, err := codec.DecodeInt(key); err == nil { 752 return fmt.Sprintf("t_%d_i_%d_%x", d.physicalBlockID, indexID, key[8:]) 753 } 754 return fmt.Sprintf("t_%d_i__%x", d.physicalBlockID, key) 755 } 756 // Has causet prefix. 757 if bytes.HasPrefix(key, []byte("t")) { 758 key = key[1:] 759 // try to decode causet ID. 760 if _, blockID, err := codec.DecodeInt(key); err == nil { 761 return fmt.Sprintf("t_%d_%x", blockID, key[8:]) 762 } 763 return fmt.Sprintf("t_%x", key) 764 } 765 return fmt.Sprintf("%x", key) 766 } 767 768 func getRegionMeta(einsteindbStore einsteindb.CausetStorage, regionMetas []*einsteindb.Region, uniqueRegionMap map[uint64]struct{}, blockPrefix, recordPrefix, indexPrefix []byte, physicalBlockID, indexID int64) ([]regionMeta, error) { 769 regions := make([]regionMeta, 0, len(regionMetas)) 770 for _, r := range regionMetas { 771 if _, ok := uniqueRegionMap[r.GetID()]; ok { 772 continue 773 } 774 uniqueRegionMap[r.GetID()] = struct{}{} 775 regions = append(regions, regionMeta{ 776 region: r.GetMeta(), 777 leaderID: r.GetLeaderPeerID(), 778 storeID: r.GetLeaderStoreID(), 779 }) 780 } 781 regions, err := getRegionInfo(einsteindbStore, regions) 782 if err != nil { 783 return regions, err 784 } 785 decodeRegionsKey(regions, blockPrefix, recordPrefix, indexPrefix, physicalBlockID, indexID) 786 return regions, nil 787 } 788 789 func getRegionInfo(causetstore einsteindb.CausetStorage, regions []regionMeta) ([]regionMeta, error) { 790 // check fidel server exists. 791 etcd, ok := causetstore.(einsteindb.EtcdBackend) 792 if !ok { 793 return regions, nil 794 } 795 FIDelHosts, err := etcd.EtcdAddrs() 796 if err != nil { 797 return regions, err 798 } 799 if len(FIDelHosts) == 0 { 800 return regions, nil 801 } 802 einsteindbHelper := &helper.Helper{ 803 CausetStore: causetstore, 804 RegionCache: causetstore.GetRegionCache(), 805 } 806 for i := range regions { 807 regionInfo, err := einsteindbHelper.GetRegionInfoByID(regions[i].region.Id) 808 if err != nil { 809 return nil, err 810 } 811 regions[i].writtenBytes = regionInfo.WrittenBytes 812 regions[i].readBytes = regionInfo.ReadBytes 813 regions[i].approximateSize = regionInfo.ApproximateSize 814 regions[i].approximateKeys = regionInfo.ApproximateKeys 815 } 816 return regions, nil 817 }