github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/request_builder.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 allegrosql
    15  
    16  import (
    17  	"math"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    20  	"github.com/whtcorpsinc/fidelpb/go-fidelpb"
    21  	"github.com/whtcorpsinc/milevadb/blockcodec"
    22  	"github.com/whtcorpsinc/milevadb/ekv"
    23  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    24  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    25  	"github.com/whtcorpsinc/milevadb/soliton/memory"
    26  	"github.com/whtcorpsinc/milevadb/soliton/ranger"
    27  	"github.com/whtcorpsinc/milevadb/statistics"
    28  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    29  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    30  	"github.com/whtcorpsinc/milevadb/types"
    31  )
    32  
    33  // RequestBuilder is used to build a "ekv.Request".
    34  // It is called before we issue a ekv request by "Select".
    35  type RequestBuilder struct {
    36  	ekv.Request
    37  	err error
    38  }
    39  
    40  // Build builds a "ekv.Request".
    41  func (builder *RequestBuilder) Build() (*ekv.Request, error) {
    42  	return &builder.Request, builder.err
    43  }
    44  
    45  // SetMemTracker sets a memTracker for this request.
    46  func (builder *RequestBuilder) SetMemTracker(tracker *memory.Tracker) *RequestBuilder {
    47  	builder.Request.MemTracker = tracker
    48  	return builder
    49  }
    50  
    51  // SetBlockRanges sets "KeyRanges" for "ekv.Request" by converting "blockRanges"
    52  // to "KeyRanges" firstly.
    53  func (builder *RequestBuilder) SetBlockRanges(tid int64, blockRanges []*ranger.Range, fb *statistics.QueryFeedback) *RequestBuilder {
    54  	if builder.err == nil {
    55  		builder.Request.KeyRanges = BlockRangesToKVRanges(tid, blockRanges, fb)
    56  	}
    57  	return builder
    58  }
    59  
    60  // SetIndexRanges sets "KeyRanges" for "ekv.Request" by converting index range
    61  // "ranges" to "KeyRanges" firstly.
    62  func (builder *RequestBuilder) SetIndexRanges(sc *stmtctx.StatementContext, tid, idxID int64, ranges []*ranger.Range) *RequestBuilder {
    63  	if builder.err == nil {
    64  		builder.Request.KeyRanges, builder.err = IndexRangesToKVRanges(sc, tid, idxID, ranges, nil)
    65  	}
    66  	return builder
    67  }
    68  
    69  // SetCommonHandleRanges sets "KeyRanges" for "ekv.Request" by converting common handle range
    70  // "ranges" to "KeyRanges" firstly.
    71  func (builder *RequestBuilder) SetCommonHandleRanges(sc *stmtctx.StatementContext, tid int64, ranges []*ranger.Range) *RequestBuilder {
    72  	if builder.err == nil {
    73  		builder.Request.KeyRanges, builder.err = CommonHandleRangesToKVRanges(sc, tid, ranges)
    74  	}
    75  	return builder
    76  }
    77  
    78  // SetBlockHandles sets "KeyRanges" for "ekv.Request" by converting causet handles
    79  // "handles" to "KeyRanges" firstly.
    80  func (builder *RequestBuilder) SetBlockHandles(tid int64, handles []ekv.Handle) *RequestBuilder {
    81  	builder.Request.KeyRanges = BlockHandlesToKVRanges(tid, handles)
    82  	return builder
    83  }
    84  
    85  const estimatedRegionRowCount = 100000
    86  
    87  // SetPosetDagRequest sets the request type to "ReqTypePosetDag" and construct request data.
    88  func (builder *RequestBuilder) SetPosetDagRequest(posetPosetDag *fidelpb.PosetDagRequest) *RequestBuilder {
    89  	if builder.err == nil {
    90  		builder.Request.Tp = ekv.ReqTypePosetDag
    91  		builder.Request.Cacheable = true
    92  		builder.Request.Data, builder.err = posetPosetDag.Marshal()
    93  	}
    94  	// When the PosetDag is just simple scan and small limit, set concurrency to 1 would be sufficient.
    95  	if len(posetPosetDag.InterlockingDirectorates) == 2 && posetPosetDag.InterlockingDirectorates[1].GetLimit() != nil {
    96  		limit := posetPosetDag.InterlockingDirectorates[1].GetLimit()
    97  		if limit != nil && limit.Limit < estimatedRegionRowCount {
    98  			builder.Request.Concurrency = 1
    99  		}
   100  	}
   101  	return builder
   102  }
   103  
   104  // SetAnalyzeRequest sets the request type to "ReqTypeAnalyze" and construct request data.
   105  func (builder *RequestBuilder) SetAnalyzeRequest(ana *fidelpb.AnalyzeReq) *RequestBuilder {
   106  	if builder.err == nil {
   107  		builder.Request.Tp = ekv.ReqTypeAnalyze
   108  		builder.Request.Data, builder.err = ana.Marshal()
   109  		builder.Request.NotFillCache = true
   110  		builder.Request.IsolationLevel = ekv.RC
   111  		builder.Request.Priority = ekv.PriorityLow
   112  	}
   113  
   114  	return builder
   115  }
   116  
   117  // SetChecksumRequest sets the request type to "ReqTypeChecksum" and construct request data.
   118  func (builder *RequestBuilder) SetChecksumRequest(checksum *fidelpb.ChecksumRequest) *RequestBuilder {
   119  	if builder.err == nil {
   120  		builder.Request.Tp = ekv.ReqTypeChecksum
   121  		builder.Request.Data, builder.err = checksum.Marshal()
   122  		builder.Request.NotFillCache = true
   123  	}
   124  
   125  	return builder
   126  }
   127  
   128  // SetKeyRanges sets "KeyRanges" for "ekv.Request".
   129  func (builder *RequestBuilder) SetKeyRanges(keyRanges []ekv.KeyRange) *RequestBuilder {
   130  	builder.Request.KeyRanges = keyRanges
   131  	return builder
   132  }
   133  
   134  // SetStartTS sets "StartTS" for "ekv.Request".
   135  func (builder *RequestBuilder) SetStartTS(startTS uint64) *RequestBuilder {
   136  	builder.Request.StartTs = startTS
   137  	return builder
   138  }
   139  
   140  // SetDesc sets "Desc" for "ekv.Request".
   141  func (builder *RequestBuilder) SetDesc(desc bool) *RequestBuilder {
   142  	builder.Request.Desc = desc
   143  	return builder
   144  }
   145  
   146  // SetKeepOrder sets "KeepOrder" for "ekv.Request".
   147  func (builder *RequestBuilder) SetKeepOrder(order bool) *RequestBuilder {
   148  	builder.Request.KeepOrder = order
   149  	return builder
   150  }
   151  
   152  // SetStoreType sets "StoreType" for "ekv.Request".
   153  func (builder *RequestBuilder) SetStoreType(storeType ekv.StoreType) *RequestBuilder {
   154  	builder.Request.StoreType = storeType
   155  	return builder
   156  }
   157  
   158  // SetAllowBatchCop sets `BatchCop` property.
   159  func (builder *RequestBuilder) SetAllowBatchCop(batchCop bool) *RequestBuilder {
   160  	builder.Request.BatchCop = batchCop
   161  	return builder
   162  }
   163  
   164  func (builder *RequestBuilder) getIsolationLevel() ekv.IsoLevel {
   165  	switch builder.Tp {
   166  	case ekv.ReqTypeAnalyze:
   167  		return ekv.RC
   168  	}
   169  	return ekv.SI
   170  }
   171  
   172  func (builder *RequestBuilder) getKVPriority(sv *variable.StochastikVars) int {
   173  	switch sv.StmtCtx.Priority {
   174  	case allegrosql.NoPriority, allegrosql.DelayedPriority:
   175  		return ekv.PriorityNormal
   176  	case allegrosql.LowPriority:
   177  		return ekv.PriorityLow
   178  	case allegrosql.HighPriority:
   179  		return ekv.PriorityHigh
   180  	}
   181  	return ekv.PriorityNormal
   182  }
   183  
   184  // SetFromStochastikVars sets the following fields for "ekv.Request" from stochastik variables:
   185  // "Concurrency", "IsolationLevel", "NotFillCache", "ReplicaRead", "SchemaVar".
   186  func (builder *RequestBuilder) SetFromStochastikVars(sv *variable.StochastikVars) *RequestBuilder {
   187  	if builder.Request.Concurrency == 0 {
   188  		// Concurrency may be set to 1 by SetPosetDagRequest
   189  		builder.Request.Concurrency = sv.DistALLEGROSQLScanConcurrency()
   190  	}
   191  	builder.Request.IsolationLevel = builder.getIsolationLevel()
   192  	builder.Request.NotFillCache = sv.StmtCtx.NotFillCache
   193  	builder.Request.TaskID = sv.StmtCtx.TaskID
   194  	builder.Request.Priority = builder.getKVPriority(sv)
   195  	builder.Request.ReplicaRead = sv.GetReplicaRead()
   196  	if sv.SnapshotschemaReplicant != nil {
   197  		builder.Request.SchemaVar = schemareplicant.GetSchemaReplicantByStochastikVars(sv).SchemaMetaVersion()
   198  	} else {
   199  		builder.Request.SchemaVar = sv.TxnCtx.SchemaVersion
   200  	}
   201  	return builder
   202  }
   203  
   204  // SetStreaming sets "Streaming" flag for "ekv.Request".
   205  func (builder *RequestBuilder) SetStreaming(streaming bool) *RequestBuilder {
   206  	builder.Request.Streaming = streaming
   207  	return builder
   208  }
   209  
   210  // SetConcurrency sets "Concurrency" for "ekv.Request".
   211  func (builder *RequestBuilder) SetConcurrency(concurrency int) *RequestBuilder {
   212  	builder.Request.Concurrency = concurrency
   213  	return builder
   214  }
   215  
   216  // BlockRangesToKVRanges converts causet ranges to "KeyRange".
   217  func BlockRangesToKVRanges(tid int64, ranges []*ranger.Range, fb *statistics.QueryFeedback) []ekv.KeyRange {
   218  	if fb == nil || fb.Hist == nil {
   219  		return blockRangesToKVRangesWithoutSplit(tid, ranges)
   220  	}
   221  	krs := make([]ekv.KeyRange, 0, len(ranges))
   222  	feedbackRanges := make([]*ranger.Range, 0, len(ranges))
   223  	for _, ran := range ranges {
   224  		low := codec.EncodeInt(nil, ran.LowVal[0].GetInt64())
   225  		high := codec.EncodeInt(nil, ran.HighVal[0].GetInt64())
   226  		if ran.LowExclude {
   227  			low = ekv.Key(low).PrefixNext()
   228  		}
   229  		// If this range is split by histogram, then the high val will equal to one bucket's upper bound,
   230  		// since we need to guarantee each range falls inside the exactly one bucket, `PrefixNext` will make the
   231  		// high value greater than upper bound, so we causetstore the range here.
   232  		r := &ranger.Range{LowVal: []types.Causet{types.NewBytesCauset(low)},
   233  			HighVal: []types.Causet{types.NewBytesCauset(high)}}
   234  		feedbackRanges = append(feedbackRanges, r)
   235  
   236  		if !ran.HighExclude {
   237  			high = ekv.Key(high).PrefixNext()
   238  		}
   239  		startKey := blockcodec.EncodeRowKey(tid, low)
   240  		endKey := blockcodec.EncodeRowKey(tid, high)
   241  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   242  	}
   243  	fb.StoreRanges(feedbackRanges)
   244  	return krs
   245  }
   246  
   247  func blockRangesToKVRangesWithoutSplit(tid int64, ranges []*ranger.Range) []ekv.KeyRange {
   248  	krs := make([]ekv.KeyRange, 0, len(ranges))
   249  	for _, ran := range ranges {
   250  		low, high := encodeHandleKey(ran)
   251  		startKey := blockcodec.EncodeRowKey(tid, low)
   252  		endKey := blockcodec.EncodeRowKey(tid, high)
   253  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   254  	}
   255  	return krs
   256  }
   257  
   258  func encodeHandleKey(ran *ranger.Range) ([]byte, []byte) {
   259  	low := codec.EncodeInt(nil, ran.LowVal[0].GetInt64())
   260  	high := codec.EncodeInt(nil, ran.HighVal[0].GetInt64())
   261  	if ran.LowExclude {
   262  		low = ekv.Key(low).PrefixNext()
   263  	}
   264  	if !ran.HighExclude {
   265  		high = ekv.Key(high).PrefixNext()
   266  	}
   267  	return low, high
   268  }
   269  
   270  // BlockHandlesToKVRanges converts sorted handle to ekv ranges.
   271  // For continuous handles, we should merge them to a single key range.
   272  func BlockHandlesToKVRanges(tid int64, handles []ekv.Handle) []ekv.KeyRange {
   273  	krs := make([]ekv.KeyRange, 0, len(handles))
   274  	i := 0
   275  	for i < len(handles) {
   276  		if commonHandle, ok := handles[i].(*ekv.CommonHandle); ok {
   277  			ran := ekv.KeyRange{
   278  				StartKey: blockcodec.EncodeRowKey(tid, commonHandle.Encoded()),
   279  				EndKey:   blockcodec.EncodeRowKey(tid, ekv.Key(commonHandle.Encoded()).Next()),
   280  			}
   281  			krs = append(krs, ran)
   282  			i++
   283  			continue
   284  		}
   285  		j := i + 1
   286  		for ; j < len(handles) && handles[j-1].IntValue() != math.MaxInt64; j++ {
   287  			if handles[j].IntValue() != handles[j-1].IntValue()+1 {
   288  				break
   289  			}
   290  		}
   291  		low := codec.EncodeInt(nil, handles[i].IntValue())
   292  		high := codec.EncodeInt(nil, handles[j-1].IntValue())
   293  		high = ekv.Key(high).PrefixNext()
   294  		startKey := blockcodec.EncodeRowKey(tid, low)
   295  		endKey := blockcodec.EncodeRowKey(tid, high)
   296  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   297  		i = j
   298  	}
   299  	return krs
   300  }
   301  
   302  // IndexRangesToKVRanges converts index ranges to "KeyRange".
   303  func IndexRangesToKVRanges(sc *stmtctx.StatementContext, tid, idxID int64, ranges []*ranger.Range, fb *statistics.QueryFeedback) ([]ekv.KeyRange, error) {
   304  	if fb == nil || fb.Hist == nil {
   305  		return indexRangesToKVWithoutSplit(sc, tid, idxID, ranges)
   306  	}
   307  	feedbackRanges := make([]*ranger.Range, 0, len(ranges))
   308  	for _, ran := range ranges {
   309  		low, high, err := encodeIndexKey(sc, ran)
   310  		if err != nil {
   311  			return nil, err
   312  		}
   313  		feedbackRanges = append(feedbackRanges, &ranger.Range{LowVal: []types.Causet{types.NewBytesCauset(low)},
   314  			HighVal: []types.Causet{types.NewBytesCauset(high)}, LowExclude: false, HighExclude: true})
   315  	}
   316  	feedbackRanges, ok := fb.Hist.SplitRange(sc, feedbackRanges, true)
   317  	if !ok {
   318  		fb.Invalidate()
   319  	}
   320  	krs := make([]ekv.KeyRange, 0, len(feedbackRanges))
   321  	for _, ran := range feedbackRanges {
   322  		low, high := ran.LowVal[0].GetBytes(), ran.HighVal[0].GetBytes()
   323  		if ran.LowExclude {
   324  			low = ekv.Key(low).PrefixNext()
   325  		}
   326  		ran.LowVal[0].SetBytes(low)
   327  		// If this range is split by histogram, then the high val will equal to one bucket's upper bound,
   328  		// since we need to guarantee each range falls inside the exactly one bucket, `PrefixNext` will make the
   329  		// high value greater than upper bound, so we causetstore the high value here.
   330  		ran.HighVal[0].SetBytes(high)
   331  		if !ran.HighExclude {
   332  			high = ekv.Key(high).PrefixNext()
   333  		}
   334  		startKey := blockcodec.EncodeIndexSeekKey(tid, idxID, low)
   335  		endKey := blockcodec.EncodeIndexSeekKey(tid, idxID, high)
   336  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   337  	}
   338  	fb.StoreRanges(feedbackRanges)
   339  	return krs, nil
   340  }
   341  
   342  // CommonHandleRangesToKVRanges converts common handle ranges to "KeyRange".
   343  func CommonHandleRangesToKVRanges(sc *stmtctx.StatementContext, tid int64, ranges []*ranger.Range) ([]ekv.KeyRange, error) {
   344  	rans := make([]*ranger.Range, 0, len(ranges))
   345  	for _, ran := range ranges {
   346  		low, high, err := encodeIndexKey(sc, ran)
   347  		if err != nil {
   348  			return nil, err
   349  		}
   350  		rans = append(rans, &ranger.Range{LowVal: []types.Causet{types.NewBytesCauset(low)},
   351  			HighVal: []types.Causet{types.NewBytesCauset(high)}, LowExclude: false, HighExclude: true})
   352  	}
   353  	krs := make([]ekv.KeyRange, 0, len(rans))
   354  	for _, ran := range rans {
   355  		low, high := ran.LowVal[0].GetBytes(), ran.HighVal[0].GetBytes()
   356  		if ran.LowExclude {
   357  			low = ekv.Key(low).PrefixNext()
   358  		}
   359  		ran.LowVal[0].SetBytes(low)
   360  		startKey := blockcodec.EncodeRowKey(tid, low)
   361  		endKey := blockcodec.EncodeRowKey(tid, high)
   362  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   363  	}
   364  	return krs, nil
   365  }
   366  
   367  func indexRangesToKVWithoutSplit(sc *stmtctx.StatementContext, tid, idxID int64, ranges []*ranger.Range) ([]ekv.KeyRange, error) {
   368  	krs := make([]ekv.KeyRange, 0, len(ranges))
   369  	for _, ran := range ranges {
   370  		low, high, err := encodeIndexKey(sc, ran)
   371  		if err != nil {
   372  			return nil, err
   373  		}
   374  		startKey := blockcodec.EncodeIndexSeekKey(tid, idxID, low)
   375  		endKey := blockcodec.EncodeIndexSeekKey(tid, idxID, high)
   376  		krs = append(krs, ekv.KeyRange{StartKey: startKey, EndKey: endKey})
   377  	}
   378  	return krs, nil
   379  }
   380  
   381  func encodeIndexKey(sc *stmtctx.StatementContext, ran *ranger.Range) ([]byte, []byte, error) {
   382  	low, err := codec.EncodeKey(sc, nil, ran.LowVal...)
   383  	if err != nil {
   384  		return nil, nil, err
   385  	}
   386  	if ran.LowExclude {
   387  		low = ekv.Key(low).PrefixNext()
   388  	}
   389  	high, err := codec.EncodeKey(sc, nil, ran.HighVal...)
   390  	if err != nil {
   391  		return nil, nil, err
   392  	}
   393  
   394  	if !ran.HighExclude {
   395  		high = ekv.Key(high).PrefixNext()
   396  	}
   397  
   398  	var hasNull bool
   399  	for _, highVal := range ran.HighVal {
   400  		if highVal.IsNull() {
   401  			hasNull = true
   402  			break
   403  		}
   404  	}
   405  
   406  	if hasNull {
   407  		// Append 0 to make unique-key range [null, null] to be a scan rather than point-get.
   408  		high = ekv.Key(high).Next()
   409  	}
   410  	return low, high, nil
   411  }