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 }