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  }