github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/allegrosql.go (about) 1 backup// Copyright 2020 WHTCORPS 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 "context" 18 "unsafe" 19 20 "github.com/whtcorpsinc/errors" 21 "github.com/whtcorpsinc/fidelpb/go-fidelpb" 22 "github.com/whtcorpsinc/milevadb/ekv" 23 "github.com/whtcorpsinc/milevadb/metrics" 24 "github.com/whtcorpsinc/milevadb/statistics" 25 "github.com/whtcorpsinc/milevadb/stochastikctx" 26 "github.com/whtcorpsinc/milevadb/types" 27 "github.com/opentracing/opentracing-go" 28 ) 29 30 31 func Select(ctx context.Context, sctx stochastikctx.Context, ekvReq *ekv.Request, fieldTypes []*types.FieldType, fb *statistics.QueryFeedback) (SelectResult, error) { 32 if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { 33 span1 := span.Tracer().StartSpan("allegrosql.Select", opentracing.ChildOf(span.Context())) 34 defer span1.Finish() 35 ctx = opentracing.ContextWithSpan(ctx, span1) 36 } 37 38 // For testing purpose. 39 if hook := ctx.Value("CheckSelectRequestHook"); hook != nil { 40 hook.(func(*ekv.Request))(ekvReq) 41 } 42 43 if !sctx.GetStochastikVars().EnableStreaming { 44 ekvReq.Streaming = false 45 } 46 resp := sctx.GetClient().Send(ctx, ekvReq, sctx.GetStochastikVars().KVVars) 47 if resp == nil { 48 err := errors.New("client returns nil response") 49 return nil, err 50 } 51 52 label := metrics.LblGeneral 53 if sctx.GetStochastikVars().InRestrictedALLEGROSQL { 54 label = metrics.LblInternal 55 } 56 57 // ekvReq.MemTracker is used to trace and control memory usage in DistALLEGROSQL layer; 58 // for streamResult, since it is a pipeline which has no buffer, it's not necessary to trace it; 59 // for selectResult, we just use the ekvReq.MemTracker prepared for co-processor 60 // instead of creating a new one for simplification. 61 if ekvReq.Streaming { 62 return &streamResult{ 63 label: "posetPosetDag-stream", 64 sqlType: label, 65 resp: resp, 66 rowLen: len(fieldTypes), 67 fieldTypes: fieldTypes, 68 ctx: sctx, 69 feedback: fb, 70 }, nil 71 } 72 encodetype := fidelpb.EncodeType_TypeDefault 73 if canUseChunkRPC(sctx) { 74 encodetype = fidelpb.EncodeType_TypeChunk 75 } 76 return &selectResult{ 77 label: "posetPosetDag", 78 resp: resp, 79 rowLen: len(fieldTypes), 80 fieldTypes: fieldTypes, 81 ctx: sctx, 82 feedback: fb, 83 sqlType: label, 84 memTracker: ekvReq.MemTracker, 85 encodeType: encodetype, 86 }, nil 87 } 88 89 // SelectWithRuntimeStats sends a PosetDag request, returns SelectResult. 90 // The difference from Select is that SelectWithRuntimeStats will set copCausetIDs into selectResult, 91 // which can help selectResult to defCauslect runtime stats. 92 func SelectWithRuntimeStats(ctx context.Context, sctx stochastikctx.Context, ekvReq *ekv.Request, 93 fieldTypes []*types.FieldType, fb *statistics.QueryFeedback, copCausetIDs []int, rootCausetID int) (SelectResult, error) { 94 sr, err := Select(ctx, sctx, ekvReq, fieldTypes, fb) 95 if err == nil { 96 if selectResult, ok := sr.(*selectResult); ok { 97 selectResult.copCausetIDs = copCausetIDs 98 selectResult.rootCausetID = rootCausetID 99 } 100 } 101 return sr, err 102 } 103 104 // Analyze do a analyze request. 105 func Analyze(ctx context.Context, client ekv.Client, ekvReq *ekv.Request, vars *ekv.Variables, 106 isRestrict bool) (SelectResult, error) { 107 resp := client.Send(ctx, ekvReq, vars) 108 if resp == nil { 109 return nil, errors.New("client returns nil response") 110 } 111 label := metrics.LblGeneral 112 if isRestrict { 113 label = metrics.LblInternal 114 } 115 result := &selectResult{ 116 label: "analyze", 117 resp: resp, 118 feedback: statistics.NewQueryFeedback(0, nil, 0, false), 119 sqlType: label, 120 encodeType: fidelpb.EncodeType_TypeDefault, 121 } 122 return result, nil 123 } 124 125 // Checksum sends a checksum request. 126 func Checksum(ctx context.Context, client ekv.Client, ekvReq *ekv.Request, vars *ekv.Variables) (SelectResult, error) { 127 resp := client.Send(ctx, ekvReq, vars) 128 if resp == nil { 129 return nil, errors.New("client returns nil response") 130 } 131 result := &selectResult{ 132 label: "checksum", 133 resp: resp, 134 feedback: statistics.NewQueryFeedback(0, nil, 0, false), 135 sqlType: metrics.LblGeneral, 136 encodeType: fidelpb.EncodeType_TypeDefault, 137 } 138 return result, nil 139 } 140 141 // SetEncodeType sets the encoding method for the PosetDagRequest. The supported encoding 142 // methods are: 143 // 1. TypeChunk: the result is encoded using the Chunk format, refer soliton/chunk/chunk.go 144 // 2. TypeDefault: the result is encoded event by event 145 func SetEncodeType(ctx stochastikctx.Context, posetPosetDagReq *fidelpb.PosetDagRequest) { 146 if canUseChunkRPC(ctx) { 147 posetPosetDagReq.EncodeType = fidelpb.EncodeType_TypeChunk 148 setChunkMemoryLayout(posetPosetDagReq) 149 } else { 150 posetPosetDagReq.EncodeType = fidelpb.EncodeType_TypeDefault 151 } 152 } 153 154 func canUseChunkRPC(ctx stochastikctx.Context) bool { 155 if !ctx.GetStochastikVars().EnableChunkRPC { 156 return false 157 } 158 if ctx.GetStochastikVars().EnableStreaming { 159 return false 160 } 161 if !checkAlignment() { 162 return false 163 } 164 return true 165 } 166 167 var supportedAlignment = unsafe.Sizeof(types.MyDecimal{}) == 40 168 169 // checkAlignment checks the alignment in current system environment. 170 // The alignment is influenced by system, machine and Golang version. 171 // Using this function can guarantee the alignment is we want. 172 func checkAlignment() bool { 173 return supportedAlignment 174 } 175 176 var systemEndian fidelpb.Endian 177 178 // setChunkMemoryLayout sets the chunk memory layout for the PosetDagRequest. 179 func setChunkMemoryLayout(posetPosetDagReq *fidelpb.PosetDagRequest) { 180 posetPosetDagReq.ChunkMemoryLayout = &fidelpb.ChunkMemoryLayout{Endian: GetSystemEndian()} 181 } 182 183 // GetSystemEndian gets the system endian. 184 func GetSystemEndian() fidelpb.Endian { 185 return systemEndian 186 } 187 188 func init() { 189 i := 0x0100 190 ptr := unsafe.Pointer(&i) 191 if 0x01 == *(*byte)(ptr) { 192 systemEndian = fidelpb.Endian_BigEndian 193 } else { 194 systemEndian = fidelpb.Endian_LittleEndian 195 } 196 }