@@ -732,7 +732,9 @@ def __init__(
732732 # and returned to pool from the left side. Stale sockets removed
733733 # from the right side.
734734 self .conns : collections .deque [AsyncConnection ] = collections .deque ()
735+ self ._conns_lock = _async_create_lock ()
735736 self .active_contexts : set [_CancellationContext ] = set ()
737+ self ._active_contexts_lock = _async_create_lock ()
736738 # The main lock for the pool. The lock should only be used to protect
737739 # updating attributes.
738740 # If possible, avoid any additional work while holding the lock.
@@ -795,6 +797,7 @@ def __init__(
795797 )
796798 # Similar to active_sockets but includes threads in the wait queue.
797799 self .operation_count : int = 0
800+ self ._operation_count_lock = _async_create_lock ()
798801 # Retain references to pinned connections to prevent the CPython GC
799802 # from thinking that a cursor's pinned connection can be GC'd when the
800803 # cursor is GC'd (see PYTHON-2751).
@@ -837,23 +840,23 @@ async def _reset(
837840 old_state = self .state
838841 if self .closed :
839842 return
840- if self .opts .pause_enabled and pause and not self .opts .load_balanced :
841- async with self .lock :
842- old_state , self .state = self .state , PoolState .PAUSED
843843
844844 with self .lock :
845+ if self .opts .pause_enabled and pause and not self .opts .load_balanced :
846+ old_state , self .state = self .state , PoolState .PAUSED
845847 self .gen .inc (service_id )
846- newpid = os .getpid ()
847- if self .pid != newpid :
848- self .pid = newpid
849- with self .lock :
848+ newpid = os .getpid ()
849+
850+ if self .pid != newpid :
851+ self .pid = newpid
852+
850853 self .active_sockets = 0
854+ with self ._conns_lock :
855+ if service_id is None :
856+ sockets , self .conns = self .conns , collections .deque ()
857+ with self ._operation_count_lock :
851858 self .operation_count = 0
852- if service_id is None :
853- new_conns = collections .deque ()
854- with self .lock :
855- sockets , self .conns = self .conns , new_conns
856- else :
859+ if service_id is not None :
857860 discard : collections .deque = collections .deque () # type: ignore[type-arg]
858861 keep : collections .deque = collections .deque () # type: ignore[type-arg]
859862 for conn in self .conns .copy ():
@@ -862,7 +865,7 @@ async def _reset(
862865 else :
863866 keep .append (conn )
864867 sockets = discard
865- with self .lock :
868+ with self ._conns_lock :
866869 self .conns = keep
867870
868871 if close :
@@ -1000,8 +1003,9 @@ async def remove_stale_sockets(self, reference_generation: int) -> None:
10001003 if self .gen .get_overall () != reference_generation :
10011004 close_conn = True
10021005 if not close_conn :
1003- async with self .lock :
1006+ async with self ._conns_lock :
10041007 self .conns .appendleft (conn )
1008+ async with self ._active_contexts_lock :
10051009 self .active_contexts .discard (conn .cancel_context )
10061010 if close_conn :
10071011 await conn .close_conn (ConnectionClosedReason .STALE )
@@ -1028,7 +1032,7 @@ async def connect(self, handler: Optional[_MongoClientErrorHandler] = None) -> A
10281032 # Use a temporary context so that interrupt_connections can cancel creating the socket.
10291033 tmp_context = _CancellationContext ()
10301034 conn_id = self .next_connection_id
1031- async with self .lock :
1035+ async with self ._active_contexts_lock :
10321036 self .next_connection_id += 1
10331037 self .active_contexts .add (tmp_context )
10341038
@@ -1050,7 +1054,7 @@ async def connect(self, handler: Optional[_MongoClientErrorHandler] = None) -> A
10501054 networking_interface = await _configured_protocol_interface (self .address , self .opts )
10511055 # Catch KeyboardInterrupt, CancelledError, etc. and cleanup.
10521056 except BaseException as error :
1053- async with self .lock :
1057+ async with self ._active_contexts_lock :
10541058 self .active_contexts .discard (tmp_context )
10551059 if self .enabled_for_cmap :
10561060 assert listeners is not None
@@ -1075,7 +1079,7 @@ async def connect(self, handler: Optional[_MongoClientErrorHandler] = None) -> A
10751079 raise
10761080
10771081 conn = AsyncConnection (networking_interface , self , self .address , conn_id , self .is_sdam ) # type: ignore[arg-type]
1078- async with self .lock :
1082+ async with self ._active_contexts_lock :
10791083 self .active_contexts .add (conn .cancel_context )
10801084 self .active_contexts .discard (tmp_context )
10811085 if tmp_context .cancelled :
@@ -1090,7 +1094,7 @@ async def connect(self, handler: Optional[_MongoClientErrorHandler] = None) -> A
10901094 await conn .authenticate ()
10911095 # Catch KeyboardInterrupt, CancelledError, etc. and cleanup.
10921096 except BaseException :
1093- async with self .lock :
1097+ async with self ._active_contexts_lock :
10941098 self .active_contexts .discard (conn .cancel_context )
10951099 await conn .close_conn (ConnectionClosedReason .ERROR )
10961100 raise
@@ -1150,7 +1154,7 @@ async def checkout(
11501154 durationMS = duration ,
11511155 )
11521156 try :
1153- async with self .lock :
1157+ async with self ._active_contexts_lock :
11541158 self .active_contexts .add (conn .cancel_context )
11551159 yield conn
11561160 # Catch KeyboardInterrupt, CancelledError, etc. and cleanup.
@@ -1169,11 +1173,11 @@ async def checkout(
11691173 await self .checkin (conn )
11701174 raise
11711175 if conn .pinned_txn :
1172- async with self .lock :
1176+ async with self ._active_contexts_lock :
11731177 self .__pinned_sockets .add (conn )
11741178 self .ntxns += 1
11751179 elif conn .pinned_cursor :
1176- async with self .lock :
1180+ async with self ._active_contexts_lock :
11771181 self .__pinned_sockets .add (conn )
11781182 self .ncursors += 1
11791183 elif conn .active :
@@ -1237,7 +1241,7 @@ async def _get_conn(
12371241 "Attempted to check out a connection from closed connection pool"
12381242 )
12391243
1240- async with self .lock :
1244+ async with self ._operation_count_lock :
12411245 self .operation_count += 1
12421246
12431247 # Get a free socket or create one.
@@ -1286,7 +1290,7 @@ async def _get_conn(
12861290 self ._raise_if_not_ready (checkout_started_time , emit_event = False )
12871291
12881292 try :
1289- async with self .lock :
1293+ async with self ._conns_lock :
12901294 conn = self .conns .popleft ()
12911295 except IndexError :
12921296 self ._pending += 1
@@ -1346,10 +1350,9 @@ async def checkin(self, conn: AsyncConnection) -> None:
13461350 conn .active = False
13471351 conn .pinned_txn = False
13481352 conn .pinned_cursor = False
1349- async with self .lock :
1350- self .__pinned_sockets .discard (conn )
13511353 listeners = self .opts ._event_listeners
1352- async with self .lock :
1354+ async with self ._active_contexts_lock :
1355+ self .__pinned_sockets .discard (conn )
13531356 self .active_contexts .discard (conn .cancel_context )
13541357 if self .enabled_for_cmap :
13551358 assert listeners is not None
@@ -1393,25 +1396,24 @@ async def checkin(self, conn: AsyncConnection) -> None:
13931396 if self .stale_generation (conn .generation , conn .service_id ):
13941397 close_conn = True
13951398 else :
1396- with self .lock :
1399+ with self ._conns_lock :
13971400 self .conns .appendleft (conn )
13981401 with self ._max_connecting_cond :
13991402 # Notify any threads waiting to create a connection.
14001403 self ._max_connecting_cond .notify ()
14011404 if close_conn :
14021405 await conn .close_conn (ConnectionClosedReason .STALE )
14031406
1404- async with self .lock :
1407+ async with self ._active_contexts_lock :
14051408 self .active_sockets -= 1
1406- self .operation_count -= 1
1407-
1408- if txn :
1409- async with self .lock :
1409+ if txn :
14101410 self .ntxns -= 1
1411- elif cursor :
1412- async with self .lock :
1411+ elif cursor :
14131412 self .ncursors -= 1
14141413
1414+ async with self ._operation_count_lock :
1415+ self .operation_count -= 1
1416+
14151417 async with self .size_cond :
14161418 self .requests -= 1
14171419 self .size_cond .notify ()
0 commit comments