github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/cmd/networkdb-test/dbclient/ndbClient.go (about) 1 package dbclient 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "log" 8 "net" 9 "net/http" 10 "os" 11 "regexp" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/sirupsen/logrus" 17 ) 18 19 var servicePort string 20 21 const totalWrittenKeys string = "totalKeys" 22 23 type resultTuple struct { 24 id string 25 result int 26 } 27 28 func httpGetFatalError(ip, port, path string) { 29 body, err := httpGet(ip, port, path) 30 if err != nil || !strings.Contains(string(body), "OK") { 31 log.Fatalf("[%s] error %s %s", path, err, body) 32 } 33 } 34 35 func httpGet(ip, port, path string) ([]byte, error) { 36 resp, err := http.Get("http://" + ip + ":" + port + path) 37 if err != nil { 38 logrus.Errorf("httpGet error:%s", err) 39 return nil, err 40 } 41 defer resp.Body.Close() 42 body, err := io.ReadAll(resp.Body) 43 return body, err 44 } 45 46 func joinCluster(ip, port string, members []string, doneCh chan resultTuple) { 47 httpGetFatalError(ip, port, "/join?members="+strings.Join(members, ",")) 48 49 if doneCh != nil { 50 doneCh <- resultTuple{id: ip, result: 0} 51 } 52 } 53 54 func joinNetwork(ip, port, network string, doneCh chan resultTuple) { 55 httpGetFatalError(ip, port, "/joinnetwork?nid="+network) 56 57 if doneCh != nil { 58 doneCh <- resultTuple{id: ip, result: 0} 59 } 60 } 61 62 func leaveNetwork(ip, port, network string, doneCh chan resultTuple) { 63 httpGetFatalError(ip, port, "/leavenetwork?nid="+network) 64 65 if doneCh != nil { 66 doneCh <- resultTuple{id: ip, result: 0} 67 } 68 } 69 70 func writeTableKey(ip, port, networkName, tableName, key string) { 71 createPath := "/createentry?unsafe&nid=" + networkName + "&tname=" + tableName + "&value=v&key=" 72 httpGetFatalError(ip, port, createPath+key) 73 } 74 75 func deleteTableKey(ip, port, networkName, tableName, key string) { 76 deletePath := "/deleteentry?nid=" + networkName + "&tname=" + tableName + "&key=" 77 httpGetFatalError(ip, port, deletePath+key) 78 } 79 80 func clusterPeersNumber(ip, port string, doneCh chan resultTuple) { 81 body, err := httpGet(ip, port, "/clusterpeers") 82 83 if err != nil { 84 logrus.Errorf("clusterPeers %s there was an error: %s", ip, err) 85 doneCh <- resultTuple{id: ip, result: -1} 86 return 87 } 88 peersRegexp := regexp.MustCompile(`total entries: ([0-9]+)`) 89 peersNum, _ := strconv.Atoi(peersRegexp.FindStringSubmatch(string(body))[1]) 90 91 doneCh <- resultTuple{id: ip, result: peersNum} 92 } 93 94 func networkPeersNumber(ip, port, networkName string, doneCh chan resultTuple) { 95 body, err := httpGet(ip, port, "/networkpeers?nid="+networkName) 96 97 if err != nil { 98 logrus.Errorf("networkPeersNumber %s there was an error: %s", ip, err) 99 doneCh <- resultTuple{id: ip, result: -1} 100 return 101 } 102 peersRegexp := regexp.MustCompile(`total entries: ([0-9]+)`) 103 peersNum, _ := strconv.Atoi(peersRegexp.FindStringSubmatch(string(body))[1]) 104 105 doneCh <- resultTuple{id: ip, result: peersNum} 106 } 107 108 func dbTableEntriesNumber(ip, port, networkName, tableName string, doneCh chan resultTuple) { 109 body, err := httpGet(ip, port, "/gettable?nid="+networkName+"&tname="+tableName) 110 111 if err != nil { 112 logrus.Errorf("tableEntriesNumber %s there was an error: %s", ip, err) 113 doneCh <- resultTuple{id: ip, result: -1} 114 return 115 } 116 elementsRegexp := regexp.MustCompile(`total entries: ([0-9]+)`) 117 entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1]) 118 doneCh <- resultTuple{id: ip, result: entriesNum} 119 } 120 121 func dbQueueLength(ip, port, networkName string, doneCh chan resultTuple) { 122 body, err := httpGet(ip, port, "/networkstats?nid="+networkName) 123 124 if err != nil { 125 logrus.Errorf("queueLength %s there was an error: %s", ip, err) 126 doneCh <- resultTuple{id: ip, result: -1} 127 return 128 } 129 elementsRegexp := regexp.MustCompile(`qlen: ([0-9]+)`) 130 entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1]) 131 doneCh <- resultTuple{id: ip, result: entriesNum} 132 } 133 134 func clientWatchTable(ip, port, networkName, tableName string, doneCh chan resultTuple) { 135 httpGetFatalError(ip, port, "/watchtable?nid="+networkName+"&tname="+tableName) 136 if doneCh != nil { 137 doneCh <- resultTuple{id: ip, result: 0} 138 } 139 } 140 141 func clientTableEntriesNumber(ip, port, networkName, tableName string, doneCh chan resultTuple) { 142 body, err := httpGet(ip, port, "/watchedtableentries?nid="+networkName+"&tname="+tableName) 143 144 if err != nil { 145 logrus.Errorf("clientTableEntriesNumber %s there was an error: %s", ip, err) 146 doneCh <- resultTuple{id: ip, result: -1} 147 return 148 } 149 elementsRegexp := regexp.MustCompile(`total elements: ([0-9]+)`) 150 entriesNum, _ := strconv.Atoi(elementsRegexp.FindStringSubmatch(string(body))[1]) 151 doneCh <- resultTuple{id: ip, result: entriesNum} 152 } 153 154 func writeKeysNumber(ip, port, networkName, tableName, key string, number int, doneCh chan resultTuple) { 155 x := 0 156 for ; x < number; x++ { 157 k := key + strconv.Itoa(x) 158 // write key 159 writeTableKey(ip, port, networkName, tableName, k) 160 } 161 doneCh <- resultTuple{id: ip, result: x} 162 } 163 164 func deleteKeysNumber(ip, port, networkName, tableName, key string, number int, doneCh chan resultTuple) { 165 x := 0 166 for ; x < number; x++ { 167 k := key + strconv.Itoa(x) 168 // write key 169 deleteTableKey(ip, port, networkName, tableName, k) 170 } 171 doneCh <- resultTuple{id: ip, result: x} 172 } 173 174 func writeUniqueKeys(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) { 175 for x := 0; ; x++ { 176 select { 177 case <-ctx.Done(): 178 doneCh <- resultTuple{id: ip, result: x} 179 return 180 default: 181 k := key + strconv.Itoa(x) 182 // write key 183 writeTableKey(ip, port, networkName, tableName, k) 184 // give time to send out key writes 185 time.Sleep(100 * time.Millisecond) 186 } 187 } 188 } 189 190 func writeDeleteUniqueKeys(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) { 191 for x := 0; ; x++ { 192 select { 193 case <-ctx.Done(): 194 doneCh <- resultTuple{id: ip, result: x} 195 return 196 default: 197 k := key + strconv.Itoa(x) 198 // write key 199 writeTableKey(ip, port, networkName, tableName, k) 200 // give time to send out key writes 201 time.Sleep(100 * time.Millisecond) 202 // delete key 203 deleteTableKey(ip, port, networkName, tableName, k) 204 } 205 } 206 } 207 208 func writeDeleteLeaveJoin(ctx context.Context, ip, port, networkName, tableName, key string, doneCh chan resultTuple) { 209 for x := 0; ; x++ { 210 select { 211 case <-ctx.Done(): 212 doneCh <- resultTuple{id: ip, result: x} 213 return 214 default: 215 k := key + strconv.Itoa(x) 216 // write key 217 writeTableKey(ip, port, networkName, tableName, k) 218 time.Sleep(100 * time.Millisecond) 219 // delete key 220 deleteTableKey(ip, port, networkName, tableName, k) 221 // give some time 222 time.Sleep(100 * time.Millisecond) 223 // leave network 224 leaveNetwork(ip, port, networkName, nil) 225 // join network 226 joinNetwork(ip, port, networkName, nil) 227 } 228 } 229 } 230 231 func ready(ip, port string, doneCh chan resultTuple) { 232 for { 233 body, err := httpGet(ip, port, "/ready") 234 if err != nil || !strings.Contains(string(body), "OK") { 235 time.Sleep(500 * time.Millisecond) 236 continue 237 } 238 // success 239 break 240 } 241 // notify the completion 242 doneCh <- resultTuple{id: ip, result: 0} 243 } 244 245 func checkTable(ctx context.Context, ips []string, port, networkName, tableName string, expectedEntries int, fn func(string, string, string, string, chan resultTuple)) (opTime time.Duration) { 246 startTime := time.Now().UnixNano() 247 var successTime int64 248 249 // Loop for 2 minutes to guarantee that the result is stable 250 for { 251 select { 252 case <-ctx.Done(): 253 // Validate test success, if the time is set means that all the tables are empty 254 if successTime != 0 { 255 opTime = time.Duration(successTime-startTime) / time.Millisecond 256 logrus.Infof("Check table passed, the cluster converged in %d msec", opTime) 257 return 258 } 259 log.Fatal("Test failed, there is still entries in the tables of the nodes") 260 default: 261 logrus.Infof("Checking table %s expected %d", tableName, expectedEntries) 262 doneCh := make(chan resultTuple, len(ips)) 263 for _, ip := range ips { 264 go fn(ip, servicePort, networkName, tableName, doneCh) 265 } 266 267 nodesWithCorrectEntriesNum := 0 268 for i := len(ips); i > 0; i-- { 269 tableEntries := <-doneCh 270 logrus.Infof("Node %s has %d entries", tableEntries.id, tableEntries.result) 271 if tableEntries.result == expectedEntries { 272 nodesWithCorrectEntriesNum++ 273 } 274 } 275 close(doneCh) 276 if nodesWithCorrectEntriesNum == len(ips) { 277 if successTime == 0 { 278 successTime = time.Now().UnixNano() 279 logrus.Infof("Success after %d msec", time.Duration(successTime-startTime)/time.Millisecond) 280 } 281 } else { 282 successTime = 0 283 } 284 time.Sleep(10 * time.Second) 285 } 286 } 287 } 288 289 func waitWriters(parallelWriters int, mustWrite bool, doneCh chan resultTuple) map[string]int { 290 var totalKeys int 291 resultTable := make(map[string]int) 292 for i := 0; i < parallelWriters; i++ { 293 logrus.Infof("Waiting for %d workers", parallelWriters-i) 294 workerReturn := <-doneCh 295 totalKeys += workerReturn.result 296 if mustWrite && workerReturn.result == 0 { 297 log.Fatalf("The worker %s did not write any key %d == 0", workerReturn.id, workerReturn.result) 298 } 299 if !mustWrite && workerReturn.result != 0 { 300 log.Fatalf("The worker %s was supposed to return 0 instead %d != 0", workerReturn.id, workerReturn.result) 301 } 302 if mustWrite { 303 resultTable[workerReturn.id] = workerReturn.result 304 logrus.Infof("The worker %s wrote %d keys", workerReturn.id, workerReturn.result) 305 } 306 } 307 resultTable[totalWrittenKeys] = totalKeys 308 return resultTable 309 } 310 311 // ready 312 func doReady(ips []string) { 313 doneCh := make(chan resultTuple, len(ips)) 314 // check all the nodes 315 for _, ip := range ips { 316 go ready(ip, servicePort, doneCh) 317 } 318 // wait for the readiness of all nodes 319 for i := len(ips); i > 0; i-- { 320 <-doneCh 321 } 322 close(doneCh) 323 } 324 325 // join 326 func doJoin(ips []string) { 327 doneCh := make(chan resultTuple, len(ips)) 328 // check all the nodes 329 for i, ip := range ips { 330 members := append([]string(nil), ips[:i]...) 331 members = append(members, ips[i+1:]...) 332 go joinCluster(ip, servicePort, members, doneCh) 333 } 334 // wait for the readiness of all nodes 335 for i := len(ips); i > 0; i-- { 336 <-doneCh 337 } 338 close(doneCh) 339 } 340 341 // cluster-peers expectedNumberPeers maxRetry 342 func doClusterPeers(ips []string, args []string) { 343 doneCh := make(chan resultTuple, len(ips)) 344 expectedPeers, _ := strconv.Atoi(args[0]) 345 maxRetry, _ := strconv.Atoi(args[1]) 346 for retry := 0; retry < maxRetry; retry++ { 347 // check all the nodes 348 for _, ip := range ips { 349 go clusterPeersNumber(ip, servicePort, doneCh) 350 } 351 var failed bool 352 // wait for the readiness of all nodes 353 for i := len(ips); i > 0; i-- { 354 node := <-doneCh 355 if node.result != expectedPeers { 356 failed = true 357 if retry == maxRetry-1 { 358 log.Fatalf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result) 359 } else { 360 logrus.Warnf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result) 361 } 362 time.Sleep(1 * time.Second) 363 } 364 } 365 // check if needs retry 366 if !failed { 367 break 368 } 369 } 370 close(doneCh) 371 } 372 373 // join-network networkName 374 func doJoinNetwork(ips []string, args []string) { 375 doneCh := make(chan resultTuple, len(ips)) 376 // check all the nodes 377 for _, ip := range ips { 378 go joinNetwork(ip, servicePort, args[0], doneCh) 379 } 380 // wait for the readiness of all nodes 381 for i := len(ips); i > 0; i-- { 382 <-doneCh 383 } 384 close(doneCh) 385 } 386 387 // leave-network networkName 388 func doLeaveNetwork(ips []string, args []string) { 389 doneCh := make(chan resultTuple, len(ips)) 390 // check all the nodes 391 for _, ip := range ips { 392 go leaveNetwork(ip, servicePort, args[0], doneCh) 393 } 394 // wait for the readiness of all nodes 395 for i := len(ips); i > 0; i-- { 396 <-doneCh 397 } 398 close(doneCh) 399 } 400 401 // network-peers networkName expectedNumberPeers maxRetry 402 func doNetworkPeers(ips []string, args []string) { 403 doneCh := make(chan resultTuple, len(ips)) 404 networkName := args[0] 405 expectedPeers, _ := strconv.Atoi(args[1]) 406 maxRetry, _ := strconv.Atoi(args[2]) 407 for retry := 0; retry < maxRetry; retry++ { 408 // check all the nodes 409 for _, ip := range ips { 410 go networkPeersNumber(ip, servicePort, networkName, doneCh) 411 } 412 var failed bool 413 // wait for the readiness of all nodes 414 for i := len(ips); i > 0; i-- { 415 node := <-doneCh 416 if node.result != expectedPeers { 417 failed = true 418 if retry == maxRetry-1 { 419 log.Fatalf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result) 420 } else { 421 logrus.Warnf("Expected peers from %s mismatch %d != %d", node.id, expectedPeers, node.result) 422 } 423 time.Sleep(1 * time.Second) 424 } 425 } 426 // check if needs retry 427 if !failed { 428 break 429 } 430 } 431 close(doneCh) 432 } 433 434 // network-stats-queue networkName <gt/lt> queueSize 435 func doNetworkStatsQueue(ips []string, args []string) { 436 doneCh := make(chan resultTuple, len(ips)) 437 networkName := args[0] 438 comparison := args[1] 439 size, _ := strconv.Atoi(args[2]) 440 441 // check all the nodes 442 for _, ip := range ips { 443 go dbQueueLength(ip, servicePort, networkName, doneCh) 444 } 445 446 var avgQueueSize int 447 // wait for the readiness of all nodes 448 for i := len(ips); i > 0; i-- { 449 node := <-doneCh 450 switch comparison { 451 case "lt": 452 if node.result > size { 453 log.Fatalf("Expected queue size from %s to be %d < %d", node.id, node.result, size) 454 } 455 case "gt": 456 if node.result < size { 457 log.Fatalf("Expected queue size from %s to be %d > %d", node.id, node.result, size) 458 } 459 default: 460 log.Fatal("unknown comparison operator") 461 } 462 avgQueueSize += node.result 463 } 464 close(doneCh) 465 avgQueueSize /= len(ips) 466 fmt.Fprintf(os.Stderr, "doNetworkStatsQueue succeeded with avg queue:%d", avgQueueSize) 467 } 468 469 // write-keys networkName tableName parallelWriters numberOfKeysEach 470 func doWriteKeys(ips []string, args []string) { 471 networkName := args[0] 472 tableName := args[1] 473 parallelWriters, _ := strconv.Atoi(args[2]) 474 numberOfKeys, _ := strconv.Atoi(args[3]) 475 476 doneCh := make(chan resultTuple, parallelWriters) 477 // Enable watch of tables from clients 478 for i := 0; i < parallelWriters; i++ { 479 go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh) 480 } 481 waitWriters(parallelWriters, false, doneCh) 482 483 // Start parallel writers that will create and delete unique keys 484 defer close(doneCh) 485 for i := 0; i < parallelWriters; i++ { 486 key := "key-" + strconv.Itoa(i) + "-" 487 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 488 go writeKeysNumber(ips[i], servicePort, networkName, tableName, key, numberOfKeys, doneCh) 489 } 490 491 // Sync with all the writers 492 keyMap := waitWriters(parallelWriters, true, doneCh) 493 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 494 495 // check table entries for 2 minutes 496 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) 497 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keyMap[totalWrittenKeys], dbTableEntriesNumber) 498 cancel() 499 fmt.Fprintf(os.Stderr, "doWriteKeys succeeded in %d msec", opTime) 500 } 501 502 // delete-keys networkName tableName parallelWriters numberOfKeysEach 503 func doDeleteKeys(ips []string, args []string) { 504 networkName := args[0] 505 tableName := args[1] 506 parallelWriters, _ := strconv.Atoi(args[2]) 507 numberOfKeys, _ := strconv.Atoi(args[3]) 508 509 doneCh := make(chan resultTuple, parallelWriters) 510 // Enable watch of tables from clients 511 for i := 0; i < parallelWriters; i++ { 512 go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh) 513 } 514 waitWriters(parallelWriters, false, doneCh) 515 516 // Start parallel writers that will create and delete unique keys 517 defer close(doneCh) 518 for i := 0; i < parallelWriters; i++ { 519 key := "key-" + strconv.Itoa(i) + "-" 520 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 521 go deleteKeysNumber(ips[i], servicePort, networkName, tableName, key, numberOfKeys, doneCh) 522 } 523 524 // Sync with all the writers 525 keyMap := waitWriters(parallelWriters, true, doneCh) 526 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 527 528 // check table entries for 2 minutes 529 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) 530 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber) 531 cancel() 532 fmt.Fprintf(os.Stderr, "doDeletekeys succeeded in %d msec", opTime) 533 } 534 535 // write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec 536 func doWriteDeleteUniqueKeys(ips []string, args []string) { 537 networkName := args[0] 538 tableName := args[1] 539 parallelWriters, _ := strconv.Atoi(args[2]) 540 writeTimeSec, _ := strconv.Atoi(args[3]) 541 542 doneCh := make(chan resultTuple, parallelWriters) 543 // Enable watch of tables from clients 544 for i := 0; i < parallelWriters; i++ { 545 go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh) 546 } 547 waitWriters(parallelWriters, false, doneCh) 548 549 // Start parallel writers that will create and delete unique keys 550 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 551 for i := 0; i < parallelWriters; i++ { 552 key := "key-" + strconv.Itoa(i) + "-" 553 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 554 go writeDeleteUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 555 } 556 557 // Sync with all the writers 558 keyMap := waitWriters(parallelWriters, true, doneCh) 559 cancel() 560 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 561 562 // check table entries for 2 minutes 563 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 564 opDBTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber) 565 cancel() 566 ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) 567 opClientTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, clientTableEntriesNumber) 568 cancel() 569 fmt.Fprintf(os.Stderr, "doWriteDeleteUniqueKeys succeeded in %d msec and client %d msec", opDBTime, opClientTime) 570 } 571 572 // write-unique-keys networkName tableName numParallelWriters writeTimeSec 573 func doWriteUniqueKeys(ips []string, args []string) { 574 networkName := args[0] 575 tableName := args[1] 576 parallelWriters, _ := strconv.Atoi(args[2]) 577 writeTimeSec, _ := strconv.Atoi(args[3]) 578 579 doneCh := make(chan resultTuple, parallelWriters) 580 // Enable watch of tables from clients 581 for i := 0; i < parallelWriters; i++ { 582 go clientWatchTable(ips[i], servicePort, networkName, tableName, doneCh) 583 } 584 waitWriters(parallelWriters, false, doneCh) 585 586 // Start parallel writers that will create and delete unique keys 587 defer close(doneCh) 588 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 589 for i := 0; i < parallelWriters; i++ { 590 key := "key-" + strconv.Itoa(i) + "-" 591 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 592 go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 593 } 594 595 // Sync with all the writers 596 keyMap := waitWriters(parallelWriters, true, doneCh) 597 cancel() 598 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 599 600 // check table entries for 2 minutes 601 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 602 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keyMap[totalWrittenKeys], dbTableEntriesNumber) 603 cancel() 604 fmt.Fprintf(os.Stderr, "doWriteUniqueKeys succeeded in %d msec", opTime) 605 } 606 607 // write-delete-leave-join networkName tableName numParallelWriters writeTimeSec 608 func doWriteDeleteLeaveJoin(ips []string, args []string) { 609 networkName := args[0] 610 tableName := args[1] 611 parallelWriters, _ := strconv.Atoi(args[2]) 612 writeTimeSec, _ := strconv.Atoi(args[3]) 613 614 // Start parallel writers that will create and delete unique keys 615 doneCh := make(chan resultTuple, parallelWriters) 616 defer close(doneCh) 617 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 618 for i := 0; i < parallelWriters; i++ { 619 key := "key-" + strconv.Itoa(i) + "-" 620 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 621 go writeDeleteLeaveJoin(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 622 } 623 624 // Sync with all the writers 625 keyMap := waitWriters(parallelWriters, true, doneCh) 626 cancel() 627 logrus.Infof("Written a total of %d keys on the cluster", keyMap["totalKeys"]) 628 629 // check table entries for 2 minutes 630 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 631 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber) 632 cancel() 633 fmt.Fprintf(os.Stderr, "doWriteDeleteLeaveJoin succeeded in %d msec", opTime) 634 } 635 636 // write-delete-wait-leave-join networkName tableName numParallelWriters writeTimeSec 637 func doWriteDeleteWaitLeaveJoin(ips []string, args []string) { 638 networkName := args[0] 639 tableName := args[1] 640 parallelWriters, _ := strconv.Atoi(args[2]) 641 writeTimeSec, _ := strconv.Atoi(args[3]) 642 643 // Start parallel writers that will create and delete unique keys 644 doneCh := make(chan resultTuple, parallelWriters) 645 defer close(doneCh) 646 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 647 for i := 0; i < parallelWriters; i++ { 648 key := "key-" + strconv.Itoa(i) + "-" 649 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 650 go writeDeleteUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 651 } 652 653 // Sync with all the writers 654 keyMap := waitWriters(parallelWriters, true, doneCh) 655 cancel() 656 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 657 658 // The writers will leave the network 659 for i := 0; i < parallelWriters; i++ { 660 logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i]) 661 go leaveNetwork(ips[i], servicePort, networkName, doneCh) 662 } 663 waitWriters(parallelWriters, false, doneCh) 664 665 // Give some time 666 time.Sleep(100 * time.Millisecond) 667 668 // The writers will join the network 669 for i := 0; i < parallelWriters; i++ { 670 logrus.Infof("worker joinNetwork: %d on IP:%s", i, ips[i]) 671 go joinNetwork(ips[i], servicePort, networkName, doneCh) 672 } 673 waitWriters(parallelWriters, false, doneCh) 674 675 // check table entries for 2 minutes 676 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 677 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber) 678 cancel() 679 fmt.Fprintf(os.Stderr, "doWriteDeleteWaitLeaveJoin succeeded in %d msec", opTime) 680 } 681 682 // write-wait-leave networkName tableName numParallelWriters writeTimeSec 683 func doWriteWaitLeave(ips []string, args []string) { 684 networkName := args[0] 685 tableName := args[1] 686 parallelWriters, _ := strconv.Atoi(args[2]) 687 writeTimeSec, _ := strconv.Atoi(args[3]) 688 689 // Start parallel writers that will create and delete unique keys 690 doneCh := make(chan resultTuple, parallelWriters) 691 defer close(doneCh) 692 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 693 for i := 0; i < parallelWriters; i++ { 694 key := "key-" + strconv.Itoa(i) + "-" 695 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 696 go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 697 } 698 699 // Sync with all the writers 700 keyMap := waitWriters(parallelWriters, true, doneCh) 701 cancel() 702 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 703 704 // The writers will leave the network 705 for i := 0; i < parallelWriters; i++ { 706 logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i]) 707 go leaveNetwork(ips[i], servicePort, networkName, doneCh) 708 } 709 waitWriters(parallelWriters, false, doneCh) 710 711 // check table entries for 2 minutes 712 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 713 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, 0, dbTableEntriesNumber) 714 cancel() 715 fmt.Fprintf(os.Stderr, "doWriteLeaveJoin succeeded in %d msec", opTime) 716 } 717 718 // write-wait-leave-join networkName tableName numParallelWriters writeTimeSec numParallelLeaver 719 func doWriteWaitLeaveJoin(ips []string, args []string) { 720 networkName := args[0] 721 tableName := args[1] 722 parallelWriters, _ := strconv.Atoi(args[2]) 723 writeTimeSec, _ := strconv.Atoi(args[3]) 724 parallelLeaver, _ := strconv.Atoi(args[4]) 725 726 // Start parallel writers that will create and delete unique keys 727 doneCh := make(chan resultTuple, parallelWriters) 728 defer close(doneCh) 729 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(writeTimeSec)*time.Second) 730 for i := 0; i < parallelWriters; i++ { 731 key := "key-" + strconv.Itoa(i) + "-" 732 logrus.Infof("Spawn worker: %d on IP:%s", i, ips[i]) 733 go writeUniqueKeys(ctx, ips[i], servicePort, networkName, tableName, key, doneCh) 734 } 735 736 // Sync with all the writers 737 keyMap := waitWriters(parallelWriters, true, doneCh) 738 cancel() 739 logrus.Infof("Written a total of %d keys on the cluster", keyMap[totalWrittenKeys]) 740 741 keysExpected := keyMap[totalWrittenKeys] 742 // The Leavers will leave the network 743 for i := 0; i < parallelLeaver; i++ { 744 logrus.Infof("worker leaveNetwork: %d on IP:%s", i, ips[i]) 745 go leaveNetwork(ips[i], servicePort, networkName, doneCh) 746 // Once a node leave all the keys written previously will be deleted, so the expected keys will consider that as removed 747 keysExpected -= keyMap[ips[i]] 748 } 749 waitWriters(parallelLeaver, false, doneCh) 750 751 // Give some time 752 time.Sleep(100 * time.Millisecond) 753 754 // The writers will join the network 755 for i := 0; i < parallelLeaver; i++ { 756 logrus.Infof("worker joinNetwork: %d on IP:%s", i, ips[i]) 757 go joinNetwork(ips[i], servicePort, networkName, doneCh) 758 } 759 waitWriters(parallelLeaver, false, doneCh) 760 761 // check table entries for 2 minutes 762 ctx, cancel = context.WithTimeout(context.Background(), 2*time.Minute) 763 opTime := checkTable(ctx, ips, servicePort, networkName, tableName, keysExpected, dbTableEntriesNumber) 764 cancel() 765 fmt.Fprintf(os.Stderr, "doWriteWaitLeaveJoin succeeded in %d msec", opTime) 766 } 767 768 var cmdArgChec = map[string]int{ 769 "debug": 0, 770 "fail": 0, 771 "ready": 2, 772 "join": 2, 773 "leave": 2, 774 "join-network": 3, 775 "leave-network": 3, 776 "cluster-peers": 5, 777 "network-peers": 5, 778 "write-delete-unique-keys": 7, 779 } 780 781 // Client is a client 782 func Client(args []string) { 783 logrus.Infof("[CLIENT] Starting with arguments %v", args) 784 command := args[0] 785 786 if len(args) < cmdArgChec[command] { 787 log.Fatalf("Command %s requires %d arguments, passed %d, aborting...", command, cmdArgChec[command], len(args)) 788 } 789 790 switch command { 791 case "debug": 792 time.Sleep(1 * time.Hour) 793 os.Exit(0) 794 case "fail": 795 log.Fatalf("Test error condition with message: error error error") 796 } 797 798 serviceName := args[1] 799 ips, _ := net.LookupHost("tasks." + serviceName) 800 logrus.Infof("got the ips %v", ips) 801 if len(ips) == 0 { 802 log.Fatalf("Cannot resolve any IP for the service tasks.%s", serviceName) 803 } 804 servicePort = args[2] 805 commandArgs := args[3:] 806 logrus.Infof("Executing %s with args:%v", command, commandArgs) 807 switch command { 808 case "ready": 809 doReady(ips) 810 case "join": 811 doJoin(ips) 812 case "leave": 813 814 case "cluster-peers": 815 // cluster-peers maxRetry 816 doClusterPeers(ips, commandArgs) 817 818 case "join-network": 819 // join-network networkName 820 doJoinNetwork(ips, commandArgs) 821 case "leave-network": 822 // leave-network networkName 823 doLeaveNetwork(ips, commandArgs) 824 case "network-peers": 825 // network-peers networkName expectedNumberPeers maxRetry 826 doNetworkPeers(ips, commandArgs) 827 // case "network-stats-entries": 828 // // network-stats-entries networkName maxRetry 829 // doNetworkPeers(ips, commandArgs) 830 case "network-stats-queue": 831 // network-stats-queue networkName <lt/gt> queueSize 832 doNetworkStatsQueue(ips, commandArgs) 833 834 case "write-keys": 835 // write-keys networkName tableName parallelWriters numberOfKeysEach 836 doWriteKeys(ips, commandArgs) 837 case "delete-keys": 838 // delete-keys networkName tableName parallelWriters numberOfKeysEach 839 doDeleteKeys(ips, commandArgs) 840 case "write-unique-keys": 841 // write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec 842 doWriteUniqueKeys(ips, commandArgs) 843 case "write-delete-unique-keys": 844 // write-delete-unique-keys networkName tableName numParallelWriters writeTimeSec 845 doWriteDeleteUniqueKeys(ips, commandArgs) 846 case "write-delete-leave-join": 847 // write-delete-leave-join networkName tableName numParallelWriters writeTimeSec 848 doWriteDeleteLeaveJoin(ips, commandArgs) 849 case "write-delete-wait-leave-join": 850 // write-delete-wait-leave-join networkName tableName numParallelWriters writeTimeSec 851 doWriteDeleteWaitLeaveJoin(ips, commandArgs) 852 case "write-wait-leave": 853 // write-wait-leave networkName tableName numParallelWriters writeTimeSec 854 doWriteWaitLeave(ips, commandArgs) 855 case "write-wait-leave-join": 856 // write-wait-leave networkName tableName numParallelWriters writeTimeSec 857 doWriteWaitLeaveJoin(ips, commandArgs) 858 default: 859 log.Fatalf("Command %s not recognized", command) 860 } 861 }