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  }