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 }