github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/coprocessor.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 "context" 18 19 "github.com/gogo/protobuf/proto" 20 "github.com/whtcorpsinc/BerolinaSQL/auth" 21 "github.com/whtcorpsinc/ekvproto/pkg/einsteindbpb" 22 "github.com/whtcorpsinc/ekvproto/pkg/interlock" 23 "github.com/whtcorpsinc/errors" 24 "github.com/whtcorpsinc/fidelpb/go-fidelpb" 25 "github.com/whtcorpsinc/milevadb/causet/embedded" 26 "github.com/whtcorpsinc/milevadb/ekv" 27 "github.com/whtcorpsinc/milevadb/privilege" 28 "github.com/whtcorpsinc/milevadb/schemareplicant" 29 "github.com/whtcorpsinc/milevadb/soliton/chunk" 30 "github.com/whtcorpsinc/milevadb/soliton/codec" 31 "github.com/whtcorpsinc/milevadb/soliton/timeutil" 32 "github.com/whtcorpsinc/milevadb/stochastikctx" 33 "github.com/whtcorpsinc/milevadb/types" 34 ) 35 36 // CoprocessorPosetDagHandler uses to handle cop posetPosetDag request. 37 type CoprocessorPosetDagHandler struct { 38 sctx stochastikctx.Context 39 posetPosetDagReq *fidelpb.PosetDagRequest 40 } 41 42 // NewCoprocessorPosetDagHandler creates a new CoprocessorPosetDagHandler. 43 func NewCoprocessorPosetDagHandler(sctx stochastikctx.Context) *CoprocessorPosetDagHandler { 44 return &CoprocessorPosetDagHandler{ 45 sctx: sctx, 46 } 47 } 48 49 // HandleRequest handles the interlock request. 50 func (h *CoprocessorPosetDagHandler) HandleRequest(ctx context.Context, req *interlock.Request) *interlock.Response { 51 e, err := h.buildPosetDagInterlockingDirectorate(req) 52 if err != nil { 53 return h.buildErrorResponse(err) 54 } 55 56 err = e.Open(ctx) 57 if err != nil { 58 return h.buildErrorResponse(err) 59 } 60 61 chk := newFirstChunk(e) 62 tps := e.base().retFieldTypes 63 var totalChunks, partChunks []fidelpb.Chunk 64 for { 65 chk.Reset() 66 err = Next(ctx, e, chk) 67 if err != nil { 68 return h.buildErrorResponse(err) 69 } 70 if chk.NumEvents() == 0 { 71 break 72 } 73 partChunks, err = h.buildChunk(chk, tps) 74 if err != nil { 75 return h.buildErrorResponse(err) 76 } 77 totalChunks = append(totalChunks, partChunks...) 78 } 79 if err := e.Close(); err != nil { 80 return h.buildErrorResponse(err) 81 } 82 return h.buildUnaryResponse(totalChunks) 83 } 84 85 // HandleStreamRequest handles the interlock stream request. 86 func (h *CoprocessorPosetDagHandler) HandleStreamRequest(ctx context.Context, req *interlock.Request, stream einsteindbpb.EinsteinDB_CoprocessorStreamServer) error { 87 e, err := h.buildPosetDagInterlockingDirectorate(req) 88 if err != nil { 89 return stream.Send(h.buildErrorResponse(err)) 90 } 91 92 err = e.Open(ctx) 93 if err != nil { 94 return stream.Send(h.buildErrorResponse(err)) 95 } 96 97 chk := newFirstChunk(e) 98 tps := e.base().retFieldTypes 99 for { 100 chk.Reset() 101 if err = Next(ctx, e, chk); err != nil { 102 return stream.Send(h.buildErrorResponse(err)) 103 } 104 if chk.NumEvents() == 0 { 105 return h.buildResponseAndSendToStream(chk, tps, stream) 106 } 107 if err = h.buildResponseAndSendToStream(chk, tps, stream); err != nil { 108 return stream.Send(h.buildErrorResponse(err)) 109 } 110 } 111 } 112 113 func (h *CoprocessorPosetDagHandler) buildResponseAndSendToStream(chk *chunk.Chunk, tps []*types.FieldType, stream einsteindbpb.EinsteinDB_CoprocessorStreamServer) error { 114 chunks, err := h.buildChunk(chk, tps) 115 if err != nil { 116 return stream.Send(h.buildErrorResponse(err)) 117 } 118 119 for _, c := range chunks { 120 resp := h.buildStreamResponse(&c) 121 if err = stream.Send(resp); err != nil { 122 return err 123 } 124 } 125 return nil 126 } 127 128 func (h *CoprocessorPosetDagHandler) buildPosetDagInterlockingDirectorate(req *interlock.Request) (InterlockingDirectorate, error) { 129 if req.GetTp() != ekv.ReqTypePosetDag { 130 return nil, errors.Errorf("unsupported request type %d", req.GetTp()) 131 } 132 posetPosetDagReq := new(fidelpb.PosetDagRequest) 133 err := proto.Unmarshal(req.Data, posetPosetDagReq) 134 if err != nil { 135 return nil, errors.Trace(err) 136 } 137 138 if posetPosetDagReq.User != nil { 139 pm := privilege.GetPrivilegeManager(h.sctx) 140 if pm != nil { 141 h.sctx.GetStochastikVars().User = &auth.UserIdentity{ 142 Username: posetPosetDagReq.User.UserName, 143 Hostname: posetPosetDagReq.User.UserHost, 144 } 145 authName, authHost, success := pm.GetAuthWithoutVerification(posetPosetDagReq.User.UserName, posetPosetDagReq.User.UserHost) 146 if success { 147 h.sctx.GetStochastikVars().User.AuthUsername = authName 148 h.sctx.GetStochastikVars().User.AuthHostname = authHost 149 h.sctx.GetStochastikVars().ActiveRoles = pm.GetDefaultRoles(authName, authHost) 150 } 151 } 152 } 153 154 stmtCtx := h.sctx.GetStochastikVars().StmtCtx 155 stmtCtx.SetFlagsFromPBFlag(posetPosetDagReq.Flags) 156 stmtCtx.TimeZone, err = timeutil.ConstructTimeZone(posetPosetDagReq.TimeZoneName, int(posetPosetDagReq.TimeZoneOffset)) 157 h.sctx.GetStochastikVars().TimeZone = stmtCtx.TimeZone 158 if err != nil { 159 return nil, errors.Trace(err) 160 } 161 h.posetPosetDagReq = posetPosetDagReq 162 is := h.sctx.GetStochastikVars().TxnCtx.SchemaReplicant.(schemareplicant.SchemaReplicant) 163 // Build physical plan. 164 bp := embedded.NewPBCausetBuilder(h.sctx, is) 165 plan, err := bp.Build(posetPosetDagReq.InterlockingDirectorates) 166 if err != nil { 167 return nil, errors.Trace(err) 168 } 169 // Build interlock. 170 b := newInterlockingDirectorateBuilder(h.sctx, is) 171 return b.build(plan), nil 172 } 173 174 func (h *CoprocessorPosetDagHandler) buildChunk(chk *chunk.Chunk, tps []*types.FieldType) (chunks []fidelpb.Chunk, err error) { 175 switch h.posetPosetDagReq.EncodeType { 176 case fidelpb.EncodeType_TypeDefault: 177 chunks, err = h.encodeDefault(chk, tps) 178 case fidelpb.EncodeType_TypeChunk: 179 chunks, err = h.encodeChunk(chk, tps) 180 default: 181 return nil, errors.Errorf("unknown PosetDag encode type: %v", h.posetPosetDagReq.EncodeType) 182 } 183 return chunks, err 184 } 185 186 func (h *CoprocessorPosetDagHandler) buildUnaryResponse(chunks []fidelpb.Chunk) *interlock.Response { 187 selResp := fidelpb.SelectResponse{ 188 Chunks: chunks, 189 EncodeType: h.posetPosetDagReq.EncodeType, 190 } 191 if h.posetPosetDagReq.DefCauslectInterDircutionSummaries != nil && *h.posetPosetDagReq.DefCauslectInterDircutionSummaries { 192 execSummary := make([]*fidelpb.InterlockingDirectorateInterDircutionSummary, len(h.posetPosetDagReq.InterlockingDirectorates)) 193 for i := range execSummary { 194 // TODO: Add real interlock execution summary information. 195 execSummary[i] = &fidelpb.InterlockingDirectorateInterDircutionSummary{} 196 } 197 selResp.InterDircutionSummaries = execSummary 198 } 199 data, err := proto.Marshal(&selResp) 200 if err != nil { 201 return h.buildErrorResponse(err) 202 } 203 return &interlock.Response{ 204 Data: data, 205 } 206 } 207 208 func (h *CoprocessorPosetDagHandler) buildStreamResponse(chunk *fidelpb.Chunk) *interlock.Response { 209 data, err := chunk.Marshal() 210 if err != nil { 211 return h.buildErrorResponse(err) 212 } 213 streamResponse := fidelpb.StreamResponse{ 214 Data: data, 215 } 216 var resp = &interlock.Response{} 217 resp.Data, err = proto.Marshal(&streamResponse) 218 if err != nil { 219 resp.OtherError = err.Error() 220 } 221 return resp 222 } 223 224 func (h *CoprocessorPosetDagHandler) buildErrorResponse(err error) *interlock.Response { 225 return &interlock.Response{ 226 OtherError: err.Error(), 227 } 228 } 229 230 func (h *CoprocessorPosetDagHandler) encodeChunk(chk *chunk.Chunk, defCausTypes []*types.FieldType) ([]fidelpb.Chunk, error) { 231 defCausOrdinal := h.posetPosetDagReq.OutputOffsets 232 respDefCausTypes := make([]*types.FieldType, 0, len(defCausOrdinal)) 233 for _, ordinal := range defCausOrdinal { 234 respDefCausTypes = append(respDefCausTypes, defCausTypes[ordinal]) 235 } 236 causetCausetEncoder := chunk.NewCodec(respDefCausTypes) 237 cur := fidelpb.Chunk{} 238 cur.EventsData = append(cur.EventsData, causetCausetEncoder.Encode(chk)...) 239 return []fidelpb.Chunk{cur}, nil 240 } 241 242 func (h *CoprocessorPosetDagHandler) encodeDefault(chk *chunk.Chunk, tps []*types.FieldType) ([]fidelpb.Chunk, error) { 243 defCausOrdinal := h.posetPosetDagReq.OutputOffsets 244 stmtCtx := h.sctx.GetStochastikVars().StmtCtx 245 requestedEvent := make([]byte, 0) 246 chunks := []fidelpb.Chunk{} 247 for i := 0; i < chk.NumEvents(); i++ { 248 requestedEvent = requestedEvent[:0] 249 event := chk.GetEvent(i) 250 for _, ordinal := range defCausOrdinal { 251 data, err := codec.EncodeValue(stmtCtx, nil, event.GetCauset(int(ordinal), tps[ordinal])) 252 if err != nil { 253 return nil, err 254 } 255 requestedEvent = append(requestedEvent, data...) 256 } 257 chunks = h.appendEvent(chunks, requestedEvent, i) 258 } 259 return chunks, nil 260 } 261 262 const rowsPerChunk = 64 263 264 func (h *CoprocessorPosetDagHandler) appendEvent(chunks []fidelpb.Chunk, data []byte, rowCnt int) []fidelpb.Chunk { 265 if rowCnt%rowsPerChunk == 0 { 266 chunks = append(chunks, fidelpb.Chunk{}) 267 } 268 cur := &chunks[len(chunks)-1] 269 cur.EventsData = append(cur.EventsData, data...) 270 return chunks 271 }