summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/pool
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-10-07 08:42:48 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2020-10-07 09:14:13 -0400
commit0220b58917b5a979891b5765f6ac5095e0368489 (patch)
tree2c914e75af50484b8e88603cfeab418e900fe4f2 /lib/sqlalchemy/pool
parentfc643ae73009e91e2dcff9ef57fb7dc0e48df88b (diff)
downloadsqlalchemy-0220b58917b5a979891b5765f6ac5095e0368489.tar.gz
Use monotonic time for pool age measurement
The internal clock used by the :class:`_pool.Pool` object is now time.monotonic_time() under Python 3. Under Python 2, time.time() is still used, which is legacy. This clock is used to measure the age of a connection against its starttime, and used in comparisons against the pool_timeout setting as well as the last time the pool was marked as invalid to determine if the connection should be recycled. Previously, time.time() was used which was subject to inaccuracies as a result of system clock changes as well as poor time resolution on windows. Change-Id: I94f90044c1809508e26a5a00134981c2a00d0405
Diffstat (limited to 'lib/sqlalchemy/pool')
-rw-r--r--lib/sqlalchemy/pool/base.py26
1 files changed, 9 insertions, 17 deletions
diff --git a/lib/sqlalchemy/pool/base.py b/lib/sqlalchemy/pool/base.py
index 87383fef7..2f1959f7c 100644
--- a/lib/sqlalchemy/pool/base.py
+++ b/lib/sqlalchemy/pool/base.py
@@ -11,16 +11,15 @@
"""
from collections import deque
-import time
import weakref
from .. import event
from .. import exc
from .. import log
from .. import util
+from ..util import monotonic_time
from ..util import threading
-
reset_rollback = util.symbol("reset_rollback")
reset_commit = util.symbol("reset_commit")
reset_none = util.symbol("reset_none")
@@ -261,7 +260,7 @@ class Pool(log.Identified):
"""
rec = getattr(connection, "_connection_record", None)
if not rec or self._invalidate_time < rec.starttime:
- self._invalidate_time = time.time()
+ self._invalidate_time = monotonic_time()
if _checkin and getattr(connection, "is_valid", False):
connection.invalidate(exception)
@@ -510,7 +509,7 @@ class _ConnectionRecord(object):
self.connection,
)
if soft:
- self._soft_invalidate_time = time.time()
+ self._soft_invalidate_time = monotonic_time()
else:
self.__close()
self.connection = None
@@ -519,23 +518,16 @@ class _ConnectionRecord(object):
recycle = False
# NOTE: the various comparisons here are assuming that measurable time
- # passes between these state changes. however, time.time() is not
- # guaranteed to have sub-second precision. comparisons of
- # "invalidation time" to "starttime" should perhaps use >= so that the
- # state change can take place assuming no measurable time has passed,
- # however this does not guarantee correct behavior here as if time
- # continues to not pass, it will try to reconnect repeatedly until
- # these timestamps diverge, so in that sense using > is safer. Per
- # https://stackoverflow.com/a/1938096/34549, Windows time.time() may be
- # within 16 milliseconds accuracy, so unit tests for connection
- # invalidation need a sleep of at least this long between initial start
- # time and invalidation for the logic below to work reliably.
+ # passes between these state changes. on Python 2, we are still using
+ # time.time() which is not guaranteed to have millisecondsecond
+ # precision, i.e. on Windows. For Python 3 we now use monotonic_time().
+
if self.connection is None:
self.info.clear()
self.__connect()
elif (
self.__pool._recycle > -1
- and time.time() - self.starttime > self.__pool._recycle
+ and monotonic_time() - self.starttime > self.__pool._recycle
):
self.__pool.logger.info(
"Connection %r exceeded timeout; recycling", self.connection
@@ -577,7 +569,7 @@ class _ConnectionRecord(object):
# creator fails, this attribute stays None
self.connection = None
try:
- self.starttime = time.time()
+ self.starttime = monotonic_time()
connection = pool._invoke_creator(self)
pool.logger.debug("Created new connection %r", connection)
self.connection = connection