github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/gopkg.in/mgo.v2/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  	"fmt"
    31  	"io"
    32  	"net"
    33  	"strings"
    34  	"sync"
    35  	"time"
    36  
    37  	. "gopkg.in/check.v1"
    38  	"gopkg.in/mgo.v2"
    39  	"gopkg.in/mgo.v2/bson"
    40  )
    41  
    42  func (s *S) TestNewSession(c *C) {
    43  	session, err := mgo.Dial("localhost:40001")
    44  	c.Assert(err, IsNil)
    45  	defer session.Close()
    46  
    47  	// Do a dummy operation to wait for connection.
    48  	coll := session.DB("mydb").C("mycoll")
    49  	err = coll.Insert(M{"_id": 1})
    50  	c.Assert(err, IsNil)
    51  
    52  	// Tweak safety and query settings to ensure other has copied those.
    53  	session.SetSafe(nil)
    54  	session.SetBatch(-1)
    55  	other := session.New()
    56  	defer other.Close()
    57  	session.SetSafe(&mgo.Safe{})
    58  
    59  	// Clone was copied while session was unsafe, so no errors.
    60  	otherColl := other.DB("mydb").C("mycoll")
    61  	err = otherColl.Insert(M{"_id": 1})
    62  	c.Assert(err, IsNil)
    63  
    64  	// Original session was made safe again.
    65  	err = coll.Insert(M{"_id": 1})
    66  	c.Assert(err, NotNil)
    67  
    68  	// With New(), each session has its own socket now.
    69  	stats := mgo.GetStats()
    70  	c.Assert(stats.MasterConns, Equals, 2)
    71  	c.Assert(stats.SocketsInUse, Equals, 2)
    72  
    73  	// Ensure query parameters were cloned.
    74  	err = otherColl.Insert(M{"_id": 2})
    75  	c.Assert(err, IsNil)
    76  
    77  	// Ping the database to ensure the nonce has been received already.
    78  	c.Assert(other.Ping(), IsNil)
    79  
    80  	mgo.ResetStats()
    81  
    82  	iter := otherColl.Find(M{}).Iter()
    83  	c.Assert(err, IsNil)
    84  
    85  	m := M{}
    86  	ok := iter.Next(m)
    87  	c.Assert(ok, Equals, true)
    88  	err = iter.Close()
    89  	c.Assert(err, IsNil)
    90  
    91  	// If Batch(-1) is in effect, a single document must have been received.
    92  	stats = mgo.GetStats()
    93  	c.Assert(stats.ReceivedDocs, Equals, 1)
    94  }
    95  
    96  func (s *S) TestCloneSession(c *C) {
    97  	session, err := mgo.Dial("localhost:40001")
    98  	c.Assert(err, IsNil)
    99  	defer session.Close()
   100  
   101  	// Do a dummy operation to wait for connection.
   102  	coll := session.DB("mydb").C("mycoll")
   103  	err = coll.Insert(M{"_id": 1})
   104  	c.Assert(err, IsNil)
   105  
   106  	// Tweak safety and query settings to ensure clone is copying those.
   107  	session.SetSafe(nil)
   108  	session.SetBatch(-1)
   109  	clone := session.Clone()
   110  	defer clone.Close()
   111  	session.SetSafe(&mgo.Safe{})
   112  
   113  	// Clone was copied while session was unsafe, so no errors.
   114  	cloneColl := clone.DB("mydb").C("mycoll")
   115  	err = cloneColl.Insert(M{"_id": 1})
   116  	c.Assert(err, IsNil)
   117  
   118  	// Original session was made safe again.
   119  	err = coll.Insert(M{"_id": 1})
   120  	c.Assert(err, NotNil)
   121  
   122  	// With Clone(), same socket is shared between sessions now.
   123  	stats := mgo.GetStats()
   124  	c.Assert(stats.SocketsInUse, Equals, 1)
   125  	c.Assert(stats.SocketRefs, Equals, 2)
   126  
   127  	// Refreshing one of them should let the original socket go,
   128  	// while preserving the safety settings.
   129  	clone.Refresh()
   130  	err = cloneColl.Insert(M{"_id": 1})
   131  	c.Assert(err, IsNil)
   132  
   133  	// Must have used another connection now.
   134  	stats = mgo.GetStats()
   135  	c.Assert(stats.SocketsInUse, Equals, 2)
   136  	c.Assert(stats.SocketRefs, Equals, 2)
   137  
   138  	// Ensure query parameters were cloned.
   139  	err = cloneColl.Insert(M{"_id": 2})
   140  	c.Assert(err, IsNil)
   141  
   142  	// Ping the database to ensure the nonce has been received already.
   143  	c.Assert(clone.Ping(), IsNil)
   144  
   145  	mgo.ResetStats()
   146  
   147  	iter := cloneColl.Find(M{}).Iter()
   148  	c.Assert(err, IsNil)
   149  
   150  	m := M{}
   151  	ok := iter.Next(m)
   152  	c.Assert(ok, Equals, true)
   153  	err = iter.Close()
   154  	c.Assert(err, IsNil)
   155  
   156  	// If Batch(-1) is in effect, a single document must have been received.
   157  	stats = mgo.GetStats()
   158  	c.Assert(stats.ReceivedDocs, Equals, 1)
   159  }
   160  
   161  func (s *S) TestModeStrong(c *C) {
   162  	session, err := mgo.Dial("localhost:40012")
   163  	c.Assert(err, IsNil)
   164  	defer session.Close()
   165  
   166  	session.SetMode(mgo.Monotonic, false)
   167  	session.SetMode(mgo.Strong, false)
   168  
   169  	c.Assert(session.Mode(), Equals, mgo.Strong)
   170  
   171  	result := M{}
   172  	cmd := session.DB("admin").C("$cmd")
   173  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   174  	c.Assert(err, IsNil)
   175  	c.Assert(result["ismaster"], Equals, true)
   176  
   177  	coll := session.DB("mydb").C("mycoll")
   178  	err = coll.Insert(M{"a": 1})
   179  	c.Assert(err, IsNil)
   180  
   181  	// Wait since the sync also uses sockets.
   182  	for len(session.LiveServers()) != 3 {
   183  		c.Log("Waiting for cluster sync to finish...")
   184  		time.Sleep(5e8)
   185  	}
   186  
   187  	stats := mgo.GetStats()
   188  	c.Assert(stats.MasterConns, Equals, 1)
   189  	c.Assert(stats.SlaveConns, Equals, 2)
   190  	c.Assert(stats.SocketsInUse, Equals, 1)
   191  
   192  	session.SetMode(mgo.Strong, true)
   193  
   194  	stats = mgo.GetStats()
   195  	c.Assert(stats.SocketsInUse, Equals, 0)
   196  }
   197  
   198  func (s *S) TestModeMonotonic(c *C) {
   199  	// Must necessarily connect to a slave, otherwise the
   200  	// master connection will be available first.
   201  	session, err := mgo.Dial("localhost:40012")
   202  	c.Assert(err, IsNil)
   203  	defer session.Close()
   204  
   205  	session.SetMode(mgo.Monotonic, false)
   206  
   207  	c.Assert(session.Mode(), Equals, mgo.Monotonic)
   208  
   209  	var result struct{ IsMaster bool }
   210  	cmd := session.DB("admin").C("$cmd")
   211  	err = cmd.Find(M{"ismaster": 1}).One(&result)
   212  	c.Assert(err, IsNil)
   213  	c.Assert(result.IsMaster, Equals, false)
   214  
   215  	coll := session.DB("mydb").C("mycoll")
   216  	err = coll.Insert(M{"a": 1})
   217  	c.Assert(err, IsNil)
   218  
   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) TestModeMonotonicAfterStrong(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) TestModeStrongAfterMonotonic(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) TestModeMonotonicWriteOnIteration(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) TestModeEventual(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) TestModeEventualAfterStrong(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) TestModeStrongFallover(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) TestModePrimaryHiccup(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) TestModeMonotonicFallover(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) TestModeMonotonicWithSlaveFallover(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) TestModeEventualFallover(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) TestModeSecondaryJustPrimary(c *C) {
   685  	if *fast {
   686  		c.Skip("-fast")
   687  	}
   688  
   689  	session, err := mgo.Dial("localhost:40001")
   690  	c.Assert(err, IsNil)
   691  	defer session.Close()
   692  
   693  	session.SetMode(mgo.Secondary, true)
   694  
   695  	err = session.Ping()
   696  	c.Assert(err, ErrorMatches, "no reachable servers")
   697  }
   698  
   699  func (s *S) TestModeSecondaryPreferredJustPrimary(c *C) {
   700  	if *fast {
   701  		c.Skip("-fast")
   702  	}
   703  
   704  	session, err := mgo.Dial("localhost:40001")
   705  	c.Assert(err, IsNil)
   706  	defer session.Close()
   707  
   708  	session.SetMode(mgo.SecondaryPreferred, true)
   709  
   710  	result := &struct{ Host string }{}
   711  	err = session.Run("serverStatus", result)
   712  	c.Assert(err, IsNil)
   713  }
   714  
   715  func (s *S) TestModeSecondaryPreferredFallover(c *C) {
   716  	if *fast {
   717  		c.Skip("-fast")
   718  	}
   719  
   720  	session, err := mgo.Dial("localhost:40011")
   721  	c.Assert(err, IsNil)
   722  	defer session.Close()
   723  
   724  	// Ensure secondaries are available for being picked up.
   725  	for len(session.LiveServers()) != 3 {
   726  		c.Log("Waiting for cluster sync to finish...")
   727  		time.Sleep(5e8)
   728  	}
   729  
   730  	session.SetMode(mgo.SecondaryPreferred, true)
   731  
   732  	result := &struct{ Host string }{}
   733  	err = session.Run("serverStatus", result)
   734  	c.Assert(err, IsNil)
   735  	c.Assert(supvName(result.Host), Not(Equals), "rs1a")
   736  	secondary := result.Host
   737  
   738  	// Should connect to the primary when needed.
   739  	coll := session.DB("mydb").C("mycoll")
   740  	err = coll.Insert(M{"a": 1})
   741  	c.Assert(err, IsNil)
   742  
   743  	// Wait a bit for this to be synchronized to slaves.
   744  	time.Sleep(3 * time.Second)
   745  
   746  	// Kill the primary.
   747  	s.Stop("localhost:40011")
   748  
   749  	// It can still talk to the selected secondary.
   750  	err = session.Run("serverStatus", result)
   751  	c.Assert(err, IsNil)
   752  	c.Assert(result.Host, Equals, secondary)
   753  
   754  	// But cannot speak to the primary until reset.
   755  	coll = session.DB("mydb").C("mycoll")
   756  	err = coll.Insert(M{"a": 1})
   757  	c.Assert(err, Equals, io.EOF)
   758  
   759  	session.Refresh()
   760  
   761  	// Can still talk to a secondary.
   762  	err = session.Run("serverStatus", result)
   763  	c.Assert(err, IsNil)
   764  	c.Assert(supvName(result.Host), Not(Equals), "rs1a")
   765  
   766  	s.StartAll()
   767  
   768  	// Should now be able to talk to the primary again.
   769  	coll = session.DB("mydb").C("mycoll")
   770  	err = coll.Insert(M{"a": 1})
   771  	c.Assert(err, IsNil)
   772  }
   773  
   774  func (s *S) TestModePrimaryPreferredFallover(c *C) {
   775  	if *fast {
   776  		c.Skip("-fast")
   777  	}
   778  
   779  	session, err := mgo.Dial("localhost:40011")
   780  	c.Assert(err, IsNil)
   781  	defer session.Close()
   782  
   783  	session.SetMode(mgo.PrimaryPreferred, true)
   784  
   785  	result := &struct{ Host string }{}
   786  	err = session.Run("serverStatus", result)
   787  	c.Assert(err, IsNil)
   788  	c.Assert(supvName(result.Host), Equals, "rs1a")
   789  
   790  	// Kill the primary.
   791  	s.Stop("localhost:40011")
   792  
   793  	// Should now fail as there was a primary socket in use already.
   794  	err = session.Run("serverStatus", result)
   795  	c.Assert(err, Equals, io.EOF)
   796  
   797  	// Refresh so the reserved primary socket goes away.
   798  	session.Refresh()
   799  
   800  	// Should be able to talk to the secondary.
   801  	err = session.Run("serverStatus", result)
   802  	c.Assert(err, IsNil)
   803  
   804  	s.StartAll()
   805  
   806  	// Should wait for the new primary to become available.
   807  	coll := session.DB("mydb").C("mycoll")
   808  	err = coll.Insert(M{"a": 1})
   809  	c.Assert(err, IsNil)
   810  
   811  	// And should use the new primary in general, as it is preferred.
   812  	err = session.Run("serverStatus", result)
   813  	c.Assert(err, IsNil)
   814  	c.Assert(supvName(result.Host), Equals, "rs1a")
   815  }
   816  
   817  func (s *S) TestModePrimaryFallover(c *C) {
   818  	if *fast {
   819  		c.Skip("-fast")
   820  	}
   821  
   822  	session, err := mgo.Dial("localhost:40011")
   823  	c.Assert(err, IsNil)
   824  	defer session.Close()
   825  
   826  	session.SetSyncTimeout(3 * time.Second)
   827  
   828  	session.SetMode(mgo.Primary, true)
   829  
   830  	result := &struct{ Host string }{}
   831  	err = session.Run("serverStatus", result)
   832  	c.Assert(err, IsNil)
   833  	c.Assert(supvName(result.Host), Equals, "rs1a")
   834  
   835  	// Kill the primary.
   836  	s.Stop("localhost:40011")
   837  
   838  	session.Refresh()
   839  
   840  	err = session.Ping()
   841  	c.Assert(err, ErrorMatches, "no reachable servers")
   842  }
   843  
   844  func (s *S) TestModeSecondary(c *C) {
   845  	if *fast {
   846  		c.Skip("-fast")
   847  	}
   848  
   849  	session, err := mgo.Dial("localhost:40011")
   850  	c.Assert(err, IsNil)
   851  	defer session.Close()
   852  
   853  	session.SetMode(mgo.Secondary, true)
   854  
   855  	result := &struct{ Host string }{}
   856  	err = session.Run("serverStatus", result)
   857  	c.Assert(err, IsNil)
   858  	c.Assert(supvName(result.Host), Not(Equals), "rs1a")
   859  	secondary := result.Host
   860  
   861  	coll := session.DB("mydb").C("mycoll")
   862  	err = coll.Insert(M{"a": 1})
   863  	c.Assert(err, IsNil)
   864  
   865  	err = session.Run("serverStatus", result)
   866  	c.Assert(err, IsNil)
   867  	c.Assert(result.Host, Equals, secondary)
   868  }
   869  
   870  func (s *S) TestPreserveSocketCountOnSync(c *C) {
   871  	if *fast {
   872  		c.Skip("-fast")
   873  	}
   874  
   875  	session, err := mgo.Dial("localhost:40011")
   876  	c.Assert(err, IsNil)
   877  	defer session.Close()
   878  
   879  	stats := mgo.GetStats()
   880  	for stats.SocketsAlive != 3 {
   881  		c.Logf("Waiting for all connections to be established (sockets alive currently %d)...", stats.SocketsAlive)
   882  		stats = mgo.GetStats()
   883  		time.Sleep(5e8)
   884  	}
   885  
   886  	c.Assert(stats.SocketsAlive, Equals, 3)
   887  
   888  	// Kill the master (with rs1, 'a' is always the master).
   889  	s.Stop("localhost:40011")
   890  
   891  	// Wait for the logic to run for a bit and bring it back.
   892  	startedAll := make(chan bool)
   893  	go func() {
   894  		time.Sleep(5e9)
   895  		s.StartAll()
   896  		startedAll <- true
   897  	}()
   898  
   899  	// Do not allow the test to return before the goroutine above is done.
   900  	defer func() {
   901  		<-startedAll
   902  	}()
   903  
   904  	// Do an action to kick the resync logic in, and also to
   905  	// wait until the cluster recognizes the server is back.
   906  	result := struct{ Ok bool }{}
   907  	err = session.Run("getLastError", &result)
   908  	c.Assert(err, IsNil)
   909  	c.Assert(result.Ok, Equals, true)
   910  
   911  	for i := 0; i != 20; i++ {
   912  		stats = mgo.GetStats()
   913  		if stats.SocketsAlive == 3 {
   914  			break
   915  		}
   916  		c.Logf("Waiting for 3 sockets alive, have %d", stats.SocketsAlive)
   917  		time.Sleep(5e8)
   918  	}
   919  
   920  	// Ensure the number of sockets is preserved after syncing.
   921  	stats = mgo.GetStats()
   922  	c.Assert(stats.SocketsAlive, Equals, 3)
   923  	c.Assert(stats.SocketsInUse, Equals, 1)
   924  	c.Assert(stats.SocketRefs, Equals, 1)
   925  }
   926  
   927  // Connect to the master of a deployment with a single server,
   928  // run an insert, and then ensure the insert worked and that a
   929  // single connection was established.
   930  func (s *S) TestTopologySyncWithSingleMaster(c *C) {
   931  	// Use hostname here rather than IP, to make things trickier.
   932  	session, err := mgo.Dial("localhost:40001")
   933  	c.Assert(err, IsNil)
   934  	defer session.Close()
   935  
   936  	coll := session.DB("mydb").C("mycoll")
   937  	err = coll.Insert(M{"a": 1, "b": 2})
   938  	c.Assert(err, IsNil)
   939  
   940  	// One connection used for discovery. Master socket recycled for
   941  	// insert. Socket is reserved after insert.
   942  	stats := mgo.GetStats()
   943  	c.Assert(stats.MasterConns, Equals, 1)
   944  	c.Assert(stats.SlaveConns, Equals, 0)
   945  	c.Assert(stats.SocketsInUse, Equals, 1)
   946  
   947  	// Refresh session and socket must be released.
   948  	session.Refresh()
   949  	stats = mgo.GetStats()
   950  	c.Assert(stats.SocketsInUse, Equals, 0)
   951  }
   952  
   953  func (s *S) TestTopologySyncWithSlaveSeed(c *C) {
   954  	// That's supposed to be a slave. Must run discovery
   955  	// and find out master to insert successfully.
   956  	session, err := mgo.Dial("localhost:40012")
   957  	c.Assert(err, IsNil)
   958  	defer session.Close()
   959  
   960  	coll := session.DB("mydb").C("mycoll")
   961  	coll.Insert(M{"a": 1, "b": 2})
   962  
   963  	result := struct{ Ok bool }{}
   964  	err = session.Run("getLastError", &result)
   965  	c.Assert(err, IsNil)
   966  	c.Assert(result.Ok, Equals, true)
   967  
   968  	// One connection to each during discovery. Master
   969  	// socket recycled for insert.
   970  	stats := mgo.GetStats()
   971  	c.Assert(stats.MasterConns, Equals, 1)
   972  	c.Assert(stats.SlaveConns, Equals, 2)
   973  
   974  	// Only one socket reference alive, in the master socket owned
   975  	// by the above session.
   976  	c.Assert(stats.SocketsInUse, Equals, 1)
   977  
   978  	// Refresh it, and it must be gone.
   979  	session.Refresh()
   980  	stats = mgo.GetStats()
   981  	c.Assert(stats.SocketsInUse, Equals, 0)
   982  }
   983  
   984  func (s *S) TestSyncTimeout(c *C) {
   985  	if *fast {
   986  		c.Skip("-fast")
   987  	}
   988  
   989  	session, err := mgo.Dial("localhost:40001")
   990  	c.Assert(err, IsNil)
   991  	defer session.Close()
   992  
   993  	s.Stop("localhost:40001")
   994  
   995  	timeout := 3 * time.Second
   996  	session.SetSyncTimeout(timeout)
   997  	started := time.Now()
   998  
   999  	// Do something.
  1000  	result := struct{ Ok bool }{}
  1001  	err = session.Run("getLastError", &result)
  1002  	c.Assert(err, ErrorMatches, "no reachable servers")
  1003  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
  1004  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
  1005  }
  1006  
  1007  func (s *S) TestDialWithTimeout(c *C) {
  1008  	if *fast {
  1009  		c.Skip("-fast")
  1010  	}
  1011  
  1012  	timeout := 2 * time.Second
  1013  	started := time.Now()
  1014  
  1015  	// 40009 isn't used by the test servers.
  1016  	session, err := mgo.DialWithTimeout("localhost:40009", timeout)
  1017  	if session != nil {
  1018  		session.Close()
  1019  	}
  1020  	c.Assert(err, ErrorMatches, "no reachable servers")
  1021  	c.Assert(session, IsNil)
  1022  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
  1023  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
  1024  }
  1025  
  1026  func (s *S) TestSocketTimeout(c *C) {
  1027  	if *fast {
  1028  		c.Skip("-fast")
  1029  	}
  1030  
  1031  	session, err := mgo.Dial("localhost:40001")
  1032  	c.Assert(err, IsNil)
  1033  	defer session.Close()
  1034  
  1035  	s.Freeze("localhost:40001")
  1036  
  1037  	timeout := 3 * time.Second
  1038  	session.SetSocketTimeout(timeout)
  1039  	started := time.Now()
  1040  
  1041  	// Do something.
  1042  	result := struct{ Ok bool }{}
  1043  	err = session.Run("getLastError", &result)
  1044  	c.Assert(err, ErrorMatches, ".*: i/o timeout")
  1045  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
  1046  	c.Assert(started.After(time.Now().Add(-timeout*2)), Equals, true)
  1047  }
  1048  
  1049  func (s *S) TestSocketTimeoutOnDial(c *C) {
  1050  	if *fast {
  1051  		c.Skip("-fast")
  1052  	}
  1053  
  1054  	timeout := 1 * time.Second
  1055  
  1056  	defer mgo.HackSyncSocketTimeout(timeout)()
  1057  
  1058  	s.Freeze("localhost:40001")
  1059  
  1060  	started := time.Now()
  1061  
  1062  	session, err := mgo.DialWithTimeout("localhost:40001", timeout)
  1063  	c.Assert(err, ErrorMatches, "no reachable servers")
  1064  	c.Assert(session, IsNil)
  1065  
  1066  	c.Assert(started.Before(time.Now().Add(-timeout)), Equals, true)
  1067  	c.Assert(started.After(time.Now().Add(-20*time.Second)), Equals, true)
  1068  }
  1069  
  1070  func (s *S) TestSocketTimeoutOnInactiveSocket(c *C) {
  1071  	if *fast {
  1072  		c.Skip("-fast")
  1073  	}
  1074  
  1075  	session, err := mgo.Dial("localhost:40001")
  1076  	c.Assert(err, IsNil)
  1077  	defer session.Close()
  1078  
  1079  	timeout := 2 * time.Second
  1080  	session.SetSocketTimeout(timeout)
  1081  
  1082  	// Do something that relies on the timeout and works.
  1083  	c.Assert(session.Ping(), IsNil)
  1084  
  1085  	// Freeze and wait for the timeout to go by.
  1086  	s.Freeze("localhost:40001")
  1087  	time.Sleep(timeout + 500*time.Millisecond)
  1088  	s.Thaw("localhost:40001")
  1089  
  1090  	// Do something again. The timeout above should not have killed
  1091  	// the socket as there was nothing to be done.
  1092  	c.Assert(session.Ping(), IsNil)
  1093  }
  1094  
  1095  func (s *S) TestDialWithReplicaSetName(c *C) {
  1096  	seedLists := [][]string{
  1097  		// rs1 primary and rs2 primary
  1098  		[]string{"localhost:40011", "localhost:40021"},
  1099  		// rs1 primary and rs2 secondary
  1100  		[]string{"localhost:40011", "localhost:40022"},
  1101  		// rs1 secondary and rs2 primary
  1102  		[]string{"localhost:40012", "localhost:40021"},
  1103  		// rs1 secondary and rs2 secondary
  1104  		[]string{"localhost:40012", "localhost:40022"},
  1105  	}
  1106  
  1107  	rs2Members := []string{":40021", ":40022", ":40023"}
  1108  
  1109  	verifySyncedServers := func(session *mgo.Session, numServers int) {
  1110  		// wait for the server(s) to be synced
  1111  		for len(session.LiveServers()) != numServers {
  1112  			c.Log("Waiting for cluster sync to finish...")
  1113  			time.Sleep(5e8)
  1114  		}
  1115  
  1116  		// ensure none of the rs2 set members are communicated with
  1117  		for _, addr := range session.LiveServers() {
  1118  			for _, rs2Member := range rs2Members {
  1119  				c.Assert(strings.HasSuffix(addr, rs2Member), Equals, false)
  1120  			}
  1121  		}
  1122  	}
  1123  
  1124  	// only communication with rs1 members is expected
  1125  	for _, seedList := range seedLists {
  1126  		info := mgo.DialInfo{
  1127  			Addrs:          seedList,
  1128  			Timeout:        5 * time.Second,
  1129  			ReplicaSetName: "rs1",
  1130  		}
  1131  
  1132  		session, err := mgo.DialWithInfo(&info)
  1133  		c.Assert(err, IsNil)
  1134  		verifySyncedServers(session, 3)
  1135  		session.Close()
  1136  
  1137  		info.Direct = true
  1138  		session, err = mgo.DialWithInfo(&info)
  1139  		c.Assert(err, IsNil)
  1140  		verifySyncedServers(session, 1)
  1141  		session.Close()
  1142  
  1143  		connectionUrl := fmt.Sprintf("mongodb://%v/?replicaSet=rs1", strings.Join(seedList, ","))
  1144  		session, err = mgo.Dial(connectionUrl)
  1145  		c.Assert(err, IsNil)
  1146  		verifySyncedServers(session, 3)
  1147  		session.Close()
  1148  
  1149  		connectionUrl += "&connect=direct"
  1150  		session, err = mgo.Dial(connectionUrl)
  1151  		c.Assert(err, IsNil)
  1152  		verifySyncedServers(session, 1)
  1153  		session.Close()
  1154  	}
  1155  
  1156  }
  1157  
  1158  func (s *S) TestDirect(c *C) {
  1159  	session, err := mgo.Dial("localhost:40012?connect=direct")
  1160  	c.Assert(err, IsNil)
  1161  	defer session.Close()
  1162  
  1163  	// We know that server is a slave.
  1164  	session.SetMode(mgo.Monotonic, true)
  1165  
  1166  	result := &struct{ Host string }{}
  1167  	err = session.Run("serverStatus", result)
  1168  	c.Assert(err, IsNil)
  1169  	c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true)
  1170  
  1171  	stats := mgo.GetStats()
  1172  	c.Assert(stats.SocketsAlive, Equals, 1)
  1173  	c.Assert(stats.SocketsInUse, Equals, 1)
  1174  	c.Assert(stats.SocketRefs, Equals, 1)
  1175  
  1176  	// We've got no master, so it'll timeout.
  1177  	session.SetSyncTimeout(5e8 * time.Nanosecond)
  1178  
  1179  	coll := session.DB("mydb").C("mycoll")
  1180  	err = coll.Insert(M{"test": 1})
  1181  	c.Assert(err, ErrorMatches, "no reachable servers")
  1182  
  1183  	// Writing to the local database is okay.
  1184  	coll = session.DB("local").C("mycoll")
  1185  	defer coll.RemoveAll(nil)
  1186  	id := bson.NewObjectId()
  1187  	err = coll.Insert(M{"_id": id})
  1188  	c.Assert(err, IsNil)
  1189  
  1190  	// Data was stored in the right server.
  1191  	n, err := coll.Find(M{"_id": id}).Count()
  1192  	c.Assert(err, IsNil)
  1193  	c.Assert(n, Equals, 1)
  1194  
  1195  	// Server hasn't changed.
  1196  	result.Host = ""
  1197  	err = session.Run("serverStatus", result)
  1198  	c.Assert(err, IsNil)
  1199  	c.Assert(strings.HasSuffix(result.Host, ":40012"), Equals, true)
  1200  }
  1201  
  1202  func (s *S) TestDirectToUnknownStateMember(c *C) {
  1203  	session, err := mgo.Dial("localhost:40041?connect=direct")
  1204  	c.Assert(err, IsNil)
  1205  	defer session.Close()
  1206  
  1207  	session.SetMode(mgo.Monotonic, true)
  1208  
  1209  	result := &struct{ Host string }{}
  1210  	err = session.Run("serverStatus", result)
  1211  	c.Assert(err, IsNil)
  1212  	c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true)
  1213  
  1214  	// We've got no master, so it'll timeout.
  1215  	session.SetSyncTimeout(5e8 * time.Nanosecond)
  1216  
  1217  	coll := session.DB("mydb").C("mycoll")
  1218  	err = coll.Insert(M{"test": 1})
  1219  	c.Assert(err, ErrorMatches, "no reachable servers")
  1220  
  1221  	// Slave is still reachable.
  1222  	result.Host = ""
  1223  	err = session.Run("serverStatus", result)
  1224  	c.Assert(err, IsNil)
  1225  	c.Assert(strings.HasSuffix(result.Host, ":40041"), Equals, true)
  1226  }
  1227  
  1228  func (s *S) TestFailFast(c *C) {
  1229  	info := mgo.DialInfo{
  1230  		Addrs:    []string{"localhost:99999"},
  1231  		Timeout:  5 * time.Second,
  1232  		FailFast: true,
  1233  	}
  1234  
  1235  	started := time.Now()
  1236  
  1237  	_, err := mgo.DialWithInfo(&info)
  1238  	c.Assert(err, ErrorMatches, "no reachable servers")
  1239  
  1240  	c.Assert(started.After(time.Now().Add(-time.Second)), Equals, true)
  1241  }
  1242  
  1243  func (s *S) countQueries(c *C, server string) (n int) {
  1244  	defer func() { c.Logf("Queries for %q: %d", server, n) }()
  1245  	session, err := mgo.Dial(server + "?connect=direct")
  1246  	c.Assert(err, IsNil)
  1247  	defer session.Close()
  1248  	session.SetMode(mgo.Monotonic, true)
  1249  	var result struct {
  1250  		OpCounters struct {
  1251  			Query int
  1252  		}
  1253  		Metrics struct {
  1254  			Commands struct{ Find struct{ Total int } }
  1255  		}
  1256  	}
  1257  	err = session.Run("serverStatus", &result)
  1258  	c.Assert(err, IsNil)
  1259  	if s.versionAtLeast(3, 2) {
  1260  		return result.Metrics.Commands.Find.Total
  1261  	}
  1262  	return result.OpCounters.Query
  1263  }
  1264  
  1265  func (s *S) countCommands(c *C, server, commandName string) (n int) {
  1266  	defer func() { c.Logf("Queries for %q: %d", server, n) }()
  1267  	session, err := mgo.Dial(server + "?connect=direct")
  1268  	c.Assert(err, IsNil)
  1269  	defer session.Close()
  1270  	session.SetMode(mgo.Monotonic, true)
  1271  	var result struct {
  1272  		Metrics struct {
  1273  			Commands map[string]struct{ Total int }
  1274  		}
  1275  	}
  1276  	err = session.Run("serverStatus", &result)
  1277  	c.Assert(err, IsNil)
  1278  	return result.Metrics.Commands[commandName].Total
  1279  }
  1280  
  1281  func (s *S) TestMonotonicSlaveOkFlagWithMongos(c *C) {
  1282  	session, err := mgo.Dial("localhost:40021")
  1283  	c.Assert(err, IsNil)
  1284  	defer session.Close()
  1285  
  1286  	ssresult := &struct{ Host string }{}
  1287  	imresult := &struct{ IsMaster bool }{}
  1288  
  1289  	// Figure the master while still using the strong session.
  1290  	err = session.Run("serverStatus", ssresult)
  1291  	c.Assert(err, IsNil)
  1292  	err = session.Run("isMaster", imresult)
  1293  	c.Assert(err, IsNil)
  1294  	master := ssresult.Host
  1295  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
  1296  
  1297  	// Ensure mongos is aware about the current topology.
  1298  	s.Stop(":40201")
  1299  	s.StartAll()
  1300  
  1301  	mongos, err := mgo.Dial("localhost:40202")
  1302  	c.Assert(err, IsNil)
  1303  	defer mongos.Close()
  1304  
  1305  	// Insert some data as otherwise 3.2+ doesn't seem to run the query at all.
  1306  	err = mongos.DB("mydb").C("mycoll").Insert(bson.M{"n": 1})
  1307  	c.Assert(err, IsNil)
  1308  
  1309  	// Wait until all servers see the data.
  1310  	for _, addr := range []string{"localhost:40021", "localhost:40022", "localhost:40023"} {
  1311  		session, err := mgo.Dial(addr + "?connect=direct")
  1312  		c.Assert(err, IsNil)
  1313  		defer session.Close()
  1314  		session.SetMode(mgo.Monotonic, true)
  1315  		for i := 300; i >= 0; i-- {
  1316  			n, err := session.DB("mydb").C("mycoll").Find(nil).Count()
  1317  			c.Assert(err, IsNil)
  1318  			if n == 1 {
  1319  				break
  1320  			}
  1321  			if i == 0 {
  1322  				c.Fatalf("Inserted data never reached " + addr)
  1323  			}
  1324  			time.Sleep(100 * time.Millisecond)
  1325  		}
  1326  	}
  1327  
  1328  	// Collect op counters for everyone.
  1329  	q21a := s.countQueries(c, "localhost:40021")
  1330  	q22a := s.countQueries(c, "localhost:40022")
  1331  	q23a := s.countQueries(c, "localhost:40023")
  1332  
  1333  	// Do a SlaveOk query through MongoS
  1334  
  1335  	mongos.SetMode(mgo.Monotonic, true)
  1336  
  1337  	coll := mongos.DB("mydb").C("mycoll")
  1338  	var result struct{ N int }
  1339  	for i := 0; i != 5; i++ {
  1340  		err = coll.Find(nil).One(&result)
  1341  		c.Assert(err, IsNil)
  1342  		c.Assert(result.N, Equals, 1)
  1343  	}
  1344  
  1345  	// Collect op counters for everyone again.
  1346  	q21b := s.countQueries(c, "localhost:40021")
  1347  	q22b := s.countQueries(c, "localhost:40022")
  1348  	q23b := s.countQueries(c, "localhost:40023")
  1349  
  1350  	var masterDelta, slaveDelta int
  1351  	switch hostPort(master) {
  1352  	case "40021":
  1353  		masterDelta = q21b - q21a
  1354  		slaveDelta = (q22b - q22a) + (q23b - q23a)
  1355  	case "40022":
  1356  		masterDelta = q22b - q22a
  1357  		slaveDelta = (q21b - q21a) + (q23b - q23a)
  1358  	case "40023":
  1359  		masterDelta = q23b - q23a
  1360  		slaveDelta = (q21b - q21a) + (q22b - q22a)
  1361  	default:
  1362  		c.Fatal("Uh?")
  1363  	}
  1364  
  1365  	c.Check(masterDelta, Equals, 0) // Just the counting itself.
  1366  	c.Check(slaveDelta, Equals, 5)  // The counting for both, plus 5 queries above.
  1367  }
  1368  
  1369  func (s *S) TestSecondaryModeWithMongos(c *C) {
  1370  	session, err := mgo.Dial("localhost:40021")
  1371  	c.Assert(err, IsNil)
  1372  	defer session.Close()
  1373  
  1374  	ssresult := &struct{ Host string }{}
  1375  	imresult := &struct{ IsMaster bool }{}
  1376  
  1377  	// Figure the master while still using the strong session.
  1378  	err = session.Run("serverStatus", ssresult)
  1379  	c.Assert(err, IsNil)
  1380  	err = session.Run("isMaster", imresult)
  1381  	c.Assert(err, IsNil)
  1382  	master := ssresult.Host
  1383  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
  1384  
  1385  	// Ensure mongos is aware about the current topology.
  1386  	s.Stop(":40201")
  1387  	s.StartAll()
  1388  
  1389  	mongos, err := mgo.Dial("localhost:40202")
  1390  	c.Assert(err, IsNil)
  1391  	defer mongos.Close()
  1392  
  1393  	mongos.SetSyncTimeout(5 * time.Second)
  1394  
  1395  	// Insert some data as otherwise 3.2+ doesn't seem to run the query at all.
  1396  	err = mongos.DB("mydb").C("mycoll").Insert(bson.M{"n": 1})
  1397  	c.Assert(err, IsNil)
  1398  
  1399  	// Wait until all servers see the data.
  1400  	for _, addr := range []string{"localhost:40021", "localhost:40022", "localhost:40023"} {
  1401  		session, err := mgo.Dial(addr + "?connect=direct")
  1402  		c.Assert(err, IsNil)
  1403  		defer session.Close()
  1404  		session.SetMode(mgo.Monotonic, true)
  1405  		for i := 300; i >= 0; i-- {
  1406  			n, err := session.DB("mydb").C("mycoll").Find(nil).Count()
  1407  			c.Assert(err, IsNil)
  1408  			if n == 1 {
  1409  				break
  1410  			}
  1411  			if i == 0 {
  1412  				c.Fatalf("Inserted data never reached " + addr)
  1413  			}
  1414  			time.Sleep(100 * time.Millisecond)
  1415  		}
  1416  	}
  1417  
  1418  	// Collect op counters for everyone.
  1419  	q21a := s.countQueries(c, "localhost:40021")
  1420  	q22a := s.countQueries(c, "localhost:40022")
  1421  	q23a := s.countQueries(c, "localhost:40023")
  1422  
  1423  	// Do a Secondary query through MongoS
  1424  
  1425  	mongos.SetMode(mgo.Secondary, true)
  1426  
  1427  	coll := mongos.DB("mydb").C("mycoll")
  1428  	var result struct{ N int }
  1429  	for i := 0; i != 5; i++ {
  1430  		err = coll.Find(nil).One(&result)
  1431  		c.Assert(err, IsNil)
  1432  		c.Assert(result.N, Equals, 1)
  1433  	}
  1434  
  1435  	// Collect op counters for everyone again.
  1436  	q21b := s.countQueries(c, "localhost:40021")
  1437  	q22b := s.countQueries(c, "localhost:40022")
  1438  	q23b := s.countQueries(c, "localhost:40023")
  1439  
  1440  	var masterDelta, slaveDelta int
  1441  	switch hostPort(master) {
  1442  	case "40021":
  1443  		masterDelta = q21b - q21a
  1444  		slaveDelta = (q22b - q22a) + (q23b - q23a)
  1445  	case "40022":
  1446  		masterDelta = q22b - q22a
  1447  		slaveDelta = (q21b - q21a) + (q23b - q23a)
  1448  	case "40023":
  1449  		masterDelta = q23b - q23a
  1450  		slaveDelta = (q21b - q21a) + (q22b - q22a)
  1451  	default:
  1452  		c.Fatal("Uh?")
  1453  	}
  1454  
  1455  	c.Check(masterDelta, Equals, 0) // Just the counting itself.
  1456  	c.Check(slaveDelta, Equals, 5)  // The counting for both, plus 5 queries above.
  1457  }
  1458  
  1459  func (s *S) TestSecondaryModeWithMongosInsert(c *C) {
  1460  	if *fast {
  1461  		c.Skip("-fast")
  1462  	}
  1463  
  1464  	session, err := mgo.Dial("localhost:40202")
  1465  	c.Assert(err, IsNil)
  1466  	defer session.Close()
  1467  
  1468  	session.SetMode(mgo.Secondary, true)
  1469  	session.SetSyncTimeout(4 * time.Second)
  1470  
  1471  	coll := session.DB("mydb").C("mycoll")
  1472  	err = coll.Insert(M{"a": 1})
  1473  	c.Assert(err, IsNil)
  1474  
  1475  	var result struct{ A int }
  1476  	coll.Find(nil).One(&result)
  1477  	c.Assert(result.A, Equals, 1)
  1478  }
  1479  
  1480  func (s *S) TestRemovalOfClusterMember(c *C) {
  1481  	if *fast {
  1482  		c.Skip("-fast")
  1483  	}
  1484  
  1485  	master, err := mgo.Dial("localhost:40021")
  1486  	c.Assert(err, IsNil)
  1487  	defer master.Close()
  1488  
  1489  	// Wait for cluster to fully sync up.
  1490  	for i := 0; i < 10; i++ {
  1491  		if len(master.LiveServers()) == 3 {
  1492  			break
  1493  		}
  1494  		time.Sleep(5e8)
  1495  	}
  1496  	if len(master.LiveServers()) != 3 {
  1497  		c.Fatalf("Test started with bad cluster state: %v", master.LiveServers())
  1498  	}
  1499  
  1500  	result := &struct {
  1501  		IsMaster bool
  1502  		Me       string
  1503  	}{}
  1504  	slave := master.Copy()
  1505  	slave.SetMode(mgo.Monotonic, true) // Monotonic can hold a non-master socket persistently.
  1506  	err = slave.Run("isMaster", result)
  1507  	c.Assert(err, IsNil)
  1508  	c.Assert(result.IsMaster, Equals, false)
  1509  	slaveAddr := result.Me
  1510  
  1511  	defer func() {
  1512  		config := map[string]string{
  1513  			"40021": `{_id: 1, host: "127.0.0.1:40021", priority: 1, tags: {rs2: "a"}}`,
  1514  			"40022": `{_id: 2, host: "127.0.0.1:40022", priority: 0, tags: {rs2: "b"}}`,
  1515  			"40023": `{_id: 3, host: "127.0.0.1:40023", priority: 0, tags: {rs2: "c"}}`,
  1516  		}
  1517  		master.Refresh()
  1518  		master.Run(bson.D{{"$eval", `rs.add(` + config[hostPort(slaveAddr)] + `)`}}, nil)
  1519  		master.Close()
  1520  		slave.Close()
  1521  
  1522  		// Ensure suite syncs up with the changes before next test.
  1523  		s.Stop(":40201")
  1524  		s.StartAll()
  1525  		time.Sleep(8 * time.Second)
  1526  		// TODO Find a better way to find out when mongos is fully aware that all
  1527  		// servers are up. Without that follow up tests that depend on mongos will
  1528  		// break due to their expectation of things being in a working state.
  1529  	}()
  1530  
  1531  	c.Logf("========== Removing slave: %s ==========", slaveAddr)
  1532  
  1533  	master.Run(bson.D{{"$eval", `rs.remove("` + slaveAddr + `")`}}, nil)
  1534  
  1535  	master.Refresh()
  1536  
  1537  	// Give the cluster a moment to catch up by doing a roundtrip to the master.
  1538  	err = master.Ping()
  1539  	c.Assert(err, IsNil)
  1540  
  1541  	time.Sleep(3e9)
  1542  
  1543  	// This must fail since the slave has been taken off the cluster.
  1544  	err = slave.Ping()
  1545  	c.Assert(err, NotNil)
  1546  
  1547  	for i := 0; i < 15; i++ {
  1548  		if len(master.LiveServers()) == 2 {
  1549  			break
  1550  		}
  1551  		time.Sleep(time.Second)
  1552  	}
  1553  	live := master.LiveServers()
  1554  	if len(live) != 2 {
  1555  		c.Errorf("Removed server still considered live: %#s", live)
  1556  	}
  1557  
  1558  	c.Log("========== Test succeeded. ==========")
  1559  }
  1560  
  1561  func (s *S) TestPoolLimitSimple(c *C) {
  1562  	for test := 0; test < 2; test++ {
  1563  		var session *mgo.Session
  1564  		var err error
  1565  		if test == 0 {
  1566  			session, err = mgo.Dial("localhost:40001")
  1567  			c.Assert(err, IsNil)
  1568  			session.SetPoolLimit(1)
  1569  		} else {
  1570  			session, err = mgo.Dial("localhost:40001?maxPoolSize=1")
  1571  			c.Assert(err, IsNil)
  1572  		}
  1573  		defer session.Close()
  1574  
  1575  		// Put one socket in use.
  1576  		c.Assert(session.Ping(), IsNil)
  1577  
  1578  		done := make(chan time.Duration)
  1579  
  1580  		// Now block trying to get another one due to the pool limit.
  1581  		go func() {
  1582  			copy := session.Copy()
  1583  			defer copy.Close()
  1584  			started := time.Now()
  1585  			c.Check(copy.Ping(), IsNil)
  1586  			done <- time.Now().Sub(started)
  1587  		}()
  1588  
  1589  		time.Sleep(300 * time.Millisecond)
  1590  
  1591  		// Put the one socket back in the pool, freeing it for the copy.
  1592  		session.Refresh()
  1593  		delay := <-done
  1594  		c.Assert(delay > 300*time.Millisecond, Equals, true, Commentf("Delay: %s", delay))
  1595  	}
  1596  }
  1597  
  1598  func (s *S) TestPoolLimitMany(c *C) {
  1599  	if *fast {
  1600  		c.Skip("-fast")
  1601  	}
  1602  
  1603  	session, err := mgo.Dial("localhost:40011")
  1604  	c.Assert(err, IsNil)
  1605  	defer session.Close()
  1606  
  1607  	stats := mgo.GetStats()
  1608  	for stats.SocketsAlive != 3 {
  1609  		c.Logf("Waiting for all connections to be established (sockets alive currently %d)...", stats.SocketsAlive)
  1610  		stats = mgo.GetStats()
  1611  		time.Sleep(5e8)
  1612  	}
  1613  
  1614  	const poolLimit = 64
  1615  	session.SetPoolLimit(poolLimit)
  1616  
  1617  	// Consume the whole limit for the master.
  1618  	var master []*mgo.Session
  1619  	for i := 0; i < poolLimit; i++ {
  1620  		s := session.Copy()
  1621  		defer s.Close()
  1622  		c.Assert(s.Ping(), IsNil)
  1623  		master = append(master, s)
  1624  	}
  1625  
  1626  	before := time.Now()
  1627  	go func() {
  1628  		time.Sleep(3e9)
  1629  		master[0].Refresh()
  1630  	}()
  1631  
  1632  	// Then, a single ping must block, since it would need another
  1633  	// connection to the master, over the limit. Once the goroutine
  1634  	// above releases its socket, it should move on.
  1635  	session.Ping()
  1636  	delay := time.Now().Sub(before)
  1637  	c.Assert(delay > 3e9, Equals, true)
  1638  	c.Assert(delay < 6e9, Equals, true)
  1639  }
  1640  
  1641  func (s *S) TestSetModeEventualIterBug(c *C) {
  1642  	session1, err := mgo.Dial("localhost:40011")
  1643  	c.Assert(err, IsNil)
  1644  	defer session1.Close()
  1645  
  1646  	session1.SetMode(mgo.Eventual, false)
  1647  
  1648  	coll1 := session1.DB("mydb").C("mycoll")
  1649  
  1650  	const N = 100
  1651  	for i := 0; i < N; i++ {
  1652  		err = coll1.Insert(M{"_id": i})
  1653  		c.Assert(err, IsNil)
  1654  	}
  1655  
  1656  	c.Logf("Waiting until secondary syncs")
  1657  	for {
  1658  		n, err := coll1.Count()
  1659  		c.Assert(err, IsNil)
  1660  		if n == N {
  1661  			c.Logf("Found all")
  1662  			break
  1663  		}
  1664  	}
  1665  
  1666  	session2, err := mgo.Dial("localhost:40011")
  1667  	c.Assert(err, IsNil)
  1668  	defer session2.Close()
  1669  
  1670  	session2.SetMode(mgo.Eventual, false)
  1671  
  1672  	coll2 := session2.DB("mydb").C("mycoll")
  1673  
  1674  	i := 0
  1675  	iter := coll2.Find(nil).Batch(10).Iter()
  1676  	var result struct{}
  1677  	for iter.Next(&result) {
  1678  		i++
  1679  	}
  1680  	c.Assert(iter.Close(), Equals, nil)
  1681  	c.Assert(i, Equals, N)
  1682  }
  1683  
  1684  func (s *S) TestCustomDialOld(c *C) {
  1685  	dials := make(chan bool, 16)
  1686  	dial := func(addr net.Addr) (net.Conn, error) {
  1687  		tcpaddr, ok := addr.(*net.TCPAddr)
  1688  		if !ok {
  1689  			return nil, fmt.Errorf("unexpected address type: %T", addr)
  1690  		}
  1691  		dials <- true
  1692  		return net.DialTCP("tcp", nil, tcpaddr)
  1693  	}
  1694  	info := mgo.DialInfo{
  1695  		Addrs: []string{"localhost:40012"},
  1696  		Dial:  dial,
  1697  	}
  1698  
  1699  	// Use hostname here rather than IP, to make things trickier.
  1700  	session, err := mgo.DialWithInfo(&info)
  1701  	c.Assert(err, IsNil)
  1702  	defer session.Close()
  1703  
  1704  	const N = 3
  1705  	for i := 0; i < N; i++ {
  1706  		select {
  1707  		case <-dials:
  1708  		case <-time.After(5 * time.Second):
  1709  			c.Fatalf("expected %d dials, got %d", N, i)
  1710  		}
  1711  	}
  1712  	select {
  1713  	case <-dials:
  1714  		c.Fatalf("got more dials than expected")
  1715  	case <-time.After(100 * time.Millisecond):
  1716  	}
  1717  }
  1718  
  1719  func (s *S) TestCustomDialNew(c *C) {
  1720  	dials := make(chan bool, 16)
  1721  	dial := func(addr *mgo.ServerAddr) (net.Conn, error) {
  1722  		dials <- true
  1723  		if addr.TCPAddr().Port == 40012 {
  1724  			c.Check(addr.String(), Equals, "localhost:40012")
  1725  		}
  1726  		return net.DialTCP("tcp", nil, addr.TCPAddr())
  1727  	}
  1728  	info := mgo.DialInfo{
  1729  		Addrs:      []string{"localhost:40012"},
  1730  		DialServer: dial,
  1731  	}
  1732  
  1733  	// Use hostname here rather than IP, to make things trickier.
  1734  	session, err := mgo.DialWithInfo(&info)
  1735  	c.Assert(err, IsNil)
  1736  	defer session.Close()
  1737  
  1738  	const N = 3
  1739  	for i := 0; i < N; i++ {
  1740  		select {
  1741  		case <-dials:
  1742  		case <-time.After(5 * time.Second):
  1743  			c.Fatalf("expected %d dials, got %d", N, i)
  1744  		}
  1745  	}
  1746  	select {
  1747  	case <-dials:
  1748  		c.Fatalf("got more dials than expected")
  1749  	case <-time.After(100 * time.Millisecond):
  1750  	}
  1751  }
  1752  
  1753  func (s *S) TestPrimaryShutdownOnAuthShard(c *C) {
  1754  	if *fast {
  1755  		c.Skip("-fast")
  1756  	}
  1757  
  1758  	// Dial the shard.
  1759  	session, err := mgo.Dial("localhost:40203")
  1760  	c.Assert(err, IsNil)
  1761  	defer session.Close()
  1762  
  1763  	// Login and insert something to make it more realistic.
  1764  	session.DB("admin").Login("root", "rapadura")
  1765  	coll := session.DB("mydb").C("mycoll")
  1766  	err = coll.Insert(bson.M{"n": 1})
  1767  	c.Assert(err, IsNil)
  1768  
  1769  	// Dial the replica set to figure the master out.
  1770  	rs, err := mgo.Dial("root:rapadura@localhost:40031")
  1771  	c.Assert(err, IsNil)
  1772  	defer rs.Close()
  1773  
  1774  	// With strong consistency, this will open a socket to the master.
  1775  	result := &struct{ Host string }{}
  1776  	err = rs.Run("serverStatus", result)
  1777  	c.Assert(err, IsNil)
  1778  
  1779  	// Kill the master.
  1780  	host := result.Host
  1781  	s.Stop(host)
  1782  
  1783  	// This must fail, since the connection was broken.
  1784  	err = rs.Run("serverStatus", result)
  1785  	c.Assert(err, Equals, io.EOF)
  1786  
  1787  	// This won't work because the master just died.
  1788  	err = coll.Insert(bson.M{"n": 2})
  1789  	c.Assert(err, NotNil)
  1790  
  1791  	// Refresh session and wait for re-election.
  1792  	session.Refresh()
  1793  	for i := 0; i < 60; i++ {
  1794  		err = coll.Insert(bson.M{"n": 3})
  1795  		if err == nil {
  1796  			break
  1797  		}
  1798  		c.Logf("Waiting for replica set to elect a new master. Last error: %v", err)
  1799  		time.Sleep(500 * time.Millisecond)
  1800  	}
  1801  	c.Assert(err, IsNil)
  1802  
  1803  	count, err := coll.Count()
  1804  	c.Assert(count > 1, Equals, true)
  1805  }
  1806  
  1807  func (s *S) TestNearestSecondary(c *C) {
  1808  	defer mgo.HackPingDelay(300 * time.Millisecond)()
  1809  
  1810  	rs1a := "127.0.0.1:40011"
  1811  	rs1b := "127.0.0.1:40012"
  1812  	rs1c := "127.0.0.1:40013"
  1813  	s.Freeze(rs1b)
  1814  
  1815  	session, err := mgo.Dial(rs1a)
  1816  	c.Assert(err, IsNil)
  1817  	defer session.Close()
  1818  
  1819  	// Wait for the sync up to run through the first couple of servers.
  1820  	for len(session.LiveServers()) != 2 {
  1821  		c.Log("Waiting for two servers to be alive...")
  1822  		time.Sleep(100 * time.Millisecond)
  1823  	}
  1824  
  1825  	// Extra delay to ensure the third server gets penalized.
  1826  	time.Sleep(500 * time.Millisecond)
  1827  
  1828  	// Release third server.
  1829  	s.Thaw(rs1b)
  1830  
  1831  	// Wait for it to come up.
  1832  	for len(session.LiveServers()) != 3 {
  1833  		c.Log("Waiting for all servers to be alive...")
  1834  		time.Sleep(100 * time.Millisecond)
  1835  	}
  1836  
  1837  	session.SetMode(mgo.Monotonic, true)
  1838  	var result struct{ Host string }
  1839  
  1840  	// See which slave picks the line, several times to avoid chance.
  1841  	for i := 0; i < 10; i++ {
  1842  		session.Refresh()
  1843  		err = session.Run("serverStatus", &result)
  1844  		c.Assert(err, IsNil)
  1845  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1c))
  1846  	}
  1847  
  1848  	if *fast {
  1849  		// Don't hold back for several seconds.
  1850  		return
  1851  	}
  1852  
  1853  	// Now hold the other server for long enough to penalize it.
  1854  	s.Freeze(rs1c)
  1855  	time.Sleep(5 * time.Second)
  1856  	s.Thaw(rs1c)
  1857  
  1858  	// Wait for the ping to be processed.
  1859  	time.Sleep(500 * time.Millisecond)
  1860  
  1861  	// Repeating the test should now pick the former server consistently.
  1862  	for i := 0; i < 10; i++ {
  1863  		session.Refresh()
  1864  		err = session.Run("serverStatus", &result)
  1865  		c.Assert(err, IsNil)
  1866  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1b))
  1867  	}
  1868  }
  1869  
  1870  func (s *S) TestNearestServer(c *C) {
  1871  	defer mgo.HackPingDelay(300 * time.Millisecond)()
  1872  
  1873  	rs1a := "127.0.0.1:40011"
  1874  	rs1b := "127.0.0.1:40012"
  1875  	rs1c := "127.0.0.1:40013"
  1876  
  1877  	session, err := mgo.Dial(rs1a)
  1878  	c.Assert(err, IsNil)
  1879  	defer session.Close()
  1880  
  1881  	s.Freeze(rs1a)
  1882  	s.Freeze(rs1b)
  1883  
  1884  	// Extra delay to ensure the first two servers get penalized.
  1885  	time.Sleep(500 * time.Millisecond)
  1886  
  1887  	// Release them.
  1888  	s.Thaw(rs1a)
  1889  	s.Thaw(rs1b)
  1890  
  1891  	// Wait for everyone to come up.
  1892  	for len(session.LiveServers()) != 3 {
  1893  		c.Log("Waiting for all servers to be alive...")
  1894  		time.Sleep(100 * time.Millisecond)
  1895  	}
  1896  
  1897  	session.SetMode(mgo.Nearest, true)
  1898  	var result struct{ Host string }
  1899  
  1900  	// See which server picks the line, several times to avoid chance.
  1901  	for i := 0; i < 10; i++ {
  1902  		session.Refresh()
  1903  		err = session.Run("serverStatus", &result)
  1904  		c.Assert(err, IsNil)
  1905  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1c))
  1906  	}
  1907  
  1908  	if *fast {
  1909  		// Don't hold back for several seconds.
  1910  		return
  1911  	}
  1912  
  1913  	// Now hold the two secondaries for long enough to penalize them.
  1914  	s.Freeze(rs1b)
  1915  	s.Freeze(rs1c)
  1916  	time.Sleep(5 * time.Second)
  1917  	s.Thaw(rs1b)
  1918  	s.Thaw(rs1c)
  1919  
  1920  	// Wait for the ping to be processed.
  1921  	time.Sleep(500 * time.Millisecond)
  1922  
  1923  	// Repeating the test should now pick the primary server consistently.
  1924  	for i := 0; i < 10; i++ {
  1925  		session.Refresh()
  1926  		err = session.Run("serverStatus", &result)
  1927  		c.Assert(err, IsNil)
  1928  		c.Assert(hostPort(result.Host), Equals, hostPort(rs1a))
  1929  	}
  1930  }
  1931  
  1932  func (s *S) TestConnectCloseConcurrency(c *C) {
  1933  	restore := mgo.HackPingDelay(500 * time.Millisecond)
  1934  	defer restore()
  1935  	var wg sync.WaitGroup
  1936  	const n = 500
  1937  	wg.Add(n)
  1938  	for i := 0; i < n; i++ {
  1939  		go func() {
  1940  			defer wg.Done()
  1941  			session, err := mgo.Dial("localhost:40001")
  1942  			if err != nil {
  1943  				c.Fatal(err)
  1944  			}
  1945  			time.Sleep(1)
  1946  			session.Close()
  1947  		}()
  1948  	}
  1949  	wg.Wait()
  1950  }
  1951  
  1952  func (s *S) TestSelectServers(c *C) {
  1953  	if !s.versionAtLeast(2, 2) {
  1954  		c.Skip("read preferences introduced in 2.2")
  1955  	}
  1956  
  1957  	session, err := mgo.Dial("localhost:40011")
  1958  	c.Assert(err, IsNil)
  1959  	defer session.Close()
  1960  
  1961  	session.SetMode(mgo.Eventual, true)
  1962  
  1963  	var result struct{ Host string }
  1964  
  1965  	session.Refresh()
  1966  	session.SelectServers(bson.D{{"rs1", "b"}})
  1967  	err = session.Run("serverStatus", &result)
  1968  	c.Assert(err, IsNil)
  1969  	c.Assert(hostPort(result.Host), Equals, "40012")
  1970  
  1971  	session.Refresh()
  1972  	session.SelectServers(bson.D{{"rs1", "c"}})
  1973  	err = session.Run("serverStatus", &result)
  1974  	c.Assert(err, IsNil)
  1975  	c.Assert(hostPort(result.Host), Equals, "40013")
  1976  }
  1977  
  1978  func (s *S) TestSelectServersWithMongos(c *C) {
  1979  	if !s.versionAtLeast(2, 2) {
  1980  		c.Skip("read preferences introduced in 2.2")
  1981  	}
  1982  
  1983  	session, err := mgo.Dial("localhost:40021")
  1984  	c.Assert(err, IsNil)
  1985  	defer session.Close()
  1986  
  1987  	ssresult := &struct{ Host string }{}
  1988  	imresult := &struct{ IsMaster bool }{}
  1989  
  1990  	// Figure the master while still using the strong session.
  1991  	err = session.Run("serverStatus", ssresult)
  1992  	c.Assert(err, IsNil)
  1993  	err = session.Run("isMaster", imresult)
  1994  	c.Assert(err, IsNil)
  1995  	master := ssresult.Host
  1996  	c.Assert(imresult.IsMaster, Equals, true, Commentf("%s is not the master", master))
  1997  
  1998  	var slave1, slave2 string
  1999  	switch hostPort(master) {
  2000  	case "40021":
  2001  		slave1, slave2 = "b", "c"
  2002  	case "40022":
  2003  		slave1, slave2 = "a", "c"
  2004  	case "40023":
  2005  		slave1, slave2 = "a", "b"
  2006  	}
  2007  
  2008  	// Collect op counters for everyone.
  2009  	q21a := s.countQueries(c, "localhost:40021")
  2010  	q22a := s.countQueries(c, "localhost:40022")
  2011  	q23a := s.countQueries(c, "localhost:40023")
  2012  
  2013  	// Do a SlaveOk query through MongoS
  2014  	mongos, err := mgo.Dial("localhost:40202")
  2015  	c.Assert(err, IsNil)
  2016  	defer mongos.Close()
  2017  
  2018  	mongos.SetMode(mgo.Monotonic, true)
  2019  
  2020  	mongos.Refresh()
  2021  	mongos.SelectServers(bson.D{{"rs2", slave1}})
  2022  	coll := mongos.DB("mydb").C("mycoll")
  2023  	result := &struct{}{}
  2024  	for i := 0; i != 5; i++ {
  2025  		err := coll.Find(nil).One(result)
  2026  		c.Assert(err, Equals, mgo.ErrNotFound)
  2027  	}
  2028  
  2029  	mongos.Refresh()
  2030  	mongos.SelectServers(bson.D{{"rs2", slave2}})
  2031  	coll = mongos.DB("mydb").C("mycoll")
  2032  	for i := 0; i != 7; i++ {
  2033  		err := coll.Find(nil).One(result)
  2034  		c.Assert(err, Equals, mgo.ErrNotFound)
  2035  	}
  2036  
  2037  	// Collect op counters for everyone again.
  2038  	q21b := s.countQueries(c, "localhost:40021")
  2039  	q22b := s.countQueries(c, "localhost:40022")
  2040  	q23b := s.countQueries(c, "localhost:40023")
  2041  
  2042  	switch hostPort(master) {
  2043  	case "40021":
  2044  		c.Check(q21b-q21a, Equals, 0)
  2045  		c.Check(q22b-q22a, Equals, 5)
  2046  		c.Check(q23b-q23a, Equals, 7)
  2047  	case "40022":
  2048  		c.Check(q21b-q21a, Equals, 5)
  2049  		c.Check(q22b-q22a, Equals, 0)
  2050  		c.Check(q23b-q23a, Equals, 7)
  2051  	case "40023":
  2052  		c.Check(q21b-q21a, Equals, 5)
  2053  		c.Check(q22b-q22a, Equals, 7)
  2054  		c.Check(q23b-q23a, Equals, 0)
  2055  	default:
  2056  		c.Fatal("Uh?")
  2057  	}
  2058  }
  2059  
  2060  func (s *S) TestDoNotFallbackToMonotonic(c *C) {
  2061  	// There was a bug at some point that some functions were
  2062  	// falling back to Monotonic mode. This test ensures all listIndexes
  2063  	// commands go to the primary, as should happen since the session is
  2064  	// in Strong mode.
  2065  	if !s.versionAtLeast(3, 0) {
  2066  		c.Skip("command-counting logic depends on 3.0+")
  2067  	}
  2068  
  2069  	session, err := mgo.Dial("localhost:40012")
  2070  	c.Assert(err, IsNil)
  2071  	defer session.Close()
  2072  
  2073  	for i := 0; i < 15; i++ {
  2074  		q11a := s.countCommands(c, "localhost:40011", "listIndexes")
  2075  		q12a := s.countCommands(c, "localhost:40012", "listIndexes")
  2076  		q13a := s.countCommands(c, "localhost:40013", "listIndexes")
  2077  
  2078  		_, err := session.DB("local").C("system.indexes").Indexes()
  2079  		c.Assert(err, IsNil)
  2080  
  2081  		q11b := s.countCommands(c, "localhost:40011", "listIndexes")
  2082  		q12b := s.countCommands(c, "localhost:40012", "listIndexes")
  2083  		q13b := s.countCommands(c, "localhost:40013", "listIndexes")
  2084  
  2085  		c.Assert(q11b, Equals, q11a+1)
  2086  		c.Assert(q12b, Equals, q12a)
  2087  		c.Assert(q13b, Equals, q13a)
  2088  	}
  2089  }