github.com/matrixorigin/matrixone@v1.2.0/pkg/queryservice/query_service.go (about) 1 // Copyright 2021 - 2023 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package queryservice 16 17 import ( 18 "context" 19 "sync" 20 "time" 21 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/common/morpc" 24 pb "github.com/matrixorigin/matrixone/pkg/pb/query" 25 "github.com/matrixorigin/matrixone/pkg/queryservice/client" 26 "github.com/pkg/errors" 27 ) 28 29 // QueryService is used to send query request to another CN service. 30 type QueryService interface { 31 // ServiceID return the uuid of current CN service 32 ServiceID() string 33 // Start starts the service. 34 Start() error 35 // Close closes the service. 36 Close() error 37 // AddHandleFunc add message handler. 38 AddHandleFunc(method pb.CmdMethod, h func(context.Context, *pb.Request, *pb.Response) error, async bool) 39 // SetReleaseFunc sets the release handler. 40 SetReleaseFunc(resp *pb.Response, f func()) 41 } 42 43 // queryService is a query service started in CN service. 44 type queryService struct { 45 // serviceID is the UUID of CN service. 46 serviceID string 47 handler morpc.MessageHandler[*pb.Request, *pb.Response] 48 49 mu struct { 50 sync.Mutex 51 releaser map[*pb.Response]func() 52 } 53 } 54 55 // NewQueryService creates a new queryService instance. 56 func NewQueryService(serviceID string, address string, cfg morpc.Config) (QueryService, error) { 57 serviceName := "query-service" 58 qs := &queryService{ 59 serviceID: serviceID, 60 } 61 62 qs.mu.releaser = make(map[*pb.Response]func()) 63 64 pool := morpc.NewMessagePool( 65 func() *pb.Request { return &pb.Request{} }, 66 func() *pb.Response { return &pb.Response{} }) 67 68 h, err := morpc.NewMessageHandler(serviceName, address, cfg, pool, 69 morpc.WithHandlerRespReleaseFunc[*pb.Request, *pb.Response](func(m morpc.Message) { 70 resp := m.(*pb.Response) 71 if resp.CmdMethod == pb.CmdMethod_GetCacheData { 72 qs.mu.Lock() 73 defer qs.mu.Unlock() 74 release, ok := qs.mu.releaser[resp] 75 if ok { 76 release() 77 delete(qs.mu.releaser, resp) 78 } 79 } 80 pool.ReleaseResponse(resp) 81 }), 82 ) 83 if err != nil { 84 return nil, err 85 } 86 qs.handler = h 87 qs.initHandleFunc() 88 return qs, nil 89 } 90 91 // AddHandleFunc implements the QueryService interface. 92 func (s *queryService) AddHandleFunc(method pb.CmdMethod, h func(context.Context, *pb.Request, *pb.Response) error, async bool) { 93 s.handler.RegisterHandleFunc(uint32(method), h, async) 94 } 95 96 // SetReleaseFunc implements the QueryService interface. 97 func (s *queryService) SetReleaseFunc(resp *pb.Response, f func()) { 98 s.mu.Lock() 99 defer s.mu.Unlock() 100 s.mu.releaser[resp] = f 101 } 102 103 func (s *queryService) initHandleFunc() { 104 s.AddHandleFunc(pb.CmdMethod_GetProtocolVersion, handleGetProtocolVersion, false) 105 s.AddHandleFunc(pb.CmdMethod_SetProtocolVersion, handleSetProtocolVersion, false) 106 s.AddHandleFunc(pb.CmdMethod_CoreDumpConfig, handleCoreDumpConfig, false) 107 } 108 109 // Start implements the QueryService interface. 110 func (s *queryService) Start() error { 111 return s.handler.Start() 112 } 113 114 // Close implements the QueryService interface. 115 func (s *queryService) Close() error { 116 return s.handler.Close() 117 } 118 119 func (s *queryService) ServiceID() string { 120 return s.serviceID 121 } 122 123 type nodeResponse struct { 124 nodeAddr string //address of cn 125 response interface{} //response to the request 126 err error 127 } 128 129 // RequestMultipleCn sends the request to multiple cn and wait the responses. 130 // nodes : the address of the multiple cn 131 // qs : QueryService 132 // genRequest : generate the specific Request based on the business 133 // handleValidResponse : valid response handler 134 // handleInvalidResponse : invalid response handler 135 func RequestMultipleCn(ctx context.Context, 136 nodes []string, 137 qc client.QueryClient, 138 genRequest func() *pb.Request, 139 handleValidResponse func(string, *pb.Response), 140 handleInvalidResponse func(string), 141 ) error { 142 if genRequest == nil { 143 return moerr.NewInternalError(ctx, "invalid request generate function") 144 } 145 if handleValidResponse == nil { 146 return moerr.NewInternalError(ctx, "invalid response handle function") 147 } 148 nodesLeft := len(nodes) 149 responseChan := make(chan nodeResponse, nodesLeft) 150 151 ctx, cancel := context.WithTimeout(ctx, time.Second*5) 152 defer cancel() 153 var retErr error 154 155 for _, node := range nodes { 156 // Invalid node address, ignore it. 157 if len(node) == 0 { 158 nodesLeft-- 159 continue 160 } 161 162 go func(addr string) { 163 // gen request and send it 164 if genRequest != nil { 165 req := genRequest() 166 resp, err := qc.SendMessage(ctx, addr, req) 167 responseChan <- nodeResponse{nodeAddr: addr, response: resp, err: err} 168 } 169 }(node) 170 } 171 172 // Wait for all responses. 173 for nodesLeft > 0 { 174 select { 175 case res := <-responseChan: 176 if res.err != nil && retErr != nil { 177 retErr = errors.Wrapf(res.err, "failed to get result from %s", res.nodeAddr) 178 } else { 179 queryResp, ok := res.response.(*pb.Response) 180 if ok { 181 //save response 182 if handleValidResponse != nil { 183 handleValidResponse(res.nodeAddr, queryResp) 184 } 185 if queryResp != nil { 186 qc.Release(queryResp) 187 } 188 } else { 189 if handleInvalidResponse != nil { 190 handleInvalidResponse(res.nodeAddr) 191 } 192 } 193 } 194 case <-ctx.Done(): 195 retErr = moerr.NewInternalError(ctx, "context deadline exceeded") 196 } 197 nodesLeft-- 198 } 199 return retErr 200 }