Skip to content

Commit

Permalink
Add a test for globalsign#120
Browse files Browse the repository at this point in the history
We've seen a deadlock happen occasionally where syncServers needs to
acquire a socket to call isMaster, but the socket acquisition needs to
know the server topology which isn't known yet. See globalsign#120
issue for a detailed breakdown.

This replicates the issue by setting up a mongo "server" which closes
sockets as soon as they're opened; about 20% of the time, this will
trigger the deadlock because the acquired socket for ismaster() dies and
needs to be reacquired.
  • Loading branch information
KJTsanaktsidis committed Mar 12, 2018
1 parent c8fc2eb commit 08c5182
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,41 @@ func (s *S) TestConnectCloseConcurrency(c *C) {
wg.Wait()
}

func (s *S) TestNoDeadlockOnClose(c *C) {
if *fast {
// Unfortunately I seem to need quite a high dial timeout to get this to work
// on my machine.
c.Skip("-fast")
}

var shouldStop int32
atomic.StoreInt32(&shouldStop, 0)

listener, err := net.Listen("tcp4", "127.0.0.1:")
c.Check(err, Equals, nil)

go func() {
for atomic.LoadInt32(&shouldStop) == 0 {
sock, err := listener.Accept()
if err != nil {
// Probs just closed
continue
}
sock.Close()
}
}()
defer func() {
atomic.StoreInt32(&shouldStop, 1)
listener.Close()
}()

session, err := mgo.DialWithTimeout(listener.Addr().String(), 10*time.Second)
// If execution reaches here, the deadlock did not happen and all is OK
if session != nil {
session.Close()
}
}

func (s *S) TestSelectServers(c *C) {
if !s.versionAtLeast(2, 2) {
c.Skip("read preferences introduced in 2.2")
Expand Down

0 comments on commit 08c5182

Please sign in to comment.