github.com/XiaoMi/Gaea@v1.2.5/proxy/server/server.go (about)

     1  // Copyright 2019 The Gaea Authors. All Rights Reserved.
     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 server
    16  
    17  import (
    18  	"net"
    19  	"runtime"
    20  	"strconv"
    21  	"time"
    22  
    23  	"fmt"
    24  
    25  	"github.com/XiaoMi/Gaea/log"
    26  	"github.com/XiaoMi/Gaea/models"
    27  	"github.com/XiaoMi/Gaea/mysql"
    28  	"github.com/XiaoMi/Gaea/util"
    29  	"github.com/XiaoMi/Gaea/util/sync2"
    30  )
    31  
    32  var (
    33  	timeWheelUnit       = time.Second * 1
    34  	timeWheelBucketsNum = 3600
    35  )
    36  
    37  // Server means proxy that serve client request
    38  type Server struct {
    39  	closed         sync2.AtomicBool
    40  	listener       net.Listener
    41  	sessionTimeout time.Duration
    42  	tw             *util.TimeWheel
    43  	adminServer    *AdminServer
    44  	manager        *Manager
    45  	EncryptKey     string
    46  	ServerVersion  string
    47  	AuthPlugin     string
    48  }
    49  
    50  // NewServer create new server
    51  func NewServer(cfg *models.Proxy, manager *Manager) (*Server, error) {
    52  	var err error
    53  	s := new(Server)
    54  
    55  	// init key
    56  	s.EncryptKey = cfg.EncryptKey
    57  	s.manager = manager
    58  	s.ServerVersion = cfg.ServerVersion
    59  	s.AuthPlugin = cfg.AuthPlugin
    60  	if len(s.AuthPlugin) > 0 {
    61  		DefaultCapability |= mysql.ClientPluginAuth
    62  	}
    63  
    64  	// if error occurs, recycle the resources during creation.
    65  	defer func() {
    66  		if e := recover(); e != nil {
    67  			err = fmt.Errorf("NewServer panic: %v", e)
    68  		}
    69  
    70  		if err != nil {
    71  			s.Close()
    72  		}
    73  	}()
    74  
    75  	s.closed = sync2.NewAtomicBool(false)
    76  
    77  	s.listener, err = net.Listen(cfg.ProtoType, cfg.ProxyAddr)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	st := strconv.Itoa(cfg.SessionTimeout)
    83  	st = st + "s"
    84  	s.sessionTimeout, err = time.ParseDuration(st)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	s.tw, err = util.NewTimeWheel(timeWheelUnit, timeWheelBucketsNum)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	s.tw.Start()
    94  
    95  	// create AdminServer
    96  	adminServer, err := NewAdminServer(s, cfg)
    97  	if err != nil {
    98  		log.Fatal(fmt.Sprintf("NewAdminServer error, quit. error: %s", err.Error()))
    99  		return nil, err
   100  	}
   101  	s.adminServer = adminServer
   102  
   103  	log.Notice("server start succ, netProtoType: %s, addr: %s", cfg.ProtoType, cfg.ProxyAddr)
   104  	return s, nil
   105  }
   106  
   107  // Listener return proxy's listener
   108  func (s *Server) Listener() net.Listener {
   109  	return s.listener
   110  }
   111  
   112  func (s *Server) onConn(c net.Conn) {
   113  	cc := newSession(s, c) //新建一个conn
   114  	defer func() {
   115  		err := recover()
   116  		if err != nil {
   117  			const size = 4096
   118  			buf := make([]byte, size)
   119  			buf = buf[:runtime.Stack(buf, false)] //获得当前goroutine的stacktrace
   120  			log.Warn("[server] onConn panic error, remoteAddr: %s, stack: %s", c.RemoteAddr().String(), string(buf))
   121  		}
   122  
   123  		// close session finally
   124  		cc.Close()
   125  	}()
   126  
   127  	if err := cc.Handshake(); err != nil {
   128  		log.Warn("[server] onConn error: %s", err.Error())
   129  		if err != mysql.ErrBadConn {
   130  			cc.c.writeErrorPacket(err)
   131  		}
   132  		return
   133  	}
   134  
   135  	// must invoke after handshake
   136  	if allowConnect := cc.IsAllowConnect(); allowConnect == false {
   137  		err := mysql.NewError(mysql.ErrAccessDenied, "ip address access denied by gaea")
   138  		cc.c.writeErrorPacket(err)
   139  		return
   140  	}
   141  
   142  	// added into time wheel
   143  	s.tw.Add(s.sessionTimeout, cc, cc.Close)
   144  	log.Notice("Connected conn_id=%d, %s@%s (%s) namespace:%s capability: %d",
   145  		cc.c.ConnectionID,
   146  		cc.executor.user,
   147  		cc.executor.clientAddr,
   148  		cc.executor.db,
   149  		cc.executor.namespace,
   150  		cc.c.capability)
   151  	cc.Run()
   152  }
   153  
   154  // Run proxy run and serve client request
   155  func (s *Server) Run() error {
   156  	// start AdminServer first
   157  	go s.adminServer.Run()
   158  
   159  	// start Server
   160  	s.closed.Set(false)
   161  	for s.closed.Get() != true {
   162  		conn, err := s.listener.Accept()
   163  		if err != nil {
   164  			log.Warn("[server] listener accept error: %s", err.Error())
   165  			continue
   166  		}
   167  
   168  		go s.onConn(conn)
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  // Close close proxy server
   175  func (s *Server) Close() error {
   176  	if s.adminServer != nil {
   177  		s.adminServer.Close()
   178  	}
   179  
   180  	s.closed.Set(true)
   181  	if s.listener != nil {
   182  		err := s.listener.Close()
   183  		if err != nil {
   184  			return err
   185  		}
   186  	}
   187  
   188  	s.manager.Close()
   189  	return nil
   190  }
   191  
   192  // ReloadNamespacePrepare config change prepare phase
   193  func (s *Server) ReloadNamespacePrepare(name string, client models.Client) error {
   194  	// get namespace conf from etcd
   195  	log.Notice("prepare config of namespace: %s begin", name)
   196  	store := models.NewStore(client)
   197  	namespaceConfig, err := store.LoadNamespace(s.EncryptKey, name)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	if err = s.manager.ReloadNamespacePrepare(namespaceConfig); err != nil {
   203  		log.Warn("Manager ReloadNamespacePrepare error: %v", err)
   204  		return err
   205  	}
   206  
   207  	log.Notice("prepare config of namespace: %s end", name)
   208  	return nil
   209  }
   210  
   211  // ReloadNamespaceCommit config change commit phase
   212  // commit namespace does not need lock
   213  func (s *Server) ReloadNamespaceCommit(name string) error {
   214  	log.Notice("commit config of namespace: %s begin", name)
   215  
   216  	if err := s.manager.ReloadNamespaceCommit(name); err != nil {
   217  		log.Warn("Manager ReloadNamespaceCommit error: %v", err)
   218  		return err
   219  	}
   220  
   221  	log.Notice("commit config of namespace: %s end", name)
   222  	return nil
   223  }
   224  
   225  // DeleteNamespace delete namespace in namespace manager
   226  func (s *Server) DeleteNamespace(name string) error {
   227  	log.Notice("delete namespace begin: %s", name)
   228  
   229  	if err := s.manager.DeleteNamespace(name); err != nil {
   230  		log.Warn("Manager DeleteNamespace error: %v", err)
   231  		return err
   232  	}
   233  
   234  	log.Notice("delete namespace end: %s", name)
   235  	return nil
   236  }