github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/cluster_test.go (about) 1 // mgo - MongoDB driver for Go 2 // 3 // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // 1. Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright notice, 13 // this list of conditions and the following disclaimer in the documentation 14 // and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 package mgo_test 28 29 import ( 30 "camlistore.org/third_party/labix.org/v2/mgo" 31 "camlistore.org/third_party/labix.org/v2/mgo/bson" 32 . "camlistore.org/third_party/launchpad.net/gocheck" 33 "fmt" 34 "io" 35 "net" 36 "strings" 37 "sync" 38 "time" 39 ) 40 41 func (s *S) TestNewSession(c *C) { 42 session, err := mgo.Dial("localhost:40001") 43 c.Assert(err, IsNil) 44 defer session.Close() 45 46 // Do a dummy operation to wait for connection. 47 coll := session.DB("mydb").C("mycoll") 48 err = coll.Insert(M{"_id": 1}) 49 c.Assert(err, IsNil) 50 51 // Tweak safety and query settings to ensure other has copied those. 52 session.SetSafe(nil) 53 session.SetBatch(-1) 54 other := session.New() 55 defer other.Close() 56 session.SetSafe(&mgo.Safe{}) 57 58 // Clone was copied while session was unsafe, so no errors. 59 otherColl := other.DB("mydb").C("mycoll") 60 err = otherColl.Insert(M{"_id": 1}) 61 c.Assert(err, IsNil) 62 63 // Original session was made safe again. 64 err = coll.Insert(M{"_id": 1}) 65 c.Assert(err, NotNil) 66 67 // With New(), each session has its own socket now. 68 stats := mgo.GetStats() 69 c.Assert(stats.MasterConns, Equals, 2) 70 c.Assert(stats.SocketsInUse, Equals, 2) 71 72 // Ensure query parameters were cloned. 73 err = otherColl.Insert(M{"_id": 2}) 74 c.Assert(err, IsNil) 75 76 // Ping the database to ensure the nonce has been received already. 77 c.Assert(other.Ping(), IsNil) 78 79 mgo.ResetStats() 80 81 iter := otherColl.Find(M{}).Iter() 82 c.Assert(err, IsNil) 83 84 m := M{} 85 ok := iter.Next(m) 86 c.Assert(ok, Equals, true) 87 err = iter.Close() 88 c.Assert(err, IsNil) 89 90 // If Batch(-1) is in effect, a single document must have been received. 91 stats = mgo.GetStats() 92 c.Assert(stats.ReceivedDocs, Equals, 1) 93 } 94 95 func (s *S) TestCloneSession(c *C) { 96 session, err := mgo.Dial("localhost:40001") 97 c.Assert(err, IsNil) 98 defer session.Close() 99 100 // Do a dummy operation to wait for connection. 101 coll := session.DB("mydb").C("mycoll") 102 err = coll.Insert(M{"_id": 1}) 103 c.Assert(err, IsNil) 104 105 // Tweak safety and query settings to ensure clone is copying those. 106 session.SetSafe(nil) 107 session.SetBatch(-1) 108 clone := session.Clone() 109 defer clone.Close() 110 session.SetSafe(&mgo.Safe{}) 111 112 // Clone was copied while session was unsafe, so no errors. 113 cloneColl := clone.DB("mydb").C("mycoll") 114 err = cloneColl.Insert(M{"_id": 1}) 115 c.Assert(err, IsNil) 116 117 // Original session was made safe again. 118 err = coll.Insert(M{"_id": 1}) 119 c.Assert(err, NotNil) 120 121 // With Clone(), same socket is shared between sessions now. 122 stats := mgo.GetStats() 123 c.Assert(stats.SocketsInUse, Equals, 1) 124 c.Assert(stats.SocketRefs, Equals, 2) 125 126 // Refreshing one of them should let the original socket go, 127 // while preserving the safety settings. 128 clone.Refresh() 129 err = cloneColl.Insert(M{"_id": 1}) 130 c.Assert(err, IsNil) 131 132 // Must have used another connection now. 133 stats = mgo.GetStats() 134 c.Assert(stats.SocketsInUse, Equals, 2) 135 c.Assert(stats.SocketRefs, Equals, 2) 136 137 // Ensure query parameters were cloned. 138 err = cloneColl.Insert(M{"_id": 2}) 139 c.Assert(err, IsNil) 140 141 // Ping the database to ensure the nonce has been received already. 142 c.Assert(clone.Ping(), IsNil) 143 144 mgo.ResetStats() 145 146 iter := cloneColl.Find(M{}).Iter() 147 c.Assert(err, IsNil) 148 149 m := M{} 150 ok := iter.Next(m) 151 c.Assert(ok, Equals, true) 152 err = iter.Close() 153 c.Assert(err, IsNil) 154 155 // If Batch(-1) is in effect, a single document must have been received. 156 stats = mgo.GetStats() 157 c.Assert(stats.ReceivedDocs, Equals, 1) 158 } 159 160 func (s *S) TestSetModeStrong(c *C) { 161 session, err := mgo.Dial("localhost:40012") 162 c.Assert(err, IsNil) 163 defer session.Close() 164 165 session.SetMode(mgo.Monotonic, false) 166 session.SetMode(mgo.Strong, false) 167 168 c.Assert(session.Mode(), Equals, mgo.Strong) 169 170 result := M{} 171 cmd := session.DB("admin").C("$cmd") 172 err = cmd.Find(M{"ismaster": 1}).One(&result) 173 c.Assert(err, IsNil) 174 c.Assert(result["ismaster"], Equals, true) 175 176 coll := session.DB("mydb").C("mycoll") 177 err = coll.Insert(M{"a": 1}) 178 c.Assert(err, IsNil) 179 180 // Wait since the sync also uses sockets. 181 for len(session.LiveServers()) != 3 { 182 c.Log("Waiting for cluster sync to finish...") 183 time.Sleep(5e8) 184 } 185 186 stats := mgo.GetStats() 187 c.Assert(stats.MasterConns, Equals, 1) 188 c.Assert(stats.SlaveConns, Equals, 2) 189 c.Assert(stats.SocketsInUse, Equals, 1) 190 191 session.SetMode(mgo.Strong, true) 192 193 stats = mgo.GetStats() 194 c.Assert(stats.SocketsInUse, Equals, 0) 195 } 196 197 func (s *S) TestSetModeMonotonic(c *C) { 198 // Must necessarily connect to a slave, otherwise the 199 // master connection will be available first. 200 session, err := mgo.Dial("localhost:40012") 201 c.Assert(err, IsNil) 202 defer session.Close() 203 204 session.SetMode(mgo.Monotonic, false) 205 206 c.Assert(session.Mode(), Equals, mgo.Monotonic) 207 208 result := M{} 209 cmd := session.DB("admin").C("$cmd") 210 err = cmd.Find(M{"ismaster": 1}).One(&result) 211 c.Assert(err, IsNil) 212 c.Assert(result["ismaster"], Equals, false) 213 214 coll := session.DB("mydb").C("mycoll") 215 err = coll.Insert(M{"a": 1}) 216 c.Assert(err, IsNil) 217 218 result = M{} 219 err = cmd.Find(M{"ismaster": 1}).One(&result) 220 c.Assert(err, IsNil) 221 c.Assert(result["ismaster"], Equals, true) 222 223 // Wait since the sync also uses sockets. 224 for len(session.LiveServers()) != 3 { 225 c.Log("Waiting for cluster sync to finish...") 226 time.Sleep(5e8) 227 } 228 229 stats := mgo.GetStats() 230 c.Assert(stats.MasterConns, Equals, 1) 231 c.Assert(stats.SlaveConns, Equals, 2) 232 c.Assert(stats.SocketsInUse, Equals, 2) 233 234 session.SetMode(mgo.Monotonic, true) 235 236 stats = mgo.GetStats() 237 c.Assert(stats.SocketsInUse, Equals, 0) 238 } 239 240 func (s *S) TestSetModeMonotonicAfterStrong(c *C) { 241 // Test that a strong session shifting to a monotonic 242 // one preserves the socket untouched. 243 244 session, err := mgo.Dial("localhost:40012") 245 c.Assert(err, IsNil) 246 defer session.Close() 247 248 // Insert something to force a connection to the master. 249 coll := session.DB("mydb").C("mycoll") 250 err = coll.Insert(M{"a": 1}) 251 c.Assert(err, IsNil) 252 253 session.SetMode(mgo.Monotonic, false) 254 255 // Wait since the sync also uses sockets. 256 for len(session.LiveServers()) != 3 { 257 c.Log("Waiting for cluster sync to finish...") 258 time.Sleep(5e8) 259 } 260 261 // Master socket should still be reserved. 262 stats := mgo.GetStats() 263 c.Assert(stats.SocketsInUse, Equals, 1) 264 265 // Confirm it's the master even though it's Monotonic by now. 266 result := M{} 267 cmd := session.DB("admin").C("$cmd") 268 err = cmd.Find(M{"ismaster": 1}).One(&result) 269 c.Assert(err, IsNil) 270 c.Assert(result["ismaster"], Equals, true) 271 } 272 273 func (s *S) TestSetModeStrongAfterMonotonic(c *C) { 274 // Test that shifting from Monotonic to Strong while 275 // using a slave socket will keep the socket reserved 276 // until the master socket is necessary, so that no 277 // switch over occurs unless it's actually necessary. 278 279 // Must necessarily connect to a slave, otherwise the 280 // master connection will be available first. 281 session, err := mgo.Dial("localhost:40012") 282 c.Assert(err, IsNil) 283 defer session.Close() 284 285 session.SetMode(mgo.Monotonic, false) 286 287 // Ensure we're talking to a slave, and reserve the socket. 288 result := M{} 289 err = session.Run("ismaster", &result) 290 c.Assert(err, IsNil) 291 c.Assert(result["ismaster"], Equals, false) 292 293 // Switch to a Strong session. 294 session.SetMode(mgo.Strong, false) 295 296 // Wait since the sync also uses sockets. 297 for len(session.LiveServers()) != 3 { 298 c.Log("Waiting for cluster sync to finish...") 299 time.Sleep(5e8) 300 } 301 302 // Slave socket should still be reserved. 303 stats := mgo.GetStats() 304 c.Assert(stats.SocketsInUse, Equals, 1) 305 306 // But any operation will switch it to the master. 307 result = M{} 308 err = session.Run("ismaster", &result) 309 c.Assert(err, IsNil) 310 c.Assert(result["ismaster"], Equals, true) 311 } 312 313 func (s *S) TestSetModeMonotonicWriteOnIteration(c *C) { 314 // Must necessarily connect to a slave, otherwise the 315 // master connection will be available first. 316 session, err := mgo.Dial("localhost:40012") 317 c.Assert(err, IsNil) 318 defer session.Close() 319 320 session.SetMode(mgo.Monotonic, false) 321 322 c.Assert(session.Mode(), Equals, mgo.Monotonic) 323 324 coll1 := session.DB("mydb").C("mycoll1") 325 coll2 := session.DB("mydb").C("mycoll2") 326 327 ns := []int{40, 41, 42, 43, 44, 45, 46} 328 for _, n := range ns { 329 err := coll1.Insert(M{"n": n}) 330 c.Assert(err, IsNil) 331 } 332 333 // Release master so we can grab a slave again. 334 session.Refresh() 335 336 // Wait until synchronization is done. 337 for { 338 n, err := coll1.Count() 339 c.Assert(err, IsNil) 340 if n == len(ns) { 341 break 342 } 343 } 344 345 iter := coll1.Find(nil).Batch(2).Iter() 346 i := 0 347 m := M{} 348 for iter.Next(&m) { 349 i++ 350 if i > 3 { 351 err := coll2.Insert(M{"n": 47 + i}) 352 c.Assert(err, IsNil) 353 } 354 } 355 c.Assert(i, Equals, len(ns)) 356 } 357 358 func (s *S) TestSetModeEventual(c *C) { 359 // Must necessarily connect to a slave, otherwise the 360 // master connection will be available first. 361 session, err := mgo.Dial("localhost:40012") 362 c.Assert(err, IsNil) 363 defer session.Close() 364 365 session.SetMode(mgo.Eventual, false) 366 367 c.Assert(session.Mode(), Equals, mgo.Eventual) 368 369 result := M{} 370 err = session.Run("ismaster", &result) 371 c.Assert(err, IsNil) 372 c.Assert(result["ismaster"], Equals, false) 373 374 coll := session.DB("mydb").C("mycoll") 375 err = coll.Insert(M{"a": 1}) 376 c.Assert(err, IsNil) 377 378 result = M{} 379 err = session.Run("ismaster", &result) 380 c.Assert(err, IsNil) 381 c.Assert(result["ismaster"], Equals, false) 382 383 // Wait since the sync also uses sockets. 384 for len(session.LiveServers()) != 3 { 385 c.Log("Waiting for cluster sync to finish...") 386 time.Sleep(5e8) 387 } 388 389 stats := mgo.GetStats() 390 c.Assert(stats.MasterConns, Equals, 1) 391 c.Assert(stats.SlaveConns, Equals, 2) 392 c.Assert(stats.SocketsInUse, Equals, 0) 393 } 394 395 func (s *S) TestSetModeEventualAfterStrong(c *C) { 396 // Test that a strong session shifting to an eventual 397 // one preserves the socket untouched. 398 399 session, err := mgo.Dial("localhost:40012") 400 c.Assert(err, IsNil) 401 defer session.Close() 402 403 // Insert something to force a connection to the master. 404 coll := session.DB("mydb").C("mycoll") 405 err = coll.Insert(M{"a": 1}) 406 c.Assert(err, IsNil) 407 408 session.SetMode(mgo.Eventual, false) 409 410 // Wait since the sync also uses sockets. 411 for len(session.LiveServers()) != 3 { 412 c.Log("Waiting for cluster sync to finish...") 413 time.Sleep(5e8) 414 } 415 416 // Master socket should still be reserved. 417 stats := mgo.GetStats() 418 c.Assert(stats.SocketsInUse, Equals, 1) 419 420 // Confirm it's the master even though it's Eventual by now. 421 result := M{} 422 cmd := session.DB("admin").C("$cmd") 423 err = cmd.Find(M{"ismaster": 1}).One(&result) 424 c.Assert(err, IsNil) 425 c.Assert(result["ismaster"], Equals, true) 426 427 session.SetMode(mgo.Eventual, true) 428 429 stats = mgo.GetStats() 430 c.Assert(stats.SocketsInUse, Equals, 0) 431 } 432 433 func (s *S) TestPrimaryShutdownStrong(c *C) { 434 if *fast { 435 c.Skip("-fast") 436 } 437 438 session, err := mgo.Dial("localhost:40021") 439 c.Assert(err, IsNil) 440 defer session.Close() 441 442 // With strong consistency, this will open a socket to the master. 443 result := &struct{ Host string }{} 444 err = session.Run("serverStatus", result) 445 c.Assert(err, IsNil) 446 447 // Kill the master. 448 host := result.Host 449 s.Stop(host) 450 451 // This must fail, since the connection was broken. 452 err = session.Run("serverStatus", result) 453 c.Assert(err, Equals, io.EOF) 454 455 // With strong consistency, it fails again until reset. 456 err = session.Run("serverStatus", result) 457 c.Assert(err, Equals, io.EOF) 458 459 session.Refresh() 460 461 // Now we should be able to talk to the new master. 462 // Increase the timeout since this may take quite a while. 463 session.SetSyncTimeout(3 * time.Minute) 464 465 err = session.Run("serverStatus", result) 466 c.Assert(err, IsNil) 467 c.Assert(result.Host, Not(Equals), host) 468 469 // Insert some data to confirm it's indeed a master. 470 err = session.DB("mydb").C("mycoll").Insert(M{"n": 42}) 471 c.Assert(err, IsNil) 472 } 473 474 func (s *S) TestPrimaryHiccup(c *C) { 475 if *fast { 476 c.Skip("-fast") 477 } 478 479 session, err := mgo.Dial("localhost:40021") 480 c.Assert(err, IsNil) 481 defer session.Close() 482 483 // With strong consistency, this will open a socket to the master. 484 result := &struct{ Host string }{} 485 err = session.Run("serverStatus", result) 486 c.Assert(err, IsNil) 487 488 // Establish a few extra sessions to create spare sockets to 489 // the master. This increases a bit the chances of getting an 490 // incorrect cached socket. 491 var sessions []*mgo.Session 492 for i := 0; i < 20; i++ { 493 sessions = append(sessions, session.Copy()) 494 err = sessions[len(sessions)-1].Run("serverStatus", result) 495 c.Assert(err, IsNil) 496 } 497 for i := range sessions { 498 sessions[i].Close() 499 } 500 501 // Kill the master, but bring it back immediatelly. 502 host := result.Host 503 s.Stop(host) 504 s.StartAll() 505 506 // This must fail, since the connection was broken. 507 err = session.Run("serverStatus", result) 508 c.Assert(err, Equals, io.EOF) 509 510 // With strong consistency, it fails again until reset. 511 err = session.Run("serverStatus", result) 512 c.Assert(err, Equals, io.EOF) 513 514 session.Refresh() 515 516 // Now we should be able to talk to the new master. 517 // Increase the timeout since this may take quite a while. 518 session.SetSyncTimeout(3 * time.Minute) 519 520 // Insert some data to confirm it's indeed a master. 521 err = session.DB("mydb").C("mycoll").Insert(M{"n": 42}) 522 c.Assert(err, IsNil) 523 } 524 525 func (s *S) TestPrimaryShutdownMonotonic(c *C) { 526 if *fast { 527 c.Skip("-fast") 528 } 529 530 session, err := mgo.Dial("localhost:40021") 531 c.Assert(err, IsNil) 532 defer session.Close() 533 534 session.SetMode(mgo.Monotonic, true) 535 536 // Insert something to force a switch to the master. 537 coll := session.DB("mydb").C("mycoll") 538 err = coll.Insert(M{"a": 1}) 539 c.Assert(err, IsNil) 540 541 // Wait a bit for this to be synchronized to slaves. 542 time.Sleep(3 * time.Second) 543 544 result := &struct{ Host string }{} 545 err = session.Run("serverStatus", result) 546 c.Assert(err, IsNil) 547 548 // Kill the master. 549 host := result.Host 550 s.Stop(host) 551 552 // This must fail, since the connection was broken. 553 err = session.Run("serverStatus", result) 554 c.Assert(err, Equals, io.EOF) 555 556 // With monotonic consistency, it fails again until reset. 557 err = session.Run("serverStatus", result) 558 c.Assert(err, Equals, io.EOF) 559 560 session.Refresh() 561 562 // Now we should be able to talk to the new master. 563 err = session.Run("serverStatus", result) 564 c.Assert(err, IsNil) 565 c.Assert(result.Host, Not(Equals), host) 566 } 567 568 func (s *S) TestPrimaryShutdownMonotonicWithSlave(c *C) { 569 if *fast { 570 c.Skip("-fast") 571 } 572 573 session, err := mgo.Dial("localhost:40021") 574 c.Assert(err, IsNil) 575 defer session.Close() 576 577 ssresult := &struct{ Host string }{} 578 imresult := &struct{ IsMaster bool }{} 579 580 // Figure the master while still using the strong session. 581 err = session.Run("serverStatus", ssresult) 582 c.Assert(err, IsNil) 583 err = session.Run("isMaster", imresult) 584 c.Assert(err, IsNil) 585 master := ssresult.Host 586 c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master)) 587 588 // Create new monotonic session with an explicit address to ensure 589 // a slave is synchronized before the master, otherwise a connection 590 // with the master may be used below for lack of other options. 591 var addr string 592 switch { 593 case strings.HasSuffix(ssresult.Host, ":40021"): 594 addr = "localhost:40022" 595 case strings.HasSuffix(ssresult.Host, ":40022"): 596 addr = "localhost:40021" 597 case strings.HasSuffix(ssresult.Host, ":40023"): 598 addr = "localhost:40021" 599 default: 600 c.Fatal("Unknown host: ", ssresult.Host) 601 } 602 603 session, err = mgo.Dial(addr) 604 c.Assert(err, IsNil) 605 defer session.Close() 606 607 session.SetMode(mgo.Monotonic, true) 608 609 // Check the address of the socket associated with the monotonic session. 610 c.Log("Running serverStatus and isMaster with monotonic session") 611 err = session.Run("serverStatus", ssresult) 612 c.Assert(err, IsNil) 613 err = session.Run("isMaster", imresult) 614 c.Assert(err, IsNil) 615 slave := ssresult.Host 616 c.Assert(imresult.IsMaster, Equals, false, Commentf("%s is not a slave", slave)) 617 618 c.Assert(master, Not(Equals), slave) 619 620 // Kill the master. 621 s.Stop(master) 622 623 // Session must still be good, since we were talking to a slave. 624 err = session.Run("serverStatus", ssresult) 625 c.Assert(err, IsNil) 626 627 c.Assert(ssresult.Host, Equals, slave, 628 Commentf("Monotonic session moved from %s to %s", slave, ssresult.Host)) 629 630 // If we try to insert something, it'll have to hold until the new 631 // master is available to move the connection, and work correctly. 632 coll := session.DB("mydb").C("mycoll") 633 err = coll.Insert(M{"a": 1}) 634 c.Assert(err, IsNil) 635 636 // Must now be talking to the new master. 637 err = session.Run("serverStatus", ssresult) 638 c.Assert(err, IsNil) 639 err = session.Run("isMaster", imresult) 640 c.Assert(err, IsNil) 641 c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master)) 642 643 // ... which is not the old one, since it's still dead. 644 c.Assert(ssresult.Host, Not(Equals), master) 645 } 646 647 func (s *S) TestPrimaryShutdownEventual(c *C) { 648 if *fast { 649 c.Skip("-fast") 650 } 651 652 session, err := mgo.Dial("localhost:40021") 653 c.Assert(err, IsNil) 654 defer session.Close() 655 656 result := &struct{ Host string }{} 657 err = session.Run("serverStatus", result) 658 c.Assert(err, IsNil) 659 master := result.Host 660 661 session.SetMode(mgo.Eventual, true) 662 663 // Should connect to the master when needed. 664 coll := session.DB("mydb").C("mycoll") 665 err = coll.Insert(M{"a": 1}) 666 c.Assert(err, IsNil) 667 668 // Wait a bit for this to be synchronized to slaves. 669 time.Sleep(3 * time.Second) 670 671 // Kill the master. 672 s.Stop(master) 673 674 // Should still work, with the new master now. 675 coll = session.DB("mydb").C("mycoll") 676 err = coll.Insert(M{"a": 1}) 677 c.Assert(err, IsNil) 678 679 err = session.Run("serverStatus", result) 680 c.Assert(err, IsNil) 681 c.Assert(result.Host, Not(Equals), master) 682 } 683 684 func (s *S) TestPreserveSocketCountOnSync(c *C) { 685 if *fast { 686 c.Skip("-fast") 687 } 688 689 session, err := mgo.Dial("localhost:40011") 690 c.Assert(err, IsNil) 691 defer session.Close() 692 693 stats := mgo.GetStats() 694 for stats.MasterConns+stats.SlaveConns != 3 { 695 stats = mgo.GetStats() 696 c.Log("Waiting for all connections to be established...") 697 time.Sleep(5e8) 698 } 699 700 c.Assert(stats.SocketsAlive, Equals, 3) 701 702 // Kill the master (with rs1, 'a' is always the master). 703 s.Stop("localhost:40011") 704 705 // Wait for the logic to run for a bit and bring it back. 706 go func() { 707 time.Sleep(5e9) 708 s.StartAll() 709 }() 710 711 // Do an action to kick the resync logic in, and also to 712 // wait until the cluster recognizes the server is back. 713 result := struct{ Ok bool }{} 714 err = session.Run("getLastError", &result) 715 c.Assert(err, IsNil) 716 c.Assert(result.Ok, Equals, true) 717 718 for i := 0; i != 20; i++ { 719 stats = mgo.GetStats() 720 if stats.SocketsAlive == 3 { 721 break 722 } 723 c.Logf("Waiting for 3 sockets alive, have %d", stats.SocketsAlive) 724 time.Sleep(5e8) 725 } 726 727 // Ensure the number of sockets is preserved after syncing. 728 stats = mgo.GetStats() 729 c.Assert(stats.SocketsAlive, Equals, 3) 730 c.Assert(stats.SocketsInUse, Equals, 1) 731 c.Assert(stats.SocketRefs, Equals, 1) 732 } 733 734 // Connect to the master of a deployment with a single server, 735 // run an insert, and then ensure the insert worked and that a 736 // single connection was established. 737 func (s *S) TestTopologySyncWithSingleMaster(c *C) { 738 // Use hostname here rather than IP, to make things trickier. 739 session, err := mgo.Dial("localhost:40001") 740 c.Assert(err, IsNil) 741 defer session.Close() 742 743 coll := session.DB("mydb").C("mycoll") 744 err = coll.Insert(M{"a": 1, "b": 2}) 745 c.Assert(err, IsNil) 746 747 // One connection used for discovery. Master socket recycled for 748 // insert. Socket is reserved after insert. 749 stats := mgo.GetStats() 750 c.Assert(stats.MasterConns, Equals, 1) 751 c.Assert(stats.SlaveConns, Equals, 0) 752 c.Assert(stats.SocketsInUse, Equals, 1) 753 754 // Refresh session and socket must be released. 755 session.Refresh() 756 stats = mgo.GetStats() 757 c.Assert(stats.SocketsInUse, Equals, 0) 758 } 759 760 func (s *S) TestTopologySyncWithSlaveSeed(c *C) { 761 // That's supposed to be a slave. Must run discovery 762 // and find out master to insert successfully. 763 session, err := mgo.Dial("localhost:40012") 764 c.Assert(err, IsNil) 765 defer session.Close() 766 767 coll := session.DB("mydb").C("mycoll") 768 coll.Insert(M{"a": 1, "b": 2}) 769 770 result := struct{ Ok bool }{} 771 err = session.Run("getLastError", &result) 772 c.Assert(err, IsNil) 773 c.Assert(result.Ok, Equals, true) 774 775 // One connection to each during discovery. Master 776 // socket recycled for insert. 777 stats := mgo.GetStats() 778 c.Assert(stats.MasterConns, Equals, 1) 779 c.Assert(stats.SlaveConns, Equals, 2) 780 781 // Only one socket reference alive, in the master socket owned 782 // by the above session. 783 c.Assert(stats.SocketsInUse, Equals, 1) 784 785 // Refresh it, and it must be gone. 786 session.Refresh() 787 stats = mgo.GetStats() 788 c.Assert(stats.SocketsInUse, Equals, 0) 789 } 790 791 func (s *S) TestSyncTimeout(c *C) { 792 if *fast { 793 c.Skip("-fast") 794 } 795 796 session, err := mgo.Dial("localhost:40001") 797 c.Assert(err, IsNil) 798 defer session.Close() 799 800 s.Stop("localhost:40001") 801 802 timeout := 3 * time.Second 803 session.SetSyncTimeout(timeout) 804 started := time.Now() 805 806 // Do something. 807 result := struct{ Ok bool }{} 808 err = session.Run("getLastError", &result) 809 c.Assert(err, ErrorMatches, "no reachable servers") 810 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 811 c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true) 812 } 813 814 func (s *S) TestDialWithTimeout(c *C) { 815 if *fast { 816 c.Skip("-fast") 817 } 818 819 timeout := 2 * time.Second 820 started := time.Now() 821 822 // 40009 isn't used by the test servers. 823 session, err := mgo.DialWithTimeout("localhost:40009", timeout) 824 if session != nil { 825 session.Close() 826 } 827 c.Assert(err, ErrorMatches, "no reachable servers") 828 c.Assert(session, IsNil) 829 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 830 c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true) 831 } 832 833 func (s *S) TestSocketTimeout(c *C) { 834 if *fast { 835 c.Skip("-fast") 836 } 837 838 session, err := mgo.Dial("localhost:40001") 839 c.Assert(err, IsNil) 840 defer session.Close() 841 842 s.Freeze("localhost:40001") 843 844 timeout := 3 * time.Second 845 session.SetSocketTimeout(timeout) 846 started := time.Now() 847 848 // Do something. 849 result := struct{ Ok bool }{} 850 err = session.Run("getLastError", &result) 851 c.Assert(err, ErrorMatches, ".*: i/o timeout") 852 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 853 c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true) 854 } 855 856 func (s *S) TestSocketTimeoutOnDial(c *C) { 857 if *fast { 858 c.Skip("-fast") 859 } 860 861 timeout := 1 * time.Second 862 863 defer mgo.HackSyncSocketTimeout(timeout)() 864 865 s.Freeze("localhost:40001") 866 867 started := time.Now() 868 869 session, err := mgo.DialWithTimeout("localhost:40001", timeout) 870 c.Assert(err, ErrorMatches, "no reachable servers") 871 c.Assert(session, IsNil) 872 873 c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true) 874 c.Assert(started.After(time.Now().Add(-20*time.Second)), Equals, true) 875 } 876 877 func (s *S) TestSocketTimeoutOnInactiveSocket(c *C) { 878 if *fast { 879 c.Skip("-fast") 880 } 881 882 session, err := mgo.Dial("localhost:40001") 883 c.Assert(err, IsNil) 884 defer session.Close() 885 886 timeout := 2 * time.Second 887 session.SetSocketTimeout(timeout) 888 889 // Do something that relies on the timeout and works. 890 c.Assert(session.Ping(), IsNil) 891 892 // Freeze and wait for the timeout to go by. 893 s.Freeze("localhost:40001") 894 time.Sleep(timeout + 500*time.Millisecond) 895 s.Thaw("localhost:40001") 896 897 // Do something again. The timeout above should not have killed 898 // the socket as there was nothing to be done. 899 c.Assert(session.Ping(), IsNil) 900 } 901 902 func (s *S) TestDirect(c *C) { 903 session, err := mgo.Dial("localhost:40012?connect=direct") 904 c.Assert(err, IsNil) 905 defer session.Close() 906 907 // We know that server is a slave. 908 session.SetMode(mgo.Monotonic, true) 909 910 result := &struct{ Host string }{} 911 err = session.Run("serverStatus", result) 912 c.Assert(err, IsNil) 913 c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true) 914 915 stats := mgo.GetStats() 916 c.Assert(stats.SocketsAlive, Equals, 1) 917 c.Assert(stats.SocketsInUse, Equals, 1) 918 c.Assert(stats.SocketRefs, Equals, 1) 919 920 // We've got no master, so it'll timeout. 921 session.SetSyncTimeout(5e8 * time.Nanosecond) 922 923 coll := session.DB("mydb").C("mycoll") 924 err = coll.Insert(M{"test": 1}) 925 c.Assert(err, ErrorMatches, "no reachable servers") 926 927 // Writing to the local database is okay. 928 coll = session.DB("local").C("mycoll") 929 defer coll.RemoveAll(nil) 930 id := bson.NewObjectId() 931 err = coll.Insert(M{"_id": id}) 932 c.Assert(err, IsNil) 933 934 // Data was stored in the right server. 935 n, err := coll.Find(M{"_id": id}).Count() 936 c.Assert(err, IsNil) 937 c.Assert(n, Equals, 1) 938 939 // Server hasn't changed. 940 result.Host = "" 941 err = session.Run("serverStatus", result) 942 c.Assert(err, IsNil) 943 c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true) 944 } 945 946 func (s *S) TestDirectToUnknownStateMember(c *C) { 947 session, err := mgo.Dial("localhost:40041?connect=direct") 948 c.Assert(err, IsNil) 949 defer session.Close() 950 951 session.SetMode(mgo.Monotonic, true) 952 953 result := &struct{ Host string }{} 954 err = session.Run("serverStatus", result) 955 c.Assert(err, IsNil) 956 c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true) 957 958 // We've got no master, so it'll timeout. 959 session.SetSyncTimeout(5e8 * time.Nanosecond) 960 961 coll := session.DB("mydb").C("mycoll") 962 err = coll.Insert(M{"test": 1}) 963 c.Assert(err, ErrorMatches, "no reachable servers") 964 965 // Slave is still reachable. 966 result.Host = "" 967 err = session.Run("serverStatus", result) 968 c.Assert(err, IsNil) 969 c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true) 970 } 971 972 type OpCounters struct { 973 Insert int 974 Query int 975 Update int 976 Delete int 977 GetMore int 978 Command int 979 } 980 981 func getOpCounters(server string) (c *OpCounters, err error) { 982 session, err := mgo.Dial(server + "?connect=direct") 983 if err != nil { 984 return nil, err 985 } 986 defer session.Close() 987 session.SetMode(mgo.Monotonic, true) 988 result := struct{ OpCounters }{} 989 err = session.Run("serverStatus", &result) 990 return &result.OpCounters, err 991 } 992 993 func (s *S) TestMonotonicSlaveOkFlagWithMongos(c *C) { 994 session, err := mgo.Dial("localhost:40021") 995 c.Assert(err, IsNil) 996 defer session.Close() 997 998 ssresult := &struct{ Host string }{} 999 imresult := &struct{ IsMaster bool }{} 1000 1001 // Figure the master while still using the strong session. 1002 err = session.Run("serverStatus", ssresult) 1003 c.Assert(err, IsNil) 1004 err = session.Run("isMaster", imresult) 1005 c.Assert(err, IsNil) 1006 master := ssresult.Host 1007 c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master)) 1008 1009 // Collect op counters for everyone. 1010 opc21a, err := getOpCounters("localhost:40021") 1011 c.Assert(err, IsNil) 1012 opc22a, err := getOpCounters("localhost:40022") 1013 c.Assert(err, IsNil) 1014 opc23a, err := getOpCounters("localhost:40023") 1015 c.Assert(err, IsNil) 1016 1017 // Do a SlaveOk query through MongoS 1018 1019 mongos, err := mgo.Dial("localhost:40202") 1020 c.Assert(err, IsNil) 1021 defer mongos.Close() 1022 1023 mongos.SetMode(mgo.Monotonic, true) 1024 1025 coll := mongos.DB("mydb").C("mycoll") 1026 result := &struct{}{} 1027 for i := 0; i != 5; i++ { 1028 err := coll.Find(nil).One(result) 1029 c.Assert(err, Equals, mgo.ErrNotFound) 1030 } 1031 1032 // Collect op counters for everyone again. 1033 opc21b, err := getOpCounters("localhost:40021") 1034 c.Assert(err, IsNil) 1035 opc22b, err := getOpCounters("localhost:40022") 1036 c.Assert(err, IsNil) 1037 opc23b, err := getOpCounters("localhost:40023") 1038 c.Assert(err, IsNil) 1039 1040 masterPort := master[strings.Index(master, ":")+1:] 1041 1042 var masterDelta, slaveDelta int 1043 switch masterPort { 1044 case "40021": 1045 masterDelta = opc21b.Query - opc21a.Query 1046 slaveDelta = (opc22b.Query - opc22a.Query) + (opc23b.Query - opc23a.Query) 1047 case "40022": 1048 masterDelta = opc22b.Query - opc22a.Query 1049 slaveDelta = (opc21b.Query - opc21a.Query) + (opc23b.Query - opc23a.Query) 1050 case "40023": 1051 masterDelta = opc23b.Query - opc23a.Query 1052 slaveDelta = (opc21b.Query - opc21a.Query) + (opc22b.Query - opc22a.Query) 1053 default: 1054 c.Fatal("Uh?") 1055 } 1056 1057 c.Check(masterDelta, Equals, 0) // Just the counting itself. 1058 c.Check(slaveDelta, Equals, 5) // The counting for both, plus 5 queries above. 1059 } 1060 1061 func (s *S) TestRemovalOfClusterMember(c *C) { 1062 if *fast { 1063 c.Skip("-fast") 1064 } 1065 1066 master, err := mgo.Dial("localhost:40021") 1067 c.Assert(err, IsNil) 1068 defer master.Close() 1069 1070 // Wait for cluster to fully sync up. 1071 for i := 0; i < 10; i++ { 1072 if len(master.LiveServers()) == 3 { 1073 break 1074 } 1075 time.Sleep(5e8) 1076 } 1077 if len(master.LiveServers()) != 3 { 1078 c.Fatalf("Test started with bad cluster state: %v", master.LiveServers()) 1079 } 1080 1081 result := &struct { 1082 IsMaster bool 1083 Me string 1084 }{} 1085 slave := master.Copy() 1086 slave.SetMode(mgo.Monotonic, true) // Monotonic can hold a non-master socket persistently. 1087 err = slave.Run("isMaster", result) 1088 c.Assert(err, IsNil) 1089 c.Assert(result.IsMaster, Equals, false) 1090 slaveAddr := result.Me 1091 1092 defer func() { 1093 master.Refresh() 1094 master.Run(bson.D{{"$eval", `rs.add("` + slaveAddr + `")`}}, nil) 1095 master.Close() 1096 slave.Close() 1097 }() 1098 1099 c.Logf("========== Removing slave: %s ==========", slaveAddr) 1100 1101 master.Run(bson.D{{"$eval", `rs.remove("` + slaveAddr + `")`}}, nil) 1102 err = master.Ping() 1103 c.Assert(err, Equals, io.EOF) 1104 1105 master.Refresh() 1106 1107 // Give the cluster a moment to catch up by doing a roundtrip to the master. 1108 err = master.Ping() 1109 c.Assert(err, IsNil) 1110 1111 time.Sleep(3e9) 1112 1113 // This must fail since the slave has been taken off the cluster. 1114 err = slave.Ping() 1115 c.Assert(err, NotNil) 1116 1117 for i := 0; i < 15; i++ { 1118 if len(master.LiveServers()) == 2 { 1119 break 1120 } 1121 time.Sleep(time.Second) 1122 } 1123 live := master.LiveServers() 1124 if len(live) != 2 { 1125 c.Errorf("Removed server still considered live: %#s", live) 1126 } 1127 1128 c.Log("========== Test succeeded. ==========") 1129 } 1130 1131 func (s *S) TestSocketLimit(c *C) { 1132 if *fast { 1133 c.Skip("-fast") 1134 } 1135 const socketLimit = 64 1136 restore := mgo.HackSocketsPerServer(socketLimit) 1137 defer restore() 1138 1139 session, err := mgo.Dial("localhost:40011") 1140 c.Assert(err, IsNil) 1141 defer session.Close() 1142 1143 stats := mgo.GetStats() 1144 for stats.MasterConns+stats.SlaveConns != 3 { 1145 stats = mgo.GetStats() 1146 c.Log("Waiting for all connections to be established...") 1147 time.Sleep(5e8) 1148 } 1149 c.Assert(stats.SocketsAlive, Equals, 3) 1150 1151 // Consume the whole limit for the master. 1152 var master []*mgo.Session 1153 for i := 0; i < socketLimit; i++ { 1154 s := session.Copy() 1155 defer s.Close() 1156 err := s.Ping() 1157 c.Assert(err, IsNil) 1158 master = append(master, s) 1159 } 1160 1161 before := time.Now() 1162 go func() { 1163 time.Sleep(3e9) 1164 master[0].Refresh() 1165 }() 1166 1167 // Now a single ping must block, since it would need another 1168 // connection to the master, over the limit. Once the goroutine 1169 // above releases its socket, it should move on. 1170 session.Ping() 1171 delay := time.Now().Sub(before) 1172 c.Assert(delay > 3e9, Equals, true) 1173 c.Assert(delay < 6e9, Equals, true) 1174 } 1175 1176 func (s *S) TestSetModeEventualIterBug(c *C) { 1177 session1, err := mgo.Dial("localhost:40011") 1178 c.Assert(err, IsNil) 1179 defer session1.Close() 1180 1181 session1.SetMode(mgo.Eventual, false) 1182 1183 coll1 := session1.DB("mydb").C("mycoll") 1184 1185 const N = 100 1186 for i := 0; i < N; i++ { 1187 err = coll1.Insert(M{"_id": i}) 1188 c.Assert(err, IsNil) 1189 } 1190 1191 c.Logf("Waiting until secondary syncs") 1192 for { 1193 n, err := coll1.Count() 1194 c.Assert(err, IsNil) 1195 if n == N { 1196 c.Logf("Found all") 1197 break 1198 } 1199 } 1200 1201 session2, err := mgo.Dial("localhost:40011") 1202 c.Assert(err, IsNil) 1203 defer session2.Close() 1204 1205 session2.SetMode(mgo.Eventual, false) 1206 1207 coll2 := session2.DB("mydb").C("mycoll") 1208 1209 i := 0 1210 iter := coll2.Find(nil).Batch(10).Iter() 1211 var result struct{} 1212 for iter.Next(&result) { 1213 i++ 1214 } 1215 c.Assert(iter.Close(), Equals, nil) 1216 c.Assert(i, Equals, N) 1217 } 1218 1219 func (s *S) TestCustomDialOld(c *C) { 1220 dials := make(chan bool, 16) 1221 dial := func(addr net.Addr) (net.Conn, error) { 1222 tcpaddr, ok := addr.(*net.TCPAddr) 1223 if !ok { 1224 return nil, fmt.Errorf("unexpected address type: %T", addr) 1225 } 1226 dials <- true 1227 return net.DialTCP("tcp", nil, tcpaddr) 1228 } 1229 info := mgo.DialInfo{ 1230 Addrs: []string{"localhost:40012"}, 1231 Dial: dial, 1232 } 1233 1234 // Use hostname here rather than IP, to make things trickier. 1235 session, err := mgo.DialWithInfo(&info) 1236 c.Assert(err, IsNil) 1237 defer session.Close() 1238 1239 const N = 3 1240 for i := 0; i < N; i++ { 1241 select { 1242 case <-dials: 1243 case <-time.After(5 * time.Second): 1244 c.Fatalf("expected %d dials, got %d", N, i) 1245 } 1246 } 1247 select { 1248 case <-dials: 1249 c.Fatalf("got more dials than expected") 1250 case <-time.After(100 * time.Millisecond): 1251 } 1252 } 1253 1254 func (s *S) TestCustomDialNew(c *C) { 1255 dials := make(chan bool, 16) 1256 dial := func(addr *mgo.ServerAddr) (net.Conn, error) { 1257 dials <- true 1258 if addr.TCPAddr().Port == 40012 { 1259 c.Check(addr.String(), Equals, "localhost:40012") 1260 } 1261 return net.DialTCP("tcp", nil, addr.TCPAddr()) 1262 } 1263 info := mgo.DialInfo{ 1264 Addrs: []string{"localhost:40012"}, 1265 DialServer: dial, 1266 } 1267 1268 // Use hostname here rather than IP, to make things trickier. 1269 session, err := mgo.DialWithInfo(&info) 1270 c.Assert(err, IsNil) 1271 defer session.Close() 1272 1273 const N = 3 1274 for i := 0; i < N; i++ { 1275 select { 1276 case <-dials: 1277 case <-time.After(5 * time.Second): 1278 c.Fatalf("expected %d dials, got %d", N, i) 1279 } 1280 } 1281 select { 1282 case <-dials: 1283 c.Fatalf("got more dials than expected") 1284 case <-time.After(100 * time.Millisecond): 1285 } 1286 } 1287 1288 func (s *S) TestPrimaryShutdownOnAuthShard(c *C) { 1289 if *fast { 1290 c.Skip("-fast") 1291 } 1292 1293 // Dial the shard. 1294 session, err := mgo.Dial("localhost:40203") 1295 c.Assert(err, IsNil) 1296 defer session.Close() 1297 1298 // Login and insert something to make it more realistic. 1299 session.DB("admin").Login("root", "rapadura") 1300 coll := session.DB("mydb").C("mycoll") 1301 err = coll.Insert(bson.M{"n": 1}) 1302 c.Assert(err, IsNil) 1303 1304 // Dial the replica set to figure the master out. 1305 rs, err := mgo.Dial("root:rapadura@localhost:40031") 1306 c.Assert(err, IsNil) 1307 defer rs.Close() 1308 1309 // With strong consistency, this will open a socket to the master. 1310 result := &struct{ Host string }{} 1311 err = rs.Run("serverStatus", result) 1312 c.Assert(err, IsNil) 1313 1314 // Kill the master. 1315 host := result.Host 1316 s.Stop(host) 1317 1318 // This must fail, since the connection was broken. 1319 err = rs.Run("serverStatus", result) 1320 c.Assert(err, Equals, io.EOF) 1321 1322 // This won't work because the master just died. 1323 err = coll.Insert(bson.M{"n": 2}) 1324 c.Assert(err, NotNil) 1325 1326 // Refresh session and wait for re-election. 1327 session.Refresh() 1328 for i := 0; i < 60; i++ { 1329 err = coll.Insert(bson.M{"n": 3}) 1330 if err == nil { 1331 break 1332 } 1333 c.Logf("Waiting for replica set to elect a new master. Last error: %v", err) 1334 time.Sleep(500 * time.Millisecond) 1335 } 1336 c.Assert(err, IsNil) 1337 1338 count, err := coll.Count() 1339 c.Assert(count > 1, Equals, true) 1340 } 1341 1342 func (s *S) TestNearestSecondary(c *C) { 1343 defer mgo.HackPingDelay(3 * time.Second)() 1344 1345 rs1a := "127.0.0.1:40011" 1346 rs1b := "127.0.0.1:40012" 1347 rs1c := "127.0.0.1:40013" 1348 s.Freeze(rs1b) 1349 1350 session, err := mgo.Dial(rs1a) 1351 c.Assert(err, IsNil) 1352 defer session.Close() 1353 1354 // Wait for the sync up to run through the first couple of servers. 1355 for len(session.LiveServers()) != 2 { 1356 c.Log("Waiting for two servers to be alive...") 1357 time.Sleep(100 * time.Millisecond) 1358 } 1359 1360 // Extra delay to ensure the third server gets penalized. 1361 time.Sleep(500 * time.Millisecond) 1362 1363 // Release third server. 1364 s.Thaw(rs1b) 1365 1366 // Wait for it to come up. 1367 for len(session.LiveServers()) != 3 { 1368 c.Log("Waiting for all servers to be alive...") 1369 time.Sleep(100 * time.Millisecond) 1370 } 1371 1372 session.SetMode(mgo.Monotonic, true) 1373 var result struct{ Host string } 1374 1375 // See which slave picks the line, several times to avoid chance. 1376 for i := 0; i < 10; i++ { 1377 session.Refresh() 1378 err = session.Run("serverStatus", &result) 1379 c.Assert(err, IsNil) 1380 c.Assert(hostPort(result.Host), Equals, hostPort(rs1c)) 1381 } 1382 1383 if *fast { 1384 // Don't hold back for several seconds. 1385 return 1386 } 1387 1388 // Now hold the other server for long enough to penalize it. 1389 s.Freeze(rs1c) 1390 time.Sleep(5 * time.Second) 1391 s.Thaw(rs1c) 1392 1393 // Wait for the ping to be processed. 1394 time.Sleep(500 * time.Millisecond) 1395 1396 // Repeating the test should now pick the former server consistently. 1397 for i := 0; i < 10; i++ { 1398 session.Refresh() 1399 err = session.Run("serverStatus", &result) 1400 c.Assert(err, IsNil) 1401 c.Assert(hostPort(result.Host), Equals, hostPort(rs1b)) 1402 } 1403 } 1404 1405 func (s *S) TestConnectCloseConcurrency(c *C) { 1406 restore := mgo.HackPingDelay(500 * time.Millisecond) 1407 defer restore() 1408 var wg sync.WaitGroup 1409 const n = 500 1410 wg.Add(n) 1411 for i := 0; i < n; i++ { 1412 go func() { 1413 defer wg.Done() 1414 session, err := mgo.Dial("localhost:40001") 1415 if err != nil { 1416 c.Fatal(err) 1417 } 1418 time.Sleep(1) 1419 session.Close() 1420 }() 1421 } 1422 wg.Wait() 1423 } 1424 1425 func (s *S) TestSelectServers(c *C) { 1426 if !s.versionAtLeast(2, 2) { 1427 c.Skip("read preferences introduced in 2.2") 1428 } 1429 1430 session, err := mgo.Dial("localhost:40011") 1431 c.Assert(err, IsNil) 1432 defer session.Close() 1433 1434 session.SetMode(mgo.Eventual, true) 1435 1436 var result struct{ Host string } 1437 1438 session.Refresh() 1439 session.SelectServers(bson.D{{"rs1", "b"}}) 1440 err = session.Run("serverStatus", &result) 1441 c.Assert(err, IsNil) 1442 c.Assert(hostPort(result.Host), Equals, "40012") 1443 1444 session.Refresh() 1445 session.SelectServers(bson.D{{"rs1", "c"}}) 1446 err = session.Run("serverStatus", &result) 1447 c.Assert(err, IsNil) 1448 c.Assert(hostPort(result.Host), Equals, "40013") 1449 } 1450 1451 func (s *S) TestSelectServersWithMongos(c *C) { 1452 if !s.versionAtLeast(2, 2) { 1453 c.Skip("read preferences introduced in 2.2") 1454 } 1455 1456 session, err := mgo.Dial("localhost:40021") 1457 c.Assert(err, IsNil) 1458 defer session.Close() 1459 1460 ssresult := &struct{ Host string }{} 1461 imresult := &struct{ IsMaster bool }{} 1462 1463 // Figure the master while still using the strong session. 1464 err = session.Run("serverStatus", ssresult) 1465 c.Assert(err, IsNil) 1466 err = session.Run("isMaster", imresult) 1467 c.Assert(err, IsNil) 1468 master := ssresult.Host 1469 c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master)) 1470 1471 var slave1, slave2 string 1472 switch hostPort(master) { 1473 case "40021": 1474 slave1, slave2 = "b", "c" 1475 case "40022": 1476 slave1, slave2 = "a", "c" 1477 case "40023": 1478 slave1, slave2 = "a", "b" 1479 } 1480 1481 // Collect op counters for everyone. 1482 opc21a, err := getOpCounters("localhost:40021") 1483 c.Assert(err, IsNil) 1484 opc22a, err := getOpCounters("localhost:40022") 1485 c.Assert(err, IsNil) 1486 opc23a, err := getOpCounters("localhost:40023") 1487 c.Assert(err, IsNil) 1488 1489 // Do a SlaveOk query through MongoS 1490 mongos, err := mgo.Dial("localhost:40202") 1491 c.Assert(err, IsNil) 1492 defer mongos.Close() 1493 1494 mongos.SetMode(mgo.Monotonic, true) 1495 1496 mongos.Refresh() 1497 mongos.SelectServers(bson.D{{"rs2", slave1}}) 1498 coll := mongos.DB("mydb").C("mycoll") 1499 result := &struct{}{} 1500 for i := 0; i != 5; i++ { 1501 err := coll.Find(nil).One(result) 1502 c.Assert(err, Equals, mgo.ErrNotFound) 1503 } 1504 1505 mongos.Refresh() 1506 mongos.SelectServers(bson.D{{"rs2", slave2}}) 1507 coll = mongos.DB("mydb").C("mycoll") 1508 for i := 0; i != 7; i++ { 1509 err := coll.Find(nil).One(result) 1510 c.Assert(err, Equals, mgo.ErrNotFound) 1511 } 1512 1513 // Collect op counters for everyone again. 1514 opc21b, err := getOpCounters("localhost:40021") 1515 c.Assert(err, IsNil) 1516 opc22b, err := getOpCounters("localhost:40022") 1517 c.Assert(err, IsNil) 1518 opc23b, err := getOpCounters("localhost:40023") 1519 c.Assert(err, IsNil) 1520 1521 switch hostPort(master) { 1522 case "40021": 1523 c.Check(opc21b.Query-opc21a.Query, Equals, 0) 1524 c.Check(opc22b.Query-opc22a.Query, Equals, 5) 1525 c.Check(opc23b.Query-opc23a.Query, Equals, 7) 1526 case "40022": 1527 c.Check(opc21b.Query-opc21a.Query, Equals, 5) 1528 c.Check(opc22b.Query-opc22a.Query, Equals, 0) 1529 c.Check(opc23b.Query-opc23a.Query, Equals, 7) 1530 case "40023": 1531 c.Check(opc21b.Query-opc21a.Query, Equals, 5) 1532 c.Check(opc22b.Query-opc22a.Query, Equals, 7) 1533 c.Check(opc23b.Query-opc23a.Query, Equals, 0) 1534 default: 1535 c.Fatal("Uh?") 1536 } 1537 }