github.com/matrixorigin/matrixone@v1.2.0/pkg/proxy/conn_manager.go (about) 1 // Copyright 2021 - 2023 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 proxy 16 17 import ( 18 "math" 19 "sync" 20 ) 21 22 // Tenant defines alias tenant name type of string. 23 type Tenant string 24 25 // EmptyTenant is an empty tenant. 26 var EmptyTenant Tenant = "" 27 28 // tunnelSet defines the tunnels map type. map is the container 29 // to contain all tunnels. It must be used within cnTunnels. 30 type tunnelSet map[*tunnel]struct{} 31 32 // add adds a new tunnel to tunnelSet. This method needs lock in connManager. 33 func (s tunnelSet) add(t *tunnel) { 34 if _, ok := s[t]; !ok { 35 s[t] = struct{}{} 36 } 37 } 38 39 // del deletes a tunnel from a tunnelSet. This method needs locked. 40 func (s tunnelSet) del(t *tunnel) { 41 delete(s, t) 42 } 43 44 // exists checks if the tunnel exist in tunnelSet. This method needs lock in connManager. 45 func (s tunnelSet) exists(t *tunnel) bool { 46 _, ok := s[t] 47 return ok 48 } 49 50 // count returns the number of tunnels in tunnelSet. This method needs lock in connManager. 51 func (s tunnelSet) count() int { 52 return len(s) 53 } 54 55 // countWithoutIntent returns the number of tunnels in tunnelSet whose transfer intent is false. 56 // This method needs lock in connManager. 57 func (s tunnelSet) countWithoutIntent() int { 58 var r int 59 for t := range s { 60 if !t.transferIntent.Load() { 61 r++ 62 } 63 } 64 return r 65 } 66 67 // cnTunnels defines the type of map cn-uuid => tunnelSet 68 type cnTunnels map[string]tunnelSet 69 70 // newCNTunnels creates new cnTunnels. 71 func newCNTunnels() cnTunnels { 72 return make(cnTunnels) 73 } 74 75 // add adds a new tunnel to the CN server. This method needs lock in connManager. 76 func (t cnTunnels) add(uuid string, tun *tunnel) { 77 if tun == nil { 78 return 79 } 80 if t[uuid] == nil { 81 t[uuid] = make(tunnelSet) 82 } 83 t[uuid].add(tun) 84 } 85 86 // add adds a new tunnel to the CN server. This method needs lock in connManager. 87 func (t cnTunnels) del(uuid string, tun *tunnel) { 88 if tun == nil { 89 return 90 } 91 tunnels, ok := t[uuid] 92 if !ok { 93 return 94 } 95 if tunnels.exists(tun) { 96 tunnels.del(tun) 97 } 98 } 99 100 // count returns number of all tunnels. This method needs lock in connManager. 101 func (t cnTunnels) count() int { 102 var r int 103 for _, ts := range t { 104 r += ts.count() 105 } 106 return r 107 } 108 109 // connInfo contains label info and CN tunnels. 110 type connInfo struct { 111 label labelInfo 112 cnTunnels cnTunnels 113 } 114 115 // newConnInfo creates a new connection info. 116 func newConnInfo(label labelInfo) *connInfo { 117 return &connInfo{ 118 label: label, 119 cnTunnels: newCNTunnels(), 120 } 121 } 122 123 // count returns the size of CN tunnels. This method needs lock in connManager. 124 func (ci *connInfo) count() int { 125 if ci == nil { 126 return 0 127 } 128 return ci.cnTunnels.count() 129 } 130 131 // connManager tracks the connections to backend CN servers. 132 type connManager struct { 133 sync.Mutex 134 // LabelHash => connInfo 135 // The hash is a hashed value from labelInfo. 136 conns map[LabelHash]*connInfo 137 138 // cn uuid => tunnels 139 // It is mainly used in CN server draining. 140 cnTunnels cnTunnels 141 142 // Map from connection ID to CN server. 143 connIDServers map[uint32]*CNServer 144 145 // transferredConnIDs keeps the connection IDs that are transferred. 146 // We don't remove these IDs when close connection. 147 transferredConnIDs map[uint32]struct{} 148 } 149 150 // newConnManager creates a new connManager. 151 func newConnManager() *connManager { 152 m := &connManager{ 153 conns: make(map[LabelHash]*connInfo), 154 connIDServers: make(map[uint32]*CNServer), 155 transferredConnIDs: make(map[uint32]struct{}), 156 cnTunnels: make(cnTunnels), 157 } 158 return m 159 } 160 161 // selectOne select the most suitable CN server according the connection count 162 // on each CN server. The least count CN server is returned. 163 func (m *connManager) selectOne(hash LabelHash, cns []*CNServer) *CNServer { 164 m.Lock() 165 defer m.Unlock() 166 167 var ret *CNServer 168 var minCount = math.MaxInt 169 for _, cn := range cns { 170 ci, ok := m.conns[hash] 171 // There are no connections yet on all CN servers of this tenant. 172 // Means that no CN server has been connected for this tenant. 173 // So return any of it. 174 if !ok { 175 return cn 176 } 177 tunnels, ok := ci.cnTunnels[cn.uuid] 178 // There are no connections on this CN server. 179 if !ok { 180 return cn 181 } 182 // Choose the CNServer that has the least connections on it. 183 if tunnels.count() < minCount { 184 ret = cn 185 minCount = tunnels.count() 186 } 187 } 188 return ret 189 } 190 191 // connect adds a new connection to connection manager. 192 func (m *connManager) connect(cn *CNServer, t *tunnel) { 193 m.Lock() 194 defer m.Unlock() 195 _, ok := m.conns[cn.hash] 196 if !ok { 197 m.conns[cn.hash] = newConnInfo(cn.reqLabel) 198 } 199 m.conns[cn.hash].cnTunnels.add(cn.uuid, t) 200 if _, ok := m.connIDServers[cn.connID]; ok { 201 // this connection is transferred to a new CN server. 202 m.transferredConnIDs[cn.connID] = struct{}{} 203 } else { 204 m.connIDServers[cn.connID] = cn 205 } 206 207 if _, ok := m.cnTunnels[cn.uuid]; !ok { 208 m.cnTunnels[cn.uuid] = make(tunnelSet) 209 } 210 m.cnTunnels[cn.uuid][t] = struct{}{} 211 } 212 213 // disconnect removes a connection from connection manager. 214 func (m *connManager) disconnect(cn *CNServer, t *tunnel) { 215 m.Lock() 216 defer m.Unlock() 217 ci, ok := m.conns[cn.hash] 218 if ok { 219 ci.cnTunnels.del(cn.uuid, t) 220 } 221 delete(m.cnTunnels[cn.uuid], t) 222 if _, ok := m.transferredConnIDs[cn.connID]; !ok { 223 delete(m.connIDServers, cn.connID) 224 } else { 225 delete(m.transferredConnIDs, cn.connID) 226 } 227 } 228 229 // count returns the total connection count. 230 func (m *connManager) count() int { 231 m.Lock() 232 defer m.Unlock() 233 var total int 234 for _, c := range m.conns { 235 total += c.count() 236 } 237 return total 238 } 239 240 // getTenants get all label hashes that have connections currently. 241 func (m *connManager) getLabelHashes() []LabelHash { 242 m.Lock() 243 defer m.Unlock() 244 hashes := make([]LabelHash, 0, len(m.conns)) 245 for h, ci := range m.conns { 246 if ci.count() > 0 { 247 hashes = append(hashes, h) 248 } 249 } 250 return hashes 251 } 252 253 // getCNTunnels get all CN tunnels belongs to this label. 254 func (m *connManager) getCNTunnels(hash LabelHash) cnTunnels { 255 m.Lock() 256 defer m.Unlock() 257 ci, ok := m.conns[hash] 258 if !ok { 259 return nil 260 } 261 return ci.cnTunnels 262 } 263 264 // getLabelInfo gets the label info in connManager. 265 func (m *connManager) getLabelInfo(hash LabelHash) labelInfo { 266 m.Lock() 267 defer m.Unlock() 268 ci, ok := m.conns[hash] 269 if !ok { 270 return labelInfo{} 271 } 272 return ci.label 273 } 274 275 // getCNServerByConnID returns a CN server which has the connection ID. 276 func (m *connManager) getCNServerByConnID(connID uint32) *CNServer { 277 m.Lock() 278 defer m.Unlock() 279 cn, ok := m.connIDServers[connID] 280 if ok { 281 return cn 282 } 283 return nil 284 } 285 286 func (m *connManager) getTunnelsByCNID(id string) []*tunnel { 287 m.Lock() 288 defer m.Unlock() 289 tunMap, ok := m.cnTunnels[id] 290 if !ok { 291 return nil 292 } 293 tuns := make([]*tunnel, 0, len(tunMap)) 294 for tun := range tunMap { 295 tuns = append(tuns, tun) 296 } 297 return tuns 298 }