@@ -222,6 +222,93 @@ async def test_pool_disconnect(self, master_host):
222222 await pool .disconnect (inuse_connections = False )
223223 assert conn .is_connected
224224
225+ async def test_lock_not_held_during_connection_establishment (self ):
226+ """
227+ Test that the connection pool lock is not held during the
228+ ensure_connection call, which involves socket connection and handshake.
229+ This is important for performance under high load.
230+ """
231+
232+ class SlowConnectConnection (DummyConnection ):
233+ """Connection that simulates slow connection establishment"""
234+
235+ def __init__ (self , ** kwargs ):
236+ super ().__init__ (** kwargs )
237+ self .connect_called = False
238+ self .lock_held_during_connect = None
239+
240+ async def connect (self ):
241+ self .connect_called = True
242+ # Check if the pool's lock is held during connection
243+ pool = self .kwargs .get ("_pool" )
244+ if pool :
245+ self .lock_held_during_connect = pool ._lock .locked ()
246+ # Simulate slow connection
247+ await asyncio .sleep (0.01 )
248+ self ._connected = True
249+
250+ async with self .get_pool (
251+ connection_class = SlowConnectConnection ,
252+ connection_kwargs = {"_pool" : None },
253+ ) as pool :
254+ # Pass the pool to the connection so it can check lock status
255+ pool .connection_kwargs ["_pool" ] = pool
256+
257+ # Get a connection - this should call connect() outside the lock
258+ connection = await pool .get_connection ()
259+
260+ # Verify connect was called
261+ assert connection .connect_called
262+
263+ # Verify the lock was NOT held during connect
264+ assert (
265+ connection .lock_held_during_connect is False
266+ ), "Lock should not be held during connection establishment"
267+
268+ await pool .release (connection )
269+
270+ async def test_concurrent_connection_acquisition_performance (self ):
271+ """
272+ Test that multiple concurrent connection acquisitions don't block
273+ each other during connection establishment.
274+ """
275+
276+ class SlowConnectConnection (DummyConnection ):
277+ """Connection that simulates slow connection establishment"""
278+
279+ async def connect (self ):
280+ # Simulate slow connection (e.g., network latency, TLS handshake)
281+ await asyncio .sleep (0.05 )
282+ self ._connected = True
283+
284+ async with self .get_pool (
285+ connection_class = SlowConnectConnection , max_connections = 10
286+ ) as pool :
287+ # Start acquiring multiple connections concurrently
288+ start_time = asyncio .get_running_loop ().time ()
289+
290+ # Try to get 3 connections concurrently
291+ connections = await asyncio .gather (
292+ pool .get_connection (),
293+ pool .get_connection (),
294+ pool .get_connection (),
295+ )
296+
297+ elapsed_time = asyncio .get_running_loop ().time () - start_time
298+
299+ # With proper lock handling, these should complete mostly in parallel
300+ # If the lock was held during connect(), it would take 3 * 0.05 = 0.15s
301+ # With lock only during pop, it should take ~0.05s (connections in parallel)
302+ # We allow some overhead, so check it's less than 0.12s
303+ assert elapsed_time < 0.12 , (
304+ f"Concurrent connections took { elapsed_time } s, "
305+ f"suggesting lock was held during connection establishment"
306+ )
307+
308+ # Clean up
309+ for conn in connections :
310+ await pool .release (conn )
311+
225312
226313class TestBlockingConnectionPool :
227314 @asynccontextmanager
0 commit comments