Skip to content

Commit

Permalink
Tune the locking in ConnectionPool.get_connection
Browse files Browse the repository at this point in the history
The lock does not need to be held while waiting for the socket to
establish and validate the TCP connection.
  • Loading branch information
andymccurdy committed May 14, 2020
1 parent fa37b8b commit 32a5840
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
* 3.5.2 (May 14, 2020)
* Tune the locking in ConnectionPool.get_connection so that the lock is
not held while waiting for the socket to establish and validate the
TCP connection.
* 3.5.1 (May 9, 2020)
* Fix for HSET argument validation to allow any non-None key. Thanks
@AleksMat, #1337, #1341
Expand Down
43 changes: 22 additions & 21 deletions redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ def __repr__(self):
)

def reset(self):
self._lock = threading.RLock()
self._lock = threading.Lock()
self._created_connections = 0
self._available_connections = []
self._in_use_connections = set()
Expand Down Expand Up @@ -1177,28 +1177,29 @@ def get_connection(self, command_name, *keys, **options):
except IndexError:
connection = self.make_connection()
self._in_use_connections.add(connection)

try:
# ensure this connection is connected to Redis
connection.connect()
# connections that the pool provides should be ready to send
# a command. if not, the connection was either returned to the
# pool before all data has been read or the socket has been
# closed. either way, reconnect and verify everything is good.
try:
# ensure this connection is connected to Redis
if connection.can_read():
raise ConnectionError('Connection has data')
except ConnectionError:
connection.disconnect()
connection.connect()
# connections that the pool provides should be ready to send
# a command. if not, the connection was either returned to the
# pool before all data has been read or the socket has been
# closed. either way, reconnect and verify everything is good.
try:
if connection.can_read():
raise ConnectionError('Connection has data')
except ConnectionError:
connection.disconnect()
connection.connect()
if connection.can_read():
raise ConnectionError('Connection not ready')
except BaseException:
# release the connection back to the pool so that we don't
# leak it
self.release(connection)
raise

return connection
if connection.can_read():
raise ConnectionError('Connection not ready')
except BaseException:
# release the connection back to the pool so that we don't
# leak it
self.release(connection)
raise

return connection

def get_encoder(self):
"Return an encoder based on encoding settings"
Expand Down

0 comments on commit 32a5840

Please sign in to comment.