github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/server/rpc_server.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 server
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  
    20  	"github.com/whtcorpsinc/ekvproto/pkg/diagnosticspb"
    21  	"github.com/whtcorpsinc/ekvproto/pkg/einsteindbpb"
    22  	"github.com/whtcorpsinc/ekvproto/pkg/interlock"
    23  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    24  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore/entangledstore"
    25  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore/mockeinsteindb"
    26  	"github.com/whtcorpsinc/milevadb/config"
    27  	"github.com/whtcorpsinc/milevadb/interlock"
    28  	"github.com/whtcorpsinc/milevadb/petri"
    29  	"github.com/whtcorpsinc/milevadb/privilege"
    30  	"github.com/whtcorpsinc/milevadb/privilege/privileges"
    31  	"github.com/whtcorpsinc/milevadb/soliton"
    32  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    33  	"github.com/whtcorpsinc/milevadb/soliton/memory"
    34  	"github.com/whtcorpsinc/milevadb/stochastik"
    35  	"github.com/whtcorpsinc/sysutil"
    36  	"go.uber.org/zap"
    37  	"google.golang.org/grpc"
    38  )
    39  
    40  // NewRPCServer creates a new rpc server.
    41  func NewRPCServer(config *config.Config, dom *petri.Petri, sm soliton.StochastikManager) *grpc.Server {
    42  	defer func() {
    43  		if v := recover(); v != nil {
    44  			logutil.BgLogger().Error("panic in MilevaDB RPC server", zap.Reflect("r", v),
    45  				zap.Stack("stack trace"))
    46  		}
    47  	}()
    48  
    49  	s := grpc.NewServer()
    50  	rpcSrv := &rpcServer{
    51  		DiagnosticsServer: sysutil.NewDiagnosticsServer(config.Log.File.Filename),
    52  		dom:               dom,
    53  		sm:                sm,
    54  	}
    55  	// For redirection the cop task.
    56  	mockeinsteindb.GRPCClientFactory = func() mockeinsteindb.Client {
    57  		return einsteindb.NewTestRPCClient(config.Security)
    58  	}
    59  	entangledstore.GRPCClientFactory = func() entangledstore.Client {
    60  		return einsteindb.NewTestRPCClient(config.Security)
    61  	}
    62  	diagnosticspb.RegisterDiagnosticsServer(s, rpcSrv)
    63  	einsteindbpb.RegisterEinsteinDBServer(s, rpcSrv)
    64  	return s
    65  }
    66  
    67  // rpcServer contains below 2 services:
    68  // 1. Diagnose service, it's used for ALLEGROALLEGROSQL diagnose.
    69  // 2. Coprocessor service, it reuse the EinsteinDBServer interface, but only support the Coprocessor interface now.
    70  // Coprocessor service will handle the cop task from other MilevaDB server. Currently, it's only use for read the cluster memory causet.
    71  type rpcServer struct {
    72  	*sysutil.DiagnosticsServer
    73  	einsteindbpb.EinsteinDBServer
    74  	dom *petri.Petri
    75  	sm  soliton.StochastikManager
    76  }
    77  
    78  // Coprocessor implements the EinsteinDBServer interface.
    79  func (s *rpcServer) Coprocessor(ctx context.Context, in *interlock.Request) (resp *interlock.Response, err error) {
    80  	resp = &interlock.Response{}
    81  	defer func() {
    82  		if v := recover(); v != nil {
    83  			logutil.BgLogger().Error("panic when RPC server handing interlock", zap.Reflect("r", v),
    84  				zap.Stack("stack trace"))
    85  			resp.OtherError = fmt.Sprintf("panic when RPC server handing interlock, stack:%v", v)
    86  		}
    87  	}()
    88  	resp = s.handleCopRequest(ctx, in)
    89  	return resp, nil
    90  }
    91  
    92  // CoprocessorStream implements the EinsteinDBServer interface.
    93  func (s *rpcServer) CoprocessorStream(in *interlock.Request, stream einsteindbpb.EinsteinDB_CoprocessorStreamServer) (err error) {
    94  	resp := &interlock.Response{}
    95  	defer func() {
    96  		if v := recover(); v != nil {
    97  			logutil.BgLogger().Error("panic when RPC server handing interlock stream", zap.Reflect("r", v),
    98  				zap.Stack("stack trace"))
    99  			resp.OtherError = fmt.Sprintf("panic when when RPC server handing interlock stream, stack:%v", v)
   100  			err = stream.Send(resp)
   101  			if err != nil {
   102  				logutil.BgLogger().Error("panic when RPC server handing interlock stream, send response to stream error", zap.Error(err))
   103  			}
   104  		}
   105  	}()
   106  
   107  	se, err := s.createStochastik()
   108  	if err != nil {
   109  		resp.OtherError = err.Error()
   110  		return stream.Send(resp)
   111  	}
   112  	defer se.Close()
   113  
   114  	h := interlock.NewCoprocessorPosetDagHandler(se)
   115  	return h.HandleStreamRequest(context.Background(), in, stream)
   116  }
   117  
   118  // BatchCommands implements the EinsteinDBServer interface.
   119  func (s *rpcServer) BatchCommands(ss einsteindbpb.EinsteinDB_BatchCommandsServer) error {
   120  	defer func() {
   121  		if v := recover(); v != nil {
   122  			logutil.BgLogger().Error("panic when RPC server handing batch commands", zap.Reflect("r", v),
   123  				zap.Stack("stack trace"))
   124  		}
   125  	}()
   126  	for {
   127  		reqs, err := ss.Recv()
   128  		if err != nil {
   129  			logutil.BgLogger().Error("RPC server batch commands receive fail", zap.Error(err))
   130  			return err
   131  		}
   132  
   133  		responses := make([]*einsteindbpb.BatchCommandsResponse_Response, 0, len(reqs.Requests))
   134  		for _, req := range reqs.Requests {
   135  			var response *einsteindbpb.BatchCommandsResponse_Response
   136  			switch request := req.Cmd.(type) {
   137  			case *einsteindbpb.BatchCommandsRequest_Request_Coprocessor:
   138  				cop := request.Coprocessor
   139  				resp, err := s.Coprocessor(context.Background(), cop)
   140  				if err != nil {
   141  					return err
   142  				}
   143  				response = &einsteindbpb.BatchCommandsResponse_Response{
   144  					Cmd: &einsteindbpb.BatchCommandsResponse_Response_Coprocessor{
   145  						Coprocessor: resp,
   146  					},
   147  				}
   148  			case *einsteindbpb.BatchCommandsRequest_Request_Empty:
   149  				response = &einsteindbpb.BatchCommandsResponse_Response{
   150  					Cmd: &einsteindbpb.BatchCommandsResponse_Response_Empty{
   151  						Empty: &einsteindbpb.BatchCommandsEmptyResponse{
   152  							TestId: request.Empty.TestId,
   153  						},
   154  					},
   155  				}
   156  			default:
   157  				logutil.BgLogger().Info("RPC server batch commands receive unknown request", zap.Any("req", request))
   158  				response = &einsteindbpb.BatchCommandsResponse_Response{
   159  					Cmd: &einsteindbpb.BatchCommandsResponse_Response_Empty{
   160  						Empty: &einsteindbpb.BatchCommandsEmptyResponse{},
   161  					},
   162  				}
   163  			}
   164  			responses = append(responses, response)
   165  		}
   166  
   167  		err = ss.Send(&einsteindbpb.BatchCommandsResponse{
   168  			Responses:  responses,
   169  			RequestIds: reqs.GetRequestIds(),
   170  		})
   171  		if err != nil {
   172  			logutil.BgLogger().Error("RPC server batch commands send fail", zap.Error(err))
   173  			return err
   174  		}
   175  	}
   176  }
   177  
   178  // handleCopRequest handles the cop posetPosetDag request.
   179  func (s *rpcServer) handleCopRequest(ctx context.Context, req *interlock.Request) *interlock.Response {
   180  	resp := &interlock.Response{}
   181  	se, err := s.createStochastik()
   182  	if err != nil {
   183  		resp.OtherError = err.Error()
   184  		return resp
   185  	}
   186  	defer se.Close()
   187  
   188  	h := interlock.NewCoprocessorPosetDagHandler(se)
   189  	return h.HandleRequest(ctx, req)
   190  }
   191  
   192  func (s *rpcServer) createStochastik() (stochastik.Stochastik, error) {
   193  	se, err := stochastik.CreateStochastikWithPetri(s.dom.CausetStore(), s.dom)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	do := petri.GetPetri(se)
   198  	is := do.SchemaReplicant()
   199  	pm := &privileges.UserPrivileges{
   200  		Handle: do.PrivilegeHandle(),
   201  	}
   202  	privilege.BindPrivilegeManager(se, pm)
   203  	se.GetStochastikVars().TxnCtx.SchemaReplicant = is
   204  	// This is for disable parallel hash agg.
   205  	// TODO: remove this.
   206  	se.GetStochastikVars().SetHashAggPartialConcurrency(1)
   207  	se.GetStochastikVars().SetHashAggFinalConcurrency(1)
   208  	se.GetStochastikVars().StmtCtx.MemTracker = memory.NewTracker(memory.LabelForCoprocessor, -1)
   209  	se.SetStochastikManager(s.sm)
   210  	return se, nil
   211  }