@@ -1379,6 +1379,40 @@ def connection():
13791379 assert shared [0 ]._con is con
13801380
13811381
1382+ def test_shared_in_transaction_becoming_idle (dbapi ):
1383+ """Check that a thread waiting for a shared connection survives unshare."""
1384+ pool = PooledDB (dbapi , 0 , 0 , 1 , 0 , True )
1385+ db = pool .connection ()
1386+ con = db ._con
1387+ db .begin ()
1388+ # the only connection that may be shared is in a transaction now
1389+ shared = []
1390+ errors = []
1391+
1392+ def connection ():
1393+ try :
1394+ shared .append (pool .connection ())
1395+ except Exception as error :
1396+ errors .append (error )
1397+
1398+ thread = Thread (target = connection )
1399+ thread .start ()
1400+ thread .join (0.1 )
1401+ # the thread cannot share that connection and blocks instead of failing
1402+ assert thread .is_alive ()
1403+ assert not shared
1404+ # closing the connection takes it out of the shared cache completely,
1405+ # so the waiting thread is woken up to find an empty shared cache;
1406+ # it must then get the connection from the idle cache instead of
1407+ # trying to share a connection that is no longer there
1408+ db .close ()
1409+ thread .join (0.1 )
1410+ assert not thread .is_alive ()
1411+ assert not errors
1412+ assert len (shared ) == 1
1413+ assert shared [0 ]._con is con
1414+
1415+
13821416def test_shared_in_transaction_with_two_connections (dbapi ):
13831417 """Check that sharing prefers connections without a transaction."""
13841418 pool = PooledDB (dbapi , 0 , 2 , 2 )
@@ -1490,26 +1524,45 @@ def test_shared_db_connection_compare(dbapi):
14901524 con1 .con ._transaction = False
14911525 con2 = SharedDBConnection (dbapi .connect ())
14921526 con2 .con ._transaction = False
1493- assert con1 == con2
1494- assert con1 <= con2
1495- assert con1 >= con2
1496- assert not con1 != con2 # noqa: SIM202
1527+ # connections with the same number of shares are ranked equally
14971528 assert not con1 < con2
1498- assert not con1 > con2
1529+ assert not con2 < con1
1530+ # the connection with fewer shares is preferred
14991531 con2 .share ()
1500- assert not con1 == con2 # noqa: SIM201
1532+ assert con1 < con2
1533+ assert not con2 < con1
15011534 assert con1 <= con2
15021535 assert not con1 >= con2
1503- assert con1 != con2
1504- assert con1 < con2
1505- assert not con1 > con2
1536+ # but connections in a transaction always come last
15061537 con1 .con ._transaction = True
1507- assert not con1 == con2 # noqa: SIM201
1508- assert not con1 <= con2
1509- assert con1 >= con2
1510- assert con1 != con2
15111538 assert not con1 < con2
1539+ assert con2 < con1
15121540 assert con1 > con2
1541+ assert not con1 <= con2
1542+
1543+
1544+ def test_shared_db_connection_equality (dbapi ):
1545+ """Check that shared connections are only equal to themselves."""
1546+ con1 = SharedDBConnection (dbapi .connect ())
1547+ con1 .con ._transaction = False
1548+ con2 = SharedDBConnection (dbapi .connect ())
1549+ con2 .con ._transaction = False
1550+ same_as_con1 = con1
1551+ # the ordering only serves to pick the least shared connection,
1552+ # it does not make equally ranked connections interchangeable
1553+ assert con1 == same_as_con1
1554+ assert con1 != con2
1555+ # equal connections must therefore also have equal hash values
1556+ # (this used to be violated, since the equality was based on the
1557+ # values while the hash value was based on the identity)
1558+ assert hash (con1 ) == hash (same_as_con1 )
1559+ assert len ({con1 , con2 , same_as_con1 }) == 2
1560+ # and removing one connection from a list of connections
1561+ # must not remove another connection that is ranked the same
1562+ cache = [con1 , con2 ]
1563+ cache .remove (con2 )
1564+ assert len (cache ) == 1
1565+ assert cache [0 ] is con1
15131566
15141567
15151568def test_shared_db_connection_hash (dbapi ):
@@ -1518,9 +1571,10 @@ def test_shared_db_connection_hash(dbapi):
15181571 con = SharedDBConnection (dbapi .connect ())
15191572 hashed = hash (con )
15201573 assert hash (con ) == hashed
1521- # the hash is derived from the underlying connection and the shares
1574+ # the hash is based on the identity, so it does not change
1575+ # when the number of shares of the connection changes
15221576 con .share ()
1523- assert hash (con ) ! = hashed
1577+ assert hash (con ) = = hashed
15241578 con .unshare ()
15251579 assert hash (con ) == hashed
15261580
0 commit comments