PYTHON-2503 Always use time.monotonic
For monotonic time needs.
This commit is contained in:
parent
e01d9a37e7
commit
cf877e95c7
@ -98,6 +98,7 @@ Classes
|
||||
"""
|
||||
|
||||
import collections
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from collections.abc import Mapping as _Mapping
|
||||
@ -107,7 +108,6 @@ from bson.int64 import Int64
|
||||
from bson.son import SON
|
||||
from bson.timestamp import Timestamp
|
||||
|
||||
from pymongo import monotonic
|
||||
from pymongo.errors import (ConfigurationError,
|
||||
ConnectionFailure,
|
||||
InvalidOperation,
|
||||
@ -336,7 +336,7 @@ _WITH_TRANSACTION_RETRY_TIME_LIMIT = 120
|
||||
|
||||
def _within_time_limit(start_time):
|
||||
"""Are we within the with_transaction retry limit?"""
|
||||
return monotonic.time() - start_time < _WITH_TRANSACTION_RETRY_TIME_LIMIT
|
||||
return time.monotonic() - start_time < _WITH_TRANSACTION_RETRY_TIME_LIMIT
|
||||
|
||||
|
||||
class ClientSession(object):
|
||||
@ -518,7 +518,7 @@ class ClientSession(object):
|
||||
|
||||
.. versionadded:: 3.9
|
||||
"""
|
||||
start_time = monotonic.time()
|
||||
start_time = time.monotonic()
|
||||
while True:
|
||||
self.start_transaction(
|
||||
read_concern, write_concern, read_preference,
|
||||
@ -797,7 +797,7 @@ class ClientSession(object):
|
||||
def _apply_to(self, command, is_retryable, read_preference):
|
||||
self._check_ended()
|
||||
|
||||
self._server_session.last_use = monotonic.time()
|
||||
self._server_session.last_use = time.monotonic()
|
||||
command['lsid'] = self._server_session.session_id
|
||||
|
||||
if not self.in_transaction:
|
||||
@ -842,7 +842,7 @@ class _ServerSession(object):
|
||||
def __init__(self, generation):
|
||||
# Ensure id is type 4, regardless of CodecOptions.uuid_representation.
|
||||
self.session_id = {'id': Binary(uuid.uuid4().bytes, 4)}
|
||||
self.last_use = monotonic.time()
|
||||
self.last_use = time.monotonic()
|
||||
self._transaction_id = 0
|
||||
self.dirty = False
|
||||
self.generation = generation
|
||||
@ -856,7 +856,7 @@ class _ServerSession(object):
|
||||
self.dirty = True
|
||||
|
||||
def timed_out(self, session_timeout_minutes):
|
||||
idle_seconds = monotonic.time() - self.last_use
|
||||
idle_seconds = time.monotonic() - self.last_use
|
||||
|
||||
# Timed out if we have less than a minute to live.
|
||||
return idle_seconds > (session_timeout_minutes - 1) * 60
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
import atexit
|
||||
import threading
|
||||
import time
|
||||
import weakref
|
||||
|
||||
from pymongo import common, periodic_executor
|
||||
@ -23,7 +24,6 @@ from pymongo.errors import (NotMasterError,
|
||||
OperationFailure,
|
||||
_OperationCancelled)
|
||||
from pymongo.ismaster import IsMaster
|
||||
from pymongo.monotonic import time as _time
|
||||
from pymongo.periodic_executor import _shutdown_executors
|
||||
from pymongo.read_preferences import MovingAverage
|
||||
from pymongo.server_description import ServerDescription
|
||||
@ -208,7 +208,7 @@ class Monitor(MonitorBase):
|
||||
|
||||
Returns a ServerDescription.
|
||||
"""
|
||||
start = _time()
|
||||
start = time.monotonic()
|
||||
try:
|
||||
try:
|
||||
return self._check_once()
|
||||
@ -223,7 +223,7 @@ class Monitor(MonitorBase):
|
||||
_sanitize(error)
|
||||
sd = self._server_description
|
||||
address = sd.address
|
||||
duration = _time() - start
|
||||
duration = time.monotonic() - start
|
||||
if self._publish:
|
||||
awaited = sd.is_server_type_known and sd.topology_version
|
||||
self._listeners.publish_server_heartbeat_failed(
|
||||
@ -265,7 +265,7 @@ class Monitor(MonitorBase):
|
||||
Can raise ConnectionFailure or OperationFailure.
|
||||
"""
|
||||
cluster_time = self._topology.max_cluster_time()
|
||||
start = _time()
|
||||
start = time.monotonic()
|
||||
if conn.more_to_come:
|
||||
# Read the next streaming isMaster (MongoDB 4.4+).
|
||||
response = IsMaster(conn._next_reply(), awaitable=True)
|
||||
@ -280,7 +280,7 @@ class Monitor(MonitorBase):
|
||||
else:
|
||||
# New connection handshake or polling isMaster (MongoDB <4.4).
|
||||
response = conn._ismaster(cluster_time, None, None, None)
|
||||
return response, _time() - start
|
||||
return response, time.monotonic() - start
|
||||
|
||||
|
||||
class SrvMonitor(MonitorBase):
|
||||
@ -388,9 +388,9 @@ class _RttMonitor(MonitorBase):
|
||||
with self._pool.get_socket({}) as sock_info:
|
||||
if self._executor._stopped:
|
||||
raise Exception('_RttMonitor closed')
|
||||
start = _time()
|
||||
start = time.monotonic()
|
||||
sock_info.ismaster()
|
||||
return _time() - start
|
||||
return time.monotonic() - start
|
||||
|
||||
|
||||
# Close monitors to cancel any in progress streaming checks before joining
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
# Copyright 2014-2015 MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Time. Monotonic if possible.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__all__ = ['time']
|
||||
|
||||
try:
|
||||
# Patches standard time module.
|
||||
# From https://pypi.python.org/pypi/Monotime.
|
||||
import monotime
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# From https://pypi.python.org/pypi/monotonic.
|
||||
from monotonic import monotonic as time
|
||||
except ImportError:
|
||||
try:
|
||||
# Monotime or Python 3.
|
||||
from time import monotonic as time
|
||||
except ImportError:
|
||||
# Not monotonic.
|
||||
from time import time
|
||||
@ -18,6 +18,7 @@ import datetime
|
||||
import errno
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
|
||||
|
||||
from bson import _decode_all_selective
|
||||
@ -31,7 +32,6 @@ from pymongo.errors import (AutoReconnect,
|
||||
ProtocolError,
|
||||
_OperationCancelled)
|
||||
from pymongo.message import _UNPACK_REPLY, _OpMsg
|
||||
from pymongo.monotonic import time
|
||||
from pymongo.socket_checker import _errno_from_exception
|
||||
|
||||
|
||||
@ -185,7 +185,7 @@ def receive_message(sock_info, request_id, max_message_size=MAX_MESSAGE_SIZE):
|
||||
"""Receive a raw BSON message or raise socket.error."""
|
||||
timeout = sock_info.sock.gettimeout()
|
||||
if timeout:
|
||||
deadline = time() + timeout
|
||||
deadline = time.monotonic() + timeout
|
||||
else:
|
||||
deadline = None
|
||||
# Ignore the response's request id.
|
||||
@ -236,7 +236,7 @@ def wait_for_read(sock_info, deadline):
|
||||
# Wait up to 500ms for the socket to become readable and then
|
||||
# check for cancellation.
|
||||
if deadline:
|
||||
timeout = max(min(deadline - time(), _POLL_TIMEOUT), 0.001)
|
||||
timeout = max(min(deadline - time.monotonic(), _POLL_TIMEOUT), 0.001)
|
||||
else:
|
||||
timeout = _POLL_TIMEOUT
|
||||
readable = sock_info.socket_checker.select(
|
||||
@ -245,7 +245,7 @@ def wait_for_read(sock_info, deadline):
|
||||
raise _OperationCancelled('isMaster cancelled')
|
||||
if readable:
|
||||
return
|
||||
if deadline and time() > deadline:
|
||||
if deadline and time.monotonic() > deadline:
|
||||
raise socket.timeout("timed out")
|
||||
|
||||
def _receive_data_on_socket(sock_info, length, deadline):
|
||||
|
||||
@ -18,8 +18,6 @@ import threading
|
||||
import time
|
||||
import weakref
|
||||
|
||||
from pymongo.monotonic import time as _time
|
||||
|
||||
|
||||
class PeriodicExecutor(object):
|
||||
def __init__(self, interval, min_interval, target, name=None):
|
||||
@ -135,8 +133,8 @@ class PeriodicExecutor(object):
|
||||
if self._skip_sleep:
|
||||
self._skip_sleep = False
|
||||
else:
|
||||
deadline = _time() + self._interval
|
||||
while not self._stopped and _time() < deadline:
|
||||
deadline = time.monotonic() + self._interval
|
||||
while not self._stopped and time.monotonic() < deadline:
|
||||
time.sleep(self._min_interval)
|
||||
if self._event:
|
||||
break # Early wake.
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
# implied. See the License for the specific language governing
|
||||
# permissions and limitations under the License.
|
||||
|
||||
import collections
|
||||
import contextlib
|
||||
import copy
|
||||
import ipaddress
|
||||
@ -20,7 +21,7 @@ import platform
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import collections
|
||||
import time
|
||||
|
||||
from bson import DEFAULT_CODEC_OPTIONS
|
||||
from bson.son import SON
|
||||
@ -48,7 +49,6 @@ from pymongo.errors import (AutoReconnect,
|
||||
OperationFailure,
|
||||
PyMongoError)
|
||||
from pymongo.ismaster import IsMaster
|
||||
from pymongo.monotonic import time as _time
|
||||
from pymongo.monitoring import (ConnectionCheckOutFailedReason,
|
||||
ConnectionClosedReason)
|
||||
from pymongo.network import (command,
|
||||
@ -250,7 +250,7 @@ def _raise_connection_failure(address, error, msg_prefix=None):
|
||||
|
||||
|
||||
def _cond_wait(condition, deadline):
|
||||
timeout = deadline - _time() if deadline else None
|
||||
timeout = deadline - time.monotonic() if deadline else None
|
||||
return condition.wait(timeout)
|
||||
|
||||
|
||||
@ -502,7 +502,7 @@ class SocketInfo(object):
|
||||
self.id = id
|
||||
self.authset = set()
|
||||
self.closed = False
|
||||
self.last_checkin_time = _time()
|
||||
self.last_checkin_time = time.monotonic()
|
||||
self.performed_handshake = False
|
||||
self.is_writable = False
|
||||
self.max_wire_version = MAX_WIRE_VERSION
|
||||
@ -862,14 +862,14 @@ class SocketInfo(object):
|
||||
_add_to_command(command, self.opts.server_api)
|
||||
|
||||
def update_last_checkin_time(self):
|
||||
self.last_checkin_time = _time()
|
||||
self.last_checkin_time = time.monotonic()
|
||||
|
||||
def update_is_writable(self, is_writable):
|
||||
self.is_writable = is_writable
|
||||
|
||||
def idle_time_seconds(self):
|
||||
"""Seconds since this socket was last checked into its pool."""
|
||||
return _time() - self.last_checkin_time
|
||||
return time.monotonic() - self.last_checkin_time
|
||||
|
||||
def _raise_connection_failure(self, error):
|
||||
# Catch *all* exceptions from socket methods and close the socket. In
|
||||
@ -1336,7 +1336,7 @@ class Pool:
|
||||
|
||||
# Get a free socket or create one.
|
||||
if self.opts.wait_queue_timeout:
|
||||
deadline = _time() + self.opts.wait_queue_timeout
|
||||
deadline = time.monotonic() + self.opts.wait_queue_timeout
|
||||
else:
|
||||
deadline = None
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ context.
|
||||
|
||||
import socket as _socket
|
||||
import ssl as _stdlibssl
|
||||
import time
|
||||
|
||||
from errno import EINTR as _EINTR
|
||||
|
||||
@ -33,7 +34,6 @@ from service_identity import (
|
||||
VerificationError as _SIVerificationError)
|
||||
|
||||
from pymongo.errors import CertificateError as _CertificateError
|
||||
from pymongo.monotonic import time as _time
|
||||
from pymongo.ocsp_support import (
|
||||
_load_trusted_ca_certs,
|
||||
_ocsp_callback)
|
||||
@ -98,14 +98,14 @@ class _sslConn(_SSL.Connection):
|
||||
def _call(self, call, *args, **kwargs):
|
||||
timeout = self.gettimeout()
|
||||
if timeout:
|
||||
start = _time()
|
||||
start = time.monotonic()
|
||||
while True:
|
||||
try:
|
||||
return call(*args, **kwargs)
|
||||
except _RETRY_ERRORS:
|
||||
self.socket_checker.select(
|
||||
self, True, True, timeout)
|
||||
if timeout and _time() - start > timeout:
|
||||
if timeout and time.monotonic() - start > timeout:
|
||||
raise _socket.timeout("timed out")
|
||||
continue
|
||||
|
||||
|
||||
@ -14,10 +14,11 @@
|
||||
|
||||
"""Represent one server the driver is connected to."""
|
||||
|
||||
import time
|
||||
|
||||
from bson import EPOCH_NAIVE
|
||||
from pymongo.server_type import SERVER_TYPE
|
||||
from pymongo.ismaster import IsMaster
|
||||
from pymongo.monotonic import time as _time
|
||||
|
||||
|
||||
class ServerDescription(object):
|
||||
@ -67,7 +68,7 @@ class ServerDescription(object):
|
||||
self._ls_timeout_minutes = ismaster.logical_session_timeout_minutes
|
||||
self._round_trip_time = round_trip_time
|
||||
self._me = ismaster.me
|
||||
self._last_update_time = _time()
|
||||
self._last_update_time = time.monotonic()
|
||||
self._error = error
|
||||
self._topology_version = ismaster.topology_version
|
||||
if error:
|
||||
|
||||
@ -18,17 +18,14 @@ import os
|
||||
import queue
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
import warnings
|
||||
import weakref
|
||||
|
||||
from pymongo import (common,
|
||||
helpers,
|
||||
periodic_executor)
|
||||
from pymongo.pool import PoolOptions
|
||||
from pymongo.topology_description import (updated_topology_description,
|
||||
_updated_topology_description_srv_polling,
|
||||
TopologyDescription,
|
||||
SRV_POLLING_TOPOLOGIES, TOPOLOGY_TYPE)
|
||||
from pymongo.client_session import _ServerSessionPool
|
||||
from pymongo.errors import (ConnectionFailure,
|
||||
ConfigurationError,
|
||||
NetworkTimeout,
|
||||
@ -37,7 +34,7 @@ from pymongo.errors import (ConnectionFailure,
|
||||
PyMongoError,
|
||||
ServerSelectionTimeoutError)
|
||||
from pymongo.monitor import SrvMonitor
|
||||
from pymongo.monotonic import time as _time
|
||||
from pymongo.pool import PoolOptions
|
||||
from pymongo.server import Server
|
||||
from pymongo.server_description import ServerDescription
|
||||
from pymongo.server_selectors import (any_server_selector,
|
||||
@ -46,7 +43,10 @@ from pymongo.server_selectors import (any_server_selector,
|
||||
readable_server_selector,
|
||||
writable_server_selector,
|
||||
Selection)
|
||||
from pymongo.client_session import _ServerSessionPool
|
||||
from pymongo.topology_description import (updated_topology_description,
|
||||
_updated_topology_description_srv_polling,
|
||||
TopologyDescription,
|
||||
SRV_POLLING_TOPOLOGIES, TOPOLOGY_TYPE)
|
||||
|
||||
|
||||
def process_events_queue(queue_ref):
|
||||
@ -200,7 +200,7 @@ class Topology(object):
|
||||
|
||||
def _select_servers_loop(self, selector, timeout, address):
|
||||
"""select_servers() guts. Hold the lock when calling this."""
|
||||
now = _time()
|
||||
now = time.monotonic()
|
||||
end_time = now + timeout
|
||||
server_descriptions = self._description.apply_selector(
|
||||
selector, address, custom_selector=self._settings.server_selector)
|
||||
@ -221,7 +221,7 @@ class Topology(object):
|
||||
# held the lock until now.
|
||||
self._condition.wait(common.MIN_HEARTBEAT_INTERVAL)
|
||||
self._description.check_compatible()
|
||||
now = _time()
|
||||
now = time.monotonic()
|
||||
server_descriptions = self._description.apply_selector(
|
||||
selector, address,
|
||||
custom_selector=self._settings.server_selector)
|
||||
|
||||
@ -18,6 +18,7 @@ import multiprocessing as mp
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import warnings
|
||||
|
||||
try:
|
||||
@ -31,7 +32,6 @@ from bson import decode, encode
|
||||
from bson.json_util import loads
|
||||
from gridfs import GridFSBucket
|
||||
from pymongo import MongoClient
|
||||
from pymongo.monotonic import time
|
||||
from test import client_context, host, port, unittest
|
||||
|
||||
NUM_ITERATIONS = 100
|
||||
@ -59,11 +59,11 @@ def tearDownModule():
|
||||
|
||||
class Timer(object):
|
||||
def __enter__(self):
|
||||
self.start = time()
|
||||
self.start = time.monotonic()
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.end = time()
|
||||
self.end = time.monotonic()
|
||||
self.interval = self.end - self.start
|
||||
|
||||
|
||||
@ -107,10 +107,10 @@ class PerformanceTest(object):
|
||||
|
||||
def runTest(self):
|
||||
results = []
|
||||
start = time()
|
||||
start = time.monotonic()
|
||||
self.max_iterations = NUM_ITERATIONS
|
||||
for i in range(NUM_ITERATIONS):
|
||||
if time() - start > MAX_ITERATION_TIME:
|
||||
if time.monotonic() - start > MAX_ITERATION_TIME:
|
||||
warnings.warn('Test timed out, completed %s iterations.' % i)
|
||||
break
|
||||
self.before()
|
||||
|
||||
@ -53,7 +53,6 @@ from pymongo.errors import (AutoReconnect,
|
||||
from pymongo.monitoring import (ServerHeartbeatListener,
|
||||
ServerHeartbeatStartedEvent)
|
||||
from pymongo.mongo_client import MongoClient
|
||||
from pymongo.monotonic import time as monotonic_time
|
||||
from pymongo.driver_info import DriverInfo
|
||||
from pymongo.pool import SocketInfo, _METADATA
|
||||
from pymongo.read_preferences import ReadPreference
|
||||
@ -1549,9 +1548,9 @@ class TestClient(IntegrationTest):
|
||||
|
||||
# Assert that application operations do not block.
|
||||
for _ in range(10):
|
||||
start = monotonic_time()
|
||||
start = time.monotonic()
|
||||
client.admin.command('ping')
|
||||
total = monotonic_time() - start
|
||||
total = time.monotonic() - start
|
||||
# Each ping command should not take more than 2 seconds
|
||||
self.assertLess(total, 2)
|
||||
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
# Copyright 2018-present MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Test the monotonic module."""
|
||||
|
||||
import sys
|
||||
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
from pymongo.monotonic import time as pymongo_time
|
||||
|
||||
from test import unittest
|
||||
|
||||
|
||||
class TestMonotonic(unittest.TestCase):
|
||||
def test_monotonic_time(self):
|
||||
try:
|
||||
from monotonic import monotonic
|
||||
self.assertIs(monotonic, pymongo_time)
|
||||
except ImportError:
|
||||
if sys.version_info[:2] >= (3, 3):
|
||||
from time import monotonic
|
||||
self.assertIs(monotonic, pymongo_time)
|
||||
else:
|
||||
from time import time
|
||||
self.assertIs(time, pymongo_time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -17,6 +17,7 @@
|
||||
import copy
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
@ -27,7 +28,6 @@ from pymongo.common import _MAX_END_SESSIONS
|
||||
from pymongo.errors import (ConfigurationError,
|
||||
InvalidOperation,
|
||||
OperationFailure)
|
||||
from pymongo.monotonic import time as _time
|
||||
from pymongo.read_concern import ReadConcern
|
||||
from test import IntegrationTest, client_context, db_user, db_pwd, unittest, SkipTest
|
||||
from test.utils import (ignore_deprecations,
|
||||
@ -108,7 +108,7 @@ class TestSession(IntegrationTest):
|
||||
for f, args, kw in ops:
|
||||
with client.start_session() as s:
|
||||
last_use = s._server_session.last_use
|
||||
start = _time()
|
||||
start = time.monotonic()
|
||||
self.assertLessEqual(last_use, start)
|
||||
listener.results.clear()
|
||||
# In case "f" modifies its inputs.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user