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 := &regionKeyCausetDecoder{
   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  }