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 }