We have a simple goroutine that subscribes to the topology and then prints some log messages each time it receives an update. One of our tests caught a data race:
03:48:08 Read at 0x00c00153a000 by goroutine 301:
Our code that does "for toplogy := range subscription.C { ... }" and logs details of topology.
03:48:08 Previous write at 0x00c00153a000 by goroutine 130:
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/description.(*serverSorter).Swap()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/description/topology.go:133 +0x149
03:48:08 sort.medianOfThree()
03:48:08 GOROOT/src/sort/sort.go:77 +0x14b
03:48:08 sort.doPivot()
03:48:08 GOROOT/src/sort/sort.go:105 +0x9b
03:48:08 sort.quickSort()
03:48:08 GOROOT/src/sort/sort.go:190 +0xa7
03:48:08 sort.Sort()
03:48:08 GOROOT/src/sort/sort.go:218 +0x8a
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/description.DiffTopology()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/description/topology.go:48 +0xba
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).apply()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/topology.go:540 +0x365
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).addServer.func1()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/topology.go:578 +0xf8
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).updateDescription()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:431 +0x345
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).update()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:381 +0x2cc
03:48:08 Goroutine 130 (running) created at:
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).Connect()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:170 +0x160
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.ConnectServer()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:113 +0x9d
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).addServer()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/topology.go:580 +0x181
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).apply()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/topology.go:554 +0x5e9
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Topology).addServer.func1()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/topology.go:578 +0xf8
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).updateDescription()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:431 +0x345
03:48:08 go.mongodb.org/mongo-driver/x/mongo/driver/topology.(*Server).update()
03:48:08 external/org_mongodb_go_mongo_driver/x/mongo/driver/topology/server.go:381 +0x2cc
I think what's happening is that Topology.apply is calling description.DiffTopology, which sorts in-place, on t.fsm.Topology, but it's still the case that a previous topology subscriber (i.e. our code) is running, presumably in response to a previous topology update. It feels like a bug that description.DiffTopology sorts in-place, though I don't think changing that would be sufficient, since fsm.go itself mutates Servers as well.