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