github.com/matrixorigin/matrixone@v0.7.0/pkg/tests/service/network.go (about)

     1  // Copyright 2021 - 2022 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 service
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/RoaringBitmap/roaring"
    21  	"github.com/matrixorigin/matrixone/pkg/tests"
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  // serviceAddresses contains addresses of all services.
    27  type serviceAddresses struct {
    28  	t *testing.T
    29  
    30  	// Construct service addresses according to service number
    31  	logServiceNum int
    32  	dnServiceNum  int
    33  	cnServiceNum  int
    34  
    35  	logAddresses []logServiceAddress
    36  	dnAddresses  []dnServiceAddress
    37  	cnAddresses  []cnServiceAddress
    38  }
    39  
    40  // newServiceAddresses constructs addresses for all services.
    41  func newServiceAddresses(t *testing.T, logServiceNum, dnServiceNum, cnServiceNum int, hostAddr string) serviceAddresses {
    42  	address := serviceAddresses{
    43  		t:             t,
    44  		logServiceNum: logServiceNum,
    45  		dnServiceNum:  dnServiceNum,
    46  		cnServiceNum:  cnServiceNum,
    47  	}
    48  
    49  	// build log service addresses
    50  	logBatch := address.logServiceNum
    51  	logAddrs := make([]logServiceAddress, logBatch)
    52  	for i := 0; i < logBatch; i++ {
    53  		logAddr, err := newLogServiceAddress(hostAddr)
    54  		require.NoError(t, err)
    55  		logAddrs[i] = logAddr
    56  	}
    57  	address.logAddresses = logAddrs
    58  
    59  	// build dn service addresses
    60  	dnBatch := address.dnServiceNum
    61  	dnAddrs := make([]dnServiceAddress, dnBatch)
    62  	for i := 0; i < dnBatch; i++ {
    63  		dnAddr, err := newDNServiceAddress(hostAddr)
    64  		require.NoError(t, err)
    65  		dnAddrs[i] = dnAddr
    66  	}
    67  	address.dnAddresses = dnAddrs
    68  
    69  	cnBatch := address.cnServiceNum
    70  	cnAddrs := make([]cnServiceAddress, cnBatch)
    71  	for i := 0; i < cnBatch; i++ {
    72  		cnAddr, err := newCNServiceAddress(hostAddr)
    73  		require.NoError(t, err)
    74  		cnAddrs[i] = cnAddr
    75  	}
    76  	address.cnAddresses = cnAddrs
    77  
    78  	return address
    79  }
    80  
    81  // assertDNService asserts constructed address for dn service.
    82  func (a serviceAddresses) assertDNService() {
    83  	assert.Equal(a.t, a.dnServiceNum, len(a.dnAddresses))
    84  }
    85  
    86  // assertLogService asserts constructed address for log service.
    87  func (a serviceAddresses) assertLogService() {
    88  	assert.Equal(a.t, a.logServiceNum, len(a.logAddresses))
    89  }
    90  
    91  // assertCnService asserts constructed address for cn service.
    92  func (a serviceAddresses) assertCnService() {
    93  	assert.Equal(a.t, a.cnServiceNum, len(a.cnAddresses))
    94  }
    95  
    96  // getDnListenAddress gets dn listen address by its index.
    97  func (a serviceAddresses) getDnListenAddress(index int) string {
    98  	a.assertDNService()
    99  
   100  	if index >= len(a.dnAddresses) || index < 0 {
   101  		return ""
   102  	}
   103  	return a.dnAddresses[index].listenAddr
   104  }
   105  
   106  // getDnLogtailAddress gets logtail server address by its index.
   107  func (a serviceAddresses) getDnLogtailAddress(index int) string {
   108  	a.assertDNService()
   109  
   110  	if index >= len(a.dnAddresses) || index < 0 {
   111  		return ""
   112  	}
   113  	return a.dnAddresses[index].logtailAddr
   114  }
   115  
   116  // getLogListenAddress gets log service address by its index.
   117  func (a serviceAddresses) getLogListenAddress(index int) string {
   118  	a.assertLogService()
   119  
   120  	if index >= len(a.logAddresses) || index < 0 {
   121  		return ""
   122  	}
   123  	return a.logAddresses[index].listenAddr
   124  }
   125  
   126  func (a serviceAddresses) getCNListenAddress(index int) string {
   127  	a.assertCnService()
   128  
   129  	if index >= len(a.cnAddresses) || index < 0 {
   130  		return ""
   131  	}
   132  	return a.cnAddresses[index].listenAddr
   133  }
   134  
   135  // getLogRaftAddress gets log raft address by its index.
   136  func (a serviceAddresses) getLogRaftAddress(index int) string {
   137  	a.assertLogService()
   138  
   139  	if index >= len(a.logAddresses) || index < 0 {
   140  		return ""
   141  	}
   142  	return a.logAddresses[index].raftAddr
   143  }
   144  
   145  // getLogGossipAddress gets log gossip address by its index.
   146  func (a serviceAddresses) getLogGossipAddress(index int) string {
   147  	a.assertLogService()
   148  
   149  	if index >= len(a.logAddresses) || index < 0 {
   150  		return ""
   151  	}
   152  	return a.logAddresses[index].gossipAddr
   153  }
   154  
   155  // getLogGossipSeedAddresses gets all gossip seed addresses.
   156  //
   157  // Select gossip addresses of the first 3 log services.
   158  // If the number of log services was less than 3,
   159  // then select all of them.
   160  func (a serviceAddresses) getLogGossipSeedAddresses() []string {
   161  	a.assertLogService()
   162  
   163  	n := gossipSeedNum(len(a.logAddresses))
   164  	seedAddrs := make([]string, n)
   165  	for i := 0; i < n; i++ {
   166  		seedAddrs[i] = a.logAddresses[i].gossipAddr
   167  	}
   168  	return seedAddrs
   169  }
   170  
   171  // listHAKeeperListenAddresses gets addresses of all hakeeper servers.
   172  //
   173  // Select the first 3 log services to start hakeeper replica.
   174  // If the number of log services was less than 3,
   175  // then select the first of them.
   176  func (a serviceAddresses) listHAKeeperListenAddresses() []string {
   177  	a.assertLogService()
   178  
   179  	n := haKeeperNum(len(a.logAddresses))
   180  	listenAddrs := make([]string, n)
   181  	for i := 0; i < n; i++ {
   182  		listenAddrs[i] = a.logAddresses[i].listenAddr
   183  	}
   184  	return listenAddrs
   185  }
   186  
   187  // buildPartitionAddressSets returns service addresses by every partition.
   188  func (a serviceAddresses) buildPartitionAddressSets(partitions ...NetworkPartition) []addressSet {
   189  	sets := make([]addressSet, 0, len(partitions))
   190  	for _, part := range partitions {
   191  		sets = append(sets, a.listPartitionAddresses(part))
   192  	}
   193  	return sets
   194  }
   195  
   196  // listPartitionAddresses returns all service addresses within the same partition.
   197  func (a serviceAddresses) listPartitionAddresses(partition NetworkPartition) addressSet {
   198  	addrSet := newAddressSet()
   199  	for _, dnIndex := range partition.ListDNServiceIndex() {
   200  		addrs := a.listDnServiceAddresses(int(dnIndex))
   201  		addrSet.addAddresses(addrs...)
   202  	}
   203  	for _, logIndex := range partition.ListLogServiceIndex() {
   204  		addrs := a.listLogServiceAddresses(int(logIndex))
   205  		addrSet.addAddresses(addrs...)
   206  	}
   207  	for _, cnIndex := range partition.ListCNServiceIndex() {
   208  		addrs := a.listCnServiceAddresses(int(cnIndex))
   209  		addrSet.addAddresses(addrs...)
   210  	}
   211  	return addrSet
   212  }
   213  
   214  // listDnServiceAddresses lists all addresses of dn service by its index.
   215  func (a serviceAddresses) listDnServiceAddresses(index int) []string {
   216  	a.assertDNService()
   217  
   218  	if index >= len(a.dnAddresses) || index < 0 {
   219  		return nil
   220  	}
   221  	return a.dnAddresses[index].listAddresses()
   222  }
   223  
   224  // listLogServiceAddresses lists all addresses of log service by its index.
   225  func (a serviceAddresses) listLogServiceAddresses(index int) []string {
   226  	a.assertLogService()
   227  
   228  	if index >= len(a.logAddresses) || index < 0 {
   229  		return nil
   230  	}
   231  	return a.logAddresses[index].listAddresses()
   232  }
   233  
   234  // listCnServiceAddresses lists all addresses of log service by its index.
   235  func (a serviceAddresses) listCnServiceAddresses(index int) []string {
   236  	a.assertCnService()
   237  
   238  	if index >= len(a.cnAddresses) || index < 0 {
   239  		return nil
   240  	}
   241  	return a.cnAddresses[index].listAddresses()
   242  }
   243  
   244  // logServiceAddress contains addresses for log service.
   245  type logServiceAddress struct {
   246  	listenAddr string
   247  	raftAddr   string
   248  	gossipAddr string
   249  }
   250  
   251  func newLogServiceAddress(host string) (logServiceAddress, error) {
   252  	addrs, err := tests.GetAddressBatch(host, 3)
   253  	if err != nil {
   254  		return logServiceAddress{}, err
   255  	}
   256  
   257  	return logServiceAddress{
   258  		listenAddr: addrs[0],
   259  		raftAddr:   addrs[1],
   260  		gossipAddr: addrs[2],
   261  	}, nil
   262  }
   263  
   264  // listAddresses returns all addresses for single log service.
   265  func (la logServiceAddress) listAddresses() []string {
   266  	return []string{la.listenAddr, la.raftAddr, la.gossipAddr}
   267  }
   268  
   269  // dnServiceAddress contains address for dn service.
   270  type dnServiceAddress struct {
   271  	listenAddr  string
   272  	logtailAddr string
   273  }
   274  
   275  func newDNServiceAddress(host string) (dnServiceAddress, error) {
   276  	addrs, err := tests.GetAddressBatch(host, 2)
   277  	if err != nil {
   278  		return dnServiceAddress{}, err
   279  	}
   280  	return dnServiceAddress{
   281  		listenAddr:  addrs[0],
   282  		logtailAddr: addrs[1],
   283  	}, nil
   284  }
   285  
   286  // listAddresses returns all addresses for single dn service.
   287  func (da dnServiceAddress) listAddresses() []string {
   288  	return []string{da.listenAddr, da.logtailAddr}
   289  }
   290  
   291  type cnServiceAddress struct {
   292  	listenAddr string
   293  }
   294  
   295  func newCNServiceAddress(host string) (cnServiceAddress, error) {
   296  	addrs, err := tests.GetAddressBatch(host, 1)
   297  	if err != nil {
   298  		return cnServiceAddress{}, err
   299  	}
   300  	return cnServiceAddress{listenAddr: addrs[0]}, nil
   301  }
   302  
   303  func (ca cnServiceAddress) listAddresses() []string {
   304  	return []string{ca.listenAddr}
   305  }
   306  
   307  // addressSet records addresses for services within the same partition.
   308  type addressSet map[string]struct{}
   309  
   310  func newAddressSet() addressSet {
   311  	return make(map[string]struct{})
   312  }
   313  
   314  // addAddresses registers a list of addresses.
   315  func (s addressSet) addAddresses(addrs ...string) {
   316  	for _, addr := range addrs {
   317  		s[addr] = struct{}{}
   318  	}
   319  }
   320  
   321  // contains checks address exist or not.
   322  func (s addressSet) contains(addr string) bool {
   323  	_, ok := s[addr]
   324  	return ok
   325  }
   326  
   327  // NetworkPartition records index of services from the same network partition.
   328  type NetworkPartition struct {
   329  	logIndexSet *roaring.Bitmap
   330  	dnIndexSet  *roaring.Bitmap
   331  	cnIndexSet  *roaring.Bitmap
   332  }
   333  
   334  // newNetworkPartition returns an instance of NetworkPartition.
   335  //
   336  // The returned instance only contains valid index according to service number.
   337  func newNetworkPartition(
   338  	logServiceNum int, logIndexes []uint32,
   339  	dnServiceNum int, dnIndexes []uint32,
   340  	cnServiceNum int, cnIndexes []uint32,
   341  ) NetworkPartition {
   342  	logTotal := roaring.FlipInt(roaring.NewBitmap(), 0, logServiceNum)
   343  	dnTotal := roaring.FlipInt(roaring.NewBitmap(), 0, dnServiceNum)
   344  	cnTotal := roaring.FlipInt(roaring.NewBitmap(), 0, cnServiceNum)
   345  
   346  	rawLogSet := roaring.BitmapOf(logIndexes...)
   347  	rawDnSet := roaring.BitmapOf(dnIndexes...)
   348  	rawCnSet := roaring.BitmapOf(cnIndexes...)
   349  
   350  	return NetworkPartition{
   351  		logIndexSet: roaring.And(logTotal, rawLogSet),
   352  		dnIndexSet:  roaring.And(dnTotal, rawDnSet),
   353  		cnIndexSet:  roaring.And(cnTotal, rawCnSet),
   354  	}
   355  }
   356  
   357  // remainingNetworkPartition returns partition for the remaining services.
   358  func remainingNetworkPartition(logServiceNum, dnServiceNum, cnServiceNum int,
   359  	partitions ...NetworkPartition) NetworkPartition {
   360  	logTotal := roaring.FlipInt(roaring.NewBitmap(), 0, logServiceNum)
   361  	dnTotal := roaring.FlipInt(roaring.NewBitmap(), 0, dnServiceNum)
   362  	cnTotal := roaring.FlipInt(roaring.NewBitmap(), 0, cnServiceNum)
   363  
   364  	logUsed := roaring.NewBitmap()
   365  	dnUsed := roaring.NewBitmap()
   366  	cnUsed := roaring.NewBitmap()
   367  	for _, p := range partitions {
   368  		dnUsed.Or(p.dnIndexSet)
   369  		logUsed.Or(p.logIndexSet)
   370  		cnUsed.Or(p.cnIndexSet)
   371  	}
   372  
   373  	return NetworkPartition{
   374  		logIndexSet: roaring.AndNot(logTotal, logUsed),
   375  		dnIndexSet:  roaring.AndNot(dnTotal, dnUsed),
   376  		cnIndexSet:  roaring.AndNot(cnTotal, cnUsed),
   377  	}
   378  }
   379  
   380  // ListDNServiceIndex lists index of all dn services in the partition.
   381  func (p NetworkPartition) ListDNServiceIndex() []uint32 {
   382  	set := p.dnIndexSet
   383  
   384  	if set.GetCardinality() == 0 {
   385  		return nil
   386  	}
   387  
   388  	indexes := make([]uint32, 0, set.GetCardinality())
   389  	iter := set.Iterator()
   390  	for iter.HasNext() {
   391  		indexes = append(indexes, iter.Next())
   392  	}
   393  	return indexes
   394  }
   395  
   396  // ListLogServiceIndex lists index of all log services in the partition.
   397  func (p NetworkPartition) ListLogServiceIndex() []uint32 {
   398  	set := p.logIndexSet
   399  
   400  	if set.GetCardinality() == 0 {
   401  		return nil
   402  	}
   403  
   404  	indexes := make([]uint32, 0, set.GetCardinality())
   405  	iter := set.Iterator()
   406  	for iter.HasNext() {
   407  		indexes = append(indexes, iter.Next())
   408  	}
   409  	return indexes
   410  }
   411  
   412  func (p NetworkPartition) ListCNServiceIndex() []uint32 {
   413  	set := p.cnIndexSet
   414  
   415  	if set.GetCardinality() == 0 {
   416  		return nil
   417  	}
   418  
   419  	indexes := make([]uint32, 0, set.GetCardinality())
   420  	iter := set.Iterator()
   421  	for iter.HasNext() {
   422  		indexes = append(indexes, iter.Next())
   423  	}
   424  	return indexes
   425  }