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 }