github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/server.go (about)

     1  // Copyright 2021 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 frontend
    16  
    17  import (
    18  	"context"
    19  	"io"
    20  	"strings"
    21  	"sync/atomic"
    22  	"time"
    23  
    24  	"go.uber.org/zap"
    25  
    26  	"github.com/fagongzi/goetty/v2"
    27  
    28  	"github.com/matrixorigin/matrixone/pkg/config"
    29  	"github.com/matrixorigin/matrixone/pkg/defines"
    30  	"github.com/matrixorigin/matrixone/pkg/logutil"
    31  	"github.com/matrixorigin/matrixone/pkg/queryservice"
    32  )
    33  
    34  // RelationName counter for the new connection
    35  var initConnectionID uint32 = 1000
    36  
    37  // ConnIDAllocKey is used get connection ID from HAKeeper.
    38  var ConnIDAllocKey = "____server_conn_id"
    39  
    40  // MOServer MatrixOne Server
    41  type MOServer struct {
    42  	addr        string
    43  	uaddr       string
    44  	app         goetty.NetApplication
    45  	rm          *RoutineManager
    46  	readTimeout time.Duration
    47  }
    48  
    49  // BaseService is an interface which indicates that the instance is
    50  // the base CN service and should implements the following methods.
    51  type BaseService interface {
    52  	// ID returns the ID of the service.
    53  	ID() string
    54  	// SQLAddress returns the SQL listen address of the service.
    55  	SQLAddress() string
    56  	// SessionMgr returns the session manager instance of the service.
    57  	SessionMgr() *queryservice.SessionManager
    58  	// CheckTenantUpgrade used to upgrade tenant metadata if the tenant is old version.
    59  	CheckTenantUpgrade(ctx context.Context, tenantID int64) error
    60  	// GetFinalVersion Get mo final version, which is based on the current code
    61  	GetFinalVersion() string
    62  	// UpgradeTenant used to upgrade tenant
    63  	UpgradeTenant(ctx context.Context, tenantName string, retryCount uint32, isALLAccount bool) error
    64  }
    65  
    66  func (mo *MOServer) GetRoutineManager() *RoutineManager {
    67  	return mo.rm
    68  }
    69  
    70  func (mo *MOServer) Start() error {
    71  	logutil.Infof("Server Listening on : %s ", mo.addr)
    72  	return mo.app.Start()
    73  }
    74  
    75  func (mo *MOServer) Stop() error {
    76  	return mo.app.Stop()
    77  }
    78  
    79  func nextConnectionID() uint32 {
    80  	return atomic.AddUint32(&initConnectionID, 1)
    81  }
    82  
    83  var globalRtMgr atomic.Value
    84  var globalPu atomic.Value
    85  var globalAicm atomic.Value
    86  
    87  func setGlobalRtMgr(rtMgr *RoutineManager) {
    88  	globalRtMgr.Store(rtMgr)
    89  }
    90  
    91  func getGlobalRtMgr() *RoutineManager {
    92  	return globalRtMgr.Load().(*RoutineManager)
    93  }
    94  
    95  func setGlobalPu(pu *config.ParameterUnit) {
    96  	globalPu.Store(pu)
    97  }
    98  
    99  func getGlobalPu() *config.ParameterUnit {
   100  	return globalPu.Load().(*config.ParameterUnit)
   101  }
   102  
   103  func setGlobalAicm(aicm *defines.AutoIncrCacheManager) {
   104  	globalAicm.Store(aicm)
   105  }
   106  
   107  func getGlobalAic() *defines.AutoIncrCacheManager {
   108  	if globalAicm.Load() != nil {
   109  		return globalAicm.Load().(*defines.AutoIncrCacheManager)
   110  	}
   111  	return nil
   112  }
   113  
   114  func NewMOServer(
   115  	ctx context.Context,
   116  	addr string,
   117  	pu *config.ParameterUnit,
   118  	aicm *defines.AutoIncrCacheManager,
   119  	baseService BaseService,
   120  ) *MOServer {
   121  	setGlobalPu(pu)
   122  	setGlobalAicm(aicm)
   123  	codec := NewSqlCodec()
   124  	rm, err := NewRoutineManager(ctx)
   125  	if err != nil {
   126  		logutil.Panicf("start server failed with %+v", err)
   127  	}
   128  	setGlobalRtMgr(rm)
   129  	rm.setBaseService(baseService)
   130  	if baseService != nil {
   131  		rm.setSessionMgr(baseService.SessionMgr())
   132  	}
   133  	// TODO asyncFlushBatch
   134  	addresses := []string{addr}
   135  	unixAddr := pu.SV.GetUnixSocketAddress()
   136  	if unixAddr != "" {
   137  		addresses = append(addresses, "unix://"+unixAddr)
   138  	}
   139  	mo := &MOServer{
   140  		addr:        addr,
   141  		uaddr:       pu.SV.UnixSocketAddress,
   142  		rm:          rm,
   143  		readTimeout: pu.SV.SessionTimeout.Duration,
   144  	}
   145  	app, err := goetty.NewApplicationWithListenAddress(
   146  		addresses,
   147  		rm.Handler,
   148  		goetty.WithAppLogger(logutil.GetGlobalLogger()),
   149  		goetty.WithAppHandleSessionFunc(mo.handleMessage),
   150  		goetty.WithAppSessionOptions(
   151  			goetty.WithSessionCodec(codec),
   152  			goetty.WithSessionLogger(logutil.GetGlobalLogger()),
   153  			goetty.WithSessionRWBUfferSize(DefaultRpcBufferSize, DefaultRpcBufferSize),
   154  			goetty.WithSessionAllocator(NewSessionAllocator(pu))),
   155  		goetty.WithAppSessionAware(rm),
   156  		//when the readTimeout expires the goetty will close the tcp connection.
   157  		goetty.WithReadTimeout(pu.SV.SessionTimeout.Duration))
   158  	if err != nil {
   159  		logutil.Panicf("start server failed with %+v", err)
   160  	}
   161  	err = initVarByConfig(ctx, pu)
   162  	if err != nil {
   163  		logutil.Panicf("start server failed with %+v", err)
   164  	}
   165  	mo.app = app
   166  	return mo
   167  }
   168  
   169  // handleMessage receives the message from the client and executes it
   170  func (mo *MOServer) handleMessage(rs goetty.IOSession) error {
   171  	received := uint64(0)
   172  	option := goetty.ReadOptions{Timeout: mo.readTimeout}
   173  	for {
   174  		msg, err := rs.Read(option)
   175  		if err != nil {
   176  			if err == io.EOF {
   177  				return nil
   178  			}
   179  
   180  			logutil.Error("session read failed",
   181  				zap.Error(err))
   182  			return err
   183  		}
   184  
   185  		received++
   186  
   187  		err = mo.rm.Handler(rs, msg, received)
   188  		if err != nil {
   189  			if skipClientQuit(err.Error()) {
   190  				return nil
   191  			} else {
   192  				logutil.Error("session handle failed, close this session", zap.Error(err))
   193  			}
   194  			return err
   195  		}
   196  	}
   197  }
   198  
   199  func initVarByConfig(ctx context.Context, pu *config.ParameterUnit) error {
   200  	var err error
   201  	if strings.ToLower(pu.SV.SaveQueryResult) == "on" {
   202  		err = GSysVariables.SetGlobalSysVar(ctx, "save_query_result", pu.SV.SaveQueryResult)
   203  		if err != nil {
   204  			return err
   205  		}
   206  	}
   207  
   208  	err = GSysVariables.SetGlobalSysVar(ctx, "query_result_maxsize", pu.SV.QueryResultMaxsize)
   209  	if err != nil {
   210  		return err
   211  	}
   212  
   213  	err = GSysVariables.SetGlobalSysVar(ctx, "query_result_timeout", pu.SV.QueryResultTimeout)
   214  	if err != nil {
   215  		return err
   216  	}
   217  
   218  	err = GSysVariables.SetGlobalSysVar(ctx, "lower_case_table_names", pu.SV.LowerCaseTableNames)
   219  	if err != nil {
   220  		return err
   221  	}
   222  	return err
   223  }