-
Type: Bug
-
Resolution: Done
-
Priority: Blocker - P1
-
Affects Version/s: 3.0
-
Component/s: None
-
None
In certain situations some helper methods could recursively call Pool.get_socket. The example helper is Database.collection_names, which gets a socket from the pool, and passes it to Database._list_collections. _list_collections returns a CommandCursor, which collection_names immediately fully iterates while still holding the original socket. If CommandCursor has to send OP_GET_MORE to the database, a second socket will be required. This can cause a deadlock because Pool._socket_semaphore uses a Lock rather than an RLock (which is correct and not the source of the bug).
Fix collection_names so that it iterates the CommandCursor after returning the original socket, and look for any other methods that might have a similar problem (Collection.options is a likely candidate).
The severity of this bug is limited with MongoDB 3.0+ since the collection count must be very large to require multiple result sets from the server, but can be hit with older versions of MongoDB easily by having more than 101 collections in the database collection_names is called for.