github.com/matrixorigin/matrixone@v0.7.0/pkg/cnservice/server.go (about)

     1  // Copyright 2021 - 2022 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 cnservice
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sync"
    21  
    22  	"github.com/fagongzi/goetty/v2"
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  	"github.com/matrixorigin/matrixone/pkg/common/morpc"
    25  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    26  	"github.com/matrixorigin/matrixone/pkg/common/stopper"
    27  	"github.com/matrixorigin/matrixone/pkg/config"
    28  	"github.com/matrixorigin/matrixone/pkg/defines"
    29  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    30  	"github.com/matrixorigin/matrixone/pkg/frontend"
    31  	"github.com/matrixorigin/matrixone/pkg/logservice"
    32  	"github.com/matrixorigin/matrixone/pkg/logutil"
    33  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    34  	"github.com/matrixorigin/matrixone/pkg/pb/pipeline"
    35  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    36  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    37  	"github.com/matrixorigin/matrixone/pkg/txn/rpc"
    38  	"github.com/matrixorigin/matrixone/pkg/txn/storage/memorystorage"
    39  	"github.com/matrixorigin/matrixone/pkg/vm/engine"
    40  	"github.com/matrixorigin/matrixone/pkg/vm/engine/memoryengine"
    41  )
    42  
    43  func NewService(
    44  	cfg *Config,
    45  	ctx context.Context,
    46  	fileService fileservice.FileService,
    47  	options ...Option,
    48  ) (Service, error) {
    49  	if err := cfg.Validate(); err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	// get metadata fs
    54  	fs, err := fileservice.Get[fileservice.ReplaceableFileService](fileService, defines.LocalFileServiceName)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	srv := &service{
    60  		metadata: metadata.CNStore{
    61  			UUID: cfg.UUID,
    62  			Role: metadata.MustParseCNRole(cfg.Role),
    63  		},
    64  		cfg:         cfg,
    65  		metadataFS:  fs,
    66  		fileService: fileService,
    67  	}
    68  	for _, opt := range options {
    69  		opt(srv)
    70  	}
    71  	srv.logger = logutil.Adjust(srv.logger)
    72  	srv.stopper = stopper.NewStopper("cn-service", stopper.WithLogger(srv.logger))
    73  
    74  	if err := srv.initMetadata(); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	srv.responsePool = &sync.Pool{
    79  		New: func() any {
    80  			return &pipeline.Message{}
    81  		},
    82  	}
    83  
    84  	hakeeper, err := srv.getHAKeeperClient()
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	pu := config.NewParameterUnit(
    90  		&cfg.Frontend,
    91  		nil,
    92  		nil,
    93  		engine.Nodes{engine.Node{
    94  			Addr: cfg.ServiceAddress,
    95  		}},
    96  		memoryengine.GetClusterDetailsFromHAKeeper(ctx, hakeeper),
    97  	)
    98  	cfg.Frontend.SetDefaultValues()
    99  	cfg.Frontend.SetMaxMessageSize(uint64(cfg.RPC.MaxMessageSize))
   100  	frontend.InitServerVersion(pu.SV.MoVersion)
   101  	if err = srv.initMOServer(ctx, pu); err != nil {
   102  		return nil, err
   103  	}
   104  	srv.pu = pu
   105  
   106  	server, err := morpc.NewRPCServer("cn-server", cfg.ListenAddress,
   107  		morpc.NewMessageCodec(srv.acquireMessage,
   108  			morpc.WithCodecMaxBodySize(int(cfg.RPC.MaxMessageSize))),
   109  		morpc.WithServerLogger(srv.logger),
   110  		morpc.WithServerGoettyOptions(
   111  			goetty.WithSessionRWBUfferSize(cfg.ReadBufferSize, cfg.WriteBufferSize),
   112  			goetty.WithSessionReleaseMsgFunc(func(v any) {
   113  				m := v.(morpc.RPCMessage)
   114  				if !m.InternalMessage() {
   115  					srv.releaseMessage(m.Message.(*pipeline.Message))
   116  				}
   117  			}),
   118  		),
   119  		morpc.WithServerDisableAutoCancelContext())
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	server.RegisterRequestHandler(srv.handleRequest)
   124  	srv.server = server
   125  	srv.storeEngine = pu.StorageEngine
   126  	srv._txnClient = pu.TxnClient
   127  
   128  	srv.requestHandler = func(ctx context.Context, message morpc.Message, cs morpc.ClientSession, engine engine.Engine, fService fileservice.FileService, cli client.TxnClient, messageAcquirer func() morpc.Message, getClusterDetails engine.GetClusterDetailsFunc) error {
   129  		return nil
   130  	}
   131  	for _, opt := range options {
   132  		opt(srv)
   133  	}
   134  
   135  	return srv, nil
   136  }
   137  
   138  func (s *service) Start() error {
   139  	s.initTaskServiceHolder()
   140  
   141  	err := s.runMoServer()
   142  	if err != nil {
   143  		return err
   144  	}
   145  	if err := s.startCNStoreHeartbeat(); err != nil {
   146  		return err
   147  	}
   148  	return s.server.Start()
   149  }
   150  
   151  func (s *service) Close() error {
   152  	defer logutil.LogClose(s.logger, "cnservice")()
   153  
   154  	s.stopper.Stop()
   155  	if err := s.stopFrontend(); err != nil {
   156  		return err
   157  	}
   158  	if err := s.stopTask(); err != nil {
   159  		return err
   160  	}
   161  	if err := s.stopRPCs(); err != nil {
   162  		return err
   163  	}
   164  	return s.server.Close()
   165  }
   166  
   167  func (s *service) stopFrontend() error {
   168  	defer logutil.LogClose(s.logger, "cnservice/frontend")()
   169  
   170  	if err := s.serverShutdown(true); err != nil {
   171  		return err
   172  	}
   173  	s.cancelMoServerFunc()
   174  	return nil
   175  }
   176  
   177  func (s *service) stopRPCs() error {
   178  	if s._txnClient != nil {
   179  		if err := s._txnClient.Close(); err != nil {
   180  			return err
   181  		}
   182  	}
   183  	if s._hakeeperClient != nil {
   184  		if err := s._hakeeperClient.Close(); err != nil {
   185  			return err
   186  		}
   187  	}
   188  	if s._txnSender != nil {
   189  		if err := s._txnSender.Close(); err != nil {
   190  			return err
   191  		}
   192  	}
   193  	return nil
   194  }
   195  
   196  func (s *service) acquireMessage() morpc.Message {
   197  	return s.responsePool.Get().(*pipeline.Message)
   198  }
   199  
   200  func (s *service) releaseMessage(m *pipeline.Message) {
   201  	if s.responsePool != nil {
   202  		m.Sid = 0
   203  		m.Err = nil
   204  		m.Data = nil
   205  		m.ProcInfoData = nil
   206  		m.Analyse = nil
   207  		s.responsePool.Put(m)
   208  	}
   209  }
   210  
   211  func (s *service) handleRequest(ctx context.Context, req morpc.Message, _ uint64, cs morpc.ClientSession) error {
   212  	go s.requestHandler(ctx, req, cs, s.storeEngine, s.fileService, s._txnClient, s.acquireMessage, s.pu.GetClusterDetails)
   213  	return nil
   214  }
   215  
   216  func (s *service) initMOServer(ctx context.Context, pu *config.ParameterUnit) error {
   217  	var err error
   218  	logutil.Infof("Shutdown The Server With Ctrl+C | Ctrl+\\.")
   219  	cancelMoServerCtx, cancelMoServerFunc := context.WithCancel(ctx)
   220  	s.cancelMoServerFunc = cancelMoServerFunc
   221  
   222  	pu.FileService = s.fileService
   223  
   224  	logutil.Info("Initialize the engine ...")
   225  	err = s.initEngine(ctx, cancelMoServerCtx, pu)
   226  	if err != nil {
   227  		return err
   228  	}
   229  
   230  	s.createMOServer(cancelMoServerCtx, pu)
   231  
   232  	return nil
   233  }
   234  
   235  func (s *service) initEngine(
   236  	ctx context.Context,
   237  	cancelMoServerCtx context.Context,
   238  	pu *config.ParameterUnit,
   239  ) error {
   240  
   241  	switch s.cfg.Engine.Type {
   242  
   243  	case EngineTAE:
   244  		if err := initTAE(cancelMoServerCtx, pu, s.cfg); err != nil {
   245  			return err
   246  		}
   247  
   248  	case EngineDistributedTAE:
   249  		if err := s.initDistributedTAE(cancelMoServerCtx, pu); err != nil {
   250  			return err
   251  		}
   252  
   253  	case EngineMemory:
   254  		if err := s.initMemoryEngine(cancelMoServerCtx, pu); err != nil {
   255  			return err
   256  		}
   257  
   258  	case EngineNonDistributedMemory:
   259  		if err := s.initMemoryEngineNonDist(cancelMoServerCtx, pu); err != nil {
   260  			return err
   261  		}
   262  
   263  	default:
   264  		return moerr.NewInternalError(ctx, "unknown engine type: %s", s.cfg.Engine.Type)
   265  
   266  	}
   267  
   268  	return nil
   269  }
   270  
   271  func (s *service) createMOServer(inputCtx context.Context, pu *config.ParameterUnit) {
   272  	address := fmt.Sprintf("%s:%d", pu.SV.Host, pu.SV.Port)
   273  	moServerCtx := context.WithValue(inputCtx, config.ParameterUnitKey, pu)
   274  	s.mo = frontend.NewMOServer(moServerCtx, address, pu)
   275  }
   276  
   277  func (s *service) runMoServer() error {
   278  	return s.mo.Start()
   279  }
   280  
   281  func (s *service) serverShutdown(isgraceful bool) error {
   282  	return s.mo.Stop()
   283  }
   284  
   285  func (s *service) getHAKeeperClient() (client logservice.CNHAKeeperClient, err error) {
   286  	s.initHakeeperClientOnce.Do(func() {
   287  		ctx, cancel := context.WithTimeout(
   288  			context.Background(),
   289  			s.cfg.HAKeeper.DiscoveryTimeout.Duration,
   290  		)
   291  		defer cancel()
   292  		client, err = logservice.NewCNHAKeeperClient(ctx, s.cfg.HAKeeper.ClientConfig)
   293  		if err != nil {
   294  			return
   295  		}
   296  		s._hakeeperClient = client
   297  	})
   298  	client = s._hakeeperClient
   299  	return
   300  }
   301  
   302  func (s *service) getTxnSender() (sender rpc.TxnSender, err error) {
   303  	// handleTemp is used to manipulate memorystorage stored for temporary table created by sessions.
   304  	// processing of temporary table is currently on local, so we need to add a WithLocalDispatch logic to service.
   305  	handleTemp := func(d metadata.DNShard) rpc.TxnRequestHandleFunc {
   306  		if d.Address != defines.TEMPORARY_TABLE_DN_ADDR {
   307  			return nil
   308  		}
   309  
   310  		// read, write, commit and rollback for temporary tables
   311  		return func(ctx context.Context, req *txn.TxnRequest, resp *txn.TxnResponse) (err error) {
   312  			storage, ok := ctx.Value(defines.TemporaryDN{}).(*memorystorage.Storage)
   313  			if !ok {
   314  				panic("tempStorage should never be nil")
   315  			}
   316  
   317  			resp.RequestID = req.RequestID
   318  			resp.Txn = &req.Txn
   319  			resp.Method = req.Method
   320  			resp.Flag = req.Flag
   321  
   322  			switch req.Method {
   323  			case txn.TxnMethod_Read:
   324  				res, err := storage.Read(
   325  					ctx,
   326  					req.Txn,
   327  					req.CNRequest.OpCode,
   328  					req.CNRequest.Payload,
   329  				)
   330  				if err != nil {
   331  					resp.TxnError = txn.WrapError(err, moerr.ErrTAERead)
   332  				} else {
   333  					payload, err := res.Read()
   334  					if err != nil {
   335  						panic(err)
   336  					}
   337  					resp.CNOpResponse = &txn.CNOpResponse{Payload: payload}
   338  					res.Release()
   339  				}
   340  			case txn.TxnMethod_Write:
   341  				payload, err := storage.Write(
   342  					ctx,
   343  					req.Txn,
   344  					req.CNRequest.OpCode,
   345  					req.CNRequest.Payload,
   346  				)
   347  				if err != nil {
   348  					resp.TxnError = txn.WrapError(err, moerr.ErrTAEWrite)
   349  				} else {
   350  					resp.CNOpResponse = &txn.CNOpResponse{Payload: payload}
   351  				}
   352  			case txn.TxnMethod_Commit:
   353  				err = storage.Commit(ctx, req.Txn)
   354  				if err == nil {
   355  					resp.Txn.Status = txn.TxnStatus_Committed
   356  				}
   357  			case txn.TxnMethod_Rollback:
   358  				err = storage.Rollback(ctx, req.Txn)
   359  				if err == nil {
   360  					resp.Txn.Status = txn.TxnStatus_Aborted
   361  				}
   362  			default:
   363  				panic("should never happen")
   364  			}
   365  			return err
   366  		}
   367  	}
   368  
   369  	s.initTxnSenderOnce.Do(func() {
   370  		sender, err = rpc.NewSenderWithConfig(
   371  			s.cfg.RPC,
   372  			runtime.ProcessLevelRuntime(),
   373  			rpc.WithSenderLocalDispatch(handleTemp),
   374  		)
   375  		if err != nil {
   376  			return
   377  		}
   378  		s._txnSender = sender
   379  	})
   380  	sender = s._txnSender
   381  	return
   382  }
   383  
   384  func (s *service) getTxnClient() (c client.TxnClient, err error) {
   385  	s.initTxnClientOnce.Do(func() {
   386  		var sender rpc.TxnSender
   387  		sender, err = s.getTxnSender()
   388  		if err != nil {
   389  			return
   390  		}
   391  		c = client.NewTxnClient(runtime.ProcessLevelRuntime(), sender)
   392  		s._txnClient = c
   393  	})
   394  	c = s._txnClient
   395  	return
   396  }