github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/split_region.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 "context" 18 19 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 20 "github.com/whtcorpsinc/errors" 21 "github.com/whtcorpsinc/milevadb/blockcodec" 22 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 23 "github.com/whtcorpsinc/milevadb/ekv" 24 "github.com/whtcorpsinc/milevadb/soliton/logutil" 25 "github.com/whtcorpsinc/milevadb/stochastikctx" 26 "go.uber.org/zap" 27 ) 28 29 func splitPartitionBlockRegion(ctx stochastikctx.Context, causetstore ekv.SplitblockStore, tbInfo *perceptron.BlockInfo, pi *perceptron.PartitionInfo, scatter bool) { 30 // Max partition count is 4096, should we sample and just choose some of the partition to split? 31 regionIDs := make([]uint64, 0, len(pi.Definitions)) 32 ctxWithTimeout, cancel := context.WithTimeout(context.Background(), ctx.GetStochastikVars().GetSplitRegionTimeout()) 33 defer cancel() 34 if tbInfo.ShardRowIDBits > 0 && tbInfo.PreSplitRegions > 0 { 35 for _, def := range pi.Definitions { 36 regionIDs = append(regionIDs, preSplitPhysicalBlockByShardRowID(ctxWithTimeout, causetstore, tbInfo, def.ID, scatter)...) 37 } 38 } else { 39 for _, def := range pi.Definitions { 40 regionIDs = append(regionIDs, splitRecordRegion(ctxWithTimeout, causetstore, def.ID, scatter)) 41 } 42 } 43 if scatter { 44 waitScatterRegionFinish(ctxWithTimeout, causetstore, regionIDs...) 45 } 46 } 47 48 func splitBlockRegion(ctx stochastikctx.Context, causetstore ekv.SplitblockStore, tbInfo *perceptron.BlockInfo, scatter bool) { 49 ctxWithTimeout, cancel := context.WithTimeout(context.Background(), ctx.GetStochastikVars().GetSplitRegionTimeout()) 50 defer cancel() 51 var regionIDs []uint64 52 if tbInfo.ShardRowIDBits > 0 && tbInfo.PreSplitRegions > 0 { 53 regionIDs = preSplitPhysicalBlockByShardRowID(ctxWithTimeout, causetstore, tbInfo, tbInfo.ID, scatter) 54 } else { 55 regionIDs = append(regionIDs, splitRecordRegion(ctxWithTimeout, causetstore, tbInfo.ID, scatter)) 56 } 57 if scatter { 58 waitScatterRegionFinish(ctxWithTimeout, causetstore, regionIDs...) 59 } 60 } 61 62 func preSplitPhysicalBlockByShardRowID(ctx context.Context, causetstore ekv.SplitblockStore, tbInfo *perceptron.BlockInfo, physicalID int64, scatter bool) []uint64 { 63 // Example: 64 // ShardRowIDBits = 4 65 // PreSplitRegions = 2 66 // 67 // then will pre-split 2^2 = 4 regions. 68 // 69 // in this code: 70 // max = 1 << tblInfo.ShardRowIDBits = 16 71 // step := int64(1 << (tblInfo.ShardRowIDBits - tblInfo.PreSplitRegions)) = 1 << (4-2) = 4; 72 // 73 // then split regionID is below: 74 // 4 << 59 = 2305843009213693952 75 // 8 << 59 = 4611686018427387904 76 // 12 << 59 = 6917529027641081856 77 // 78 // The 4 pre-split regions range is below: 79 // 0 ~ 2305843009213693952 80 // 2305843009213693952 ~ 4611686018427387904 81 // 4611686018427387904 ~ 6917529027641081856 82 // 6917529027641081856 ~ 9223372036854775807 ( (1 << 63) - 1 ) 83 // 84 // And the max _milevadb_rowid is 9223372036854775807, it won't be negative number. 85 86 // Split causet region. 87 step := int64(1 << (tbInfo.ShardRowIDBits - tbInfo.PreSplitRegions)) 88 max := int64(1 << tbInfo.ShardRowIDBits) 89 splitBlockKeys := make([][]byte, 0, 1<<(tbInfo.PreSplitRegions)) 90 splitBlockKeys = append(splitBlockKeys, blockcodec.GenBlockPrefix(physicalID)) 91 for p := step; p < max; p += step { 92 recordID := p << (64 - tbInfo.ShardRowIDBits - 1) 93 recordPrefix := blockcodec.GenBlockRecordPrefix(physicalID) 94 key := blockcodec.EncodeRecordKey(recordPrefix, ekv.IntHandle(recordID)) 95 splitBlockKeys = append(splitBlockKeys, key) 96 } 97 var err error 98 regionIDs, err := causetstore.SplitRegions(ctx, splitBlockKeys, scatter, &tbInfo.ID) 99 if err != nil { 100 logutil.BgLogger().Warn("[dbs] pre split some causet regions failed", 101 zap.Stringer("causet", tbInfo.Name), zap.Int("successful region count", len(regionIDs)), zap.Error(err)) 102 } 103 regionIDs = append(regionIDs, splitIndexRegion(causetstore, tbInfo, scatter)...) 104 return regionIDs 105 } 106 107 func splitRecordRegion(ctx context.Context, causetstore ekv.SplitblockStore, blockID int64, scatter bool) uint64 { 108 blockStartKey := blockcodec.GenBlockPrefix(blockID) 109 regionIDs, err := causetstore.SplitRegions(ctx, [][]byte{blockStartKey}, scatter, &blockID) 110 if err != nil { 111 // It will be automatically split by EinsteinDB later. 112 logutil.BgLogger().Warn("[dbs] split causet region failed", zap.Error(err)) 113 } 114 if len(regionIDs) == 1 { 115 return regionIDs[0] 116 } 117 return 0 118 } 119 120 func splitIndexRegion(causetstore ekv.SplitblockStore, tblInfo *perceptron.BlockInfo, scatter bool) []uint64 { 121 splitKeys := make([][]byte, 0, len(tblInfo.Indices)) 122 for _, idx := range tblInfo.Indices { 123 indexPrefix := blockcodec.EncodeBlockIndexPrefix(tblInfo.ID, idx.ID) 124 splitKeys = append(splitKeys, indexPrefix) 125 } 126 regionIDs, err := causetstore.SplitRegions(context.Background(), splitKeys, scatter, &tblInfo.ID) 127 if err != nil { 128 logutil.BgLogger().Warn("[dbs] pre split some causet index regions failed", 129 zap.Stringer("causet", tblInfo.Name), zap.Int("successful region count", len(regionIDs)), zap.Error(err)) 130 } 131 return regionIDs 132 } 133 134 func waitScatterRegionFinish(ctx context.Context, causetstore ekv.SplitblockStore, regionIDs ...uint64) { 135 for _, regionID := range regionIDs { 136 err := causetstore.WaitScatterRegionFinish(ctx, regionID, 0) 137 if err != nil { 138 logutil.BgLogger().Warn("[dbs] wait scatter region failed", zap.Uint64("regionID", regionID), zap.Error(err)) 139 // We don't break for FIDelError because it may caused by ScatterRegion request failed. 140 if _, ok := errors.Cause(err).(*einsteindb.FIDelError); !ok { 141 break 142 } 143 } 144 } 145 }