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