Skip to content

Commit 6d2620a

Browse files
committed
PYTHON-5011 Cleanup
1 parent b77f913 commit 6d2620a

File tree

1 file changed

+69
-87
lines changed

1 file changed

+69
-87
lines changed

pymongo/network_layer.py

Lines changed: 69 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -316,108 +316,90 @@ async def _async_receive(conn: socket.socket, length: int, loop: AbstractEventLo
316316
return mv
317317

318318

319-
if "PyPy" not in sys.version:
320-
321-
def receive_data(conn: Connection, length: int, deadline: Optional[float]) -> memoryview:
322-
buf = bytearray(length)
323-
mv = memoryview(buf)
324-
bytes_read = 0
325-
# To support cancelling a network read, we shorten the socket timeout and
326-
# check for the cancellation signal after each timeout. Alternatively we
327-
# could close the socket but that does not reliably cancel recv() calls
328-
# on all OSes.
329-
orig_timeout = conn.conn.gettimeout()
330-
try:
331-
while bytes_read < length:
332-
if deadline is not None:
333-
# CSOT: Update timeout. When the timeout has expired perform one
334-
# final non-blocking recv. This helps avoid spurious timeouts when
335-
# the response is actually already buffered on the client.
336-
short_timeout = min(max(deadline - time.monotonic(), 0), _POLL_TIMEOUT)
337-
else:
338-
short_timeout = _POLL_TIMEOUT
339-
conn.set_conn_timeout(short_timeout)
340-
try:
341-
chunk_length = conn.conn.recv_into(mv[bytes_read:])
342-
except BLOCKING_IO_ERRORS:
343-
if conn.cancel_context.cancelled:
344-
raise _OperationCancelled("operation cancelled") from None
345-
# We reached the true deadline.
346-
raise socket.timeout("timed out") from None
347-
except socket.timeout:
348-
if conn.cancel_context.cancelled:
349-
raise _OperationCancelled("operation cancelled") from None
350-
continue
351-
except OSError as exc:
352-
if conn.cancel_context.cancelled:
353-
raise _OperationCancelled("operation cancelled") from None
354-
if _errno_from_exception(exc) == errno.EINTR:
355-
continue
356-
raise
357-
if chunk_length == 0:
358-
raise OSError("connection closed")
319+
_PYPY = "PyPy" in sys.version
359320

360-
bytes_read += chunk_length
361-
finally:
362-
conn.set_conn_timeout(orig_timeout)
363-
364-
return mv
365-
else:
366321

367-
def wait_for_read(conn: Connection, deadline: Optional[float]) -> None:
368-
"""Block until at least one byte is read, or a timeout, or a cancel."""
369-
sock = conn.conn
370-
timed_out = False
371-
# Check if the connection's socket has been manually closed
372-
if sock.fileno() == -1:
373-
return
374-
while True:
375-
# SSLSocket can have buffered data which won't be caught by select.
376-
if hasattr(sock, "pending") and sock.pending() > 0:
377-
readable = True
322+
def wait_for_read(conn: Connection, deadline: Optional[float]) -> None:
323+
"""Block until at least one byte is read, or a timeout, or a cancel."""
324+
sock = conn.conn
325+
timed_out = False
326+
# Check if the connection's socket has been manually closed
327+
if sock.fileno() == -1:
328+
return
329+
while True:
330+
# SSLSocket can have buffered data which won't be caught by select.
331+
if hasattr(sock, "pending") and sock.pending() > 0:
332+
readable = True
333+
else:
334+
# Wait up to 500ms for the socket to become readable and then
335+
# check for cancellation.
336+
if deadline:
337+
remaining = deadline - time.monotonic()
338+
# When the timeout has expired perform one final check to
339+
# see if the socket is readable. This helps avoid spurious
340+
# timeouts on AWS Lambda and other FaaS environments.
341+
if remaining <= 0:
342+
timed_out = True
343+
timeout = max(min(remaining, _POLL_TIMEOUT), 0)
378344
else:
379-
# Wait up to 500ms for the socket to become readable and then
380-
# check for cancellation.
381-
if deadline:
382-
remaining = deadline - time.monotonic()
383-
# When the timeout has expired perform one final check to
384-
# see if the socket is readable. This helps avoid spurious
385-
# timeouts on AWS Lambda and other FaaS environments.
386-
if remaining <= 0:
387-
timed_out = True
388-
timeout = max(min(remaining, _POLL_TIMEOUT), 0)
389-
else:
390-
timeout = _POLL_TIMEOUT
391-
readable = conn.socket_checker.select(sock, read=True, timeout=timeout)
392-
if conn.cancel_context.cancelled:
393-
raise _OperationCancelled("operation cancelled")
394-
if readable:
395-
return
396-
if timed_out:
397-
raise socket.timeout("timed out")
345+
timeout = _POLL_TIMEOUT
346+
readable = conn.socket_checker.select(sock, read=True, timeout=timeout)
347+
if conn.cancel_context.cancelled:
348+
raise _OperationCancelled("operation cancelled")
349+
if readable:
350+
return
351+
if timed_out:
352+
raise socket.timeout("timed out")
398353

399-
def receive_data(conn: Connection, length: int, deadline: Optional[float]) -> memoryview:
400-
buf = bytearray(length)
401-
mv = memoryview(buf)
402-
bytes_read = 0
354+
355+
def receive_data(conn: Connection, length: int, deadline: Optional[float]) -> memoryview:
356+
buf = bytearray(length)
357+
mv = memoryview(buf)
358+
bytes_read = 0
359+
# To support cancelling a network read, we shorten the socket timeout and
360+
# check for the cancellation signal after each timeout. Alternatively we
361+
# could close the socket but that does not reliably cancel recv() calls
362+
# on all OSes.
363+
# When the timeout has expired we perform one final non-blocking recv.
364+
# This helps avoid spurious timeouts when the response is actually already
365+
# buffered on the client.
366+
orig_timeout = conn.conn.gettimeout()
367+
try:
403368
while bytes_read < length:
404369
try:
405-
wait_for_read(conn, deadline)
406-
# CSOT: Update timeout. When the timeout has expired perform one
407-
# final non-blocking recv. This helps avoid spurious timeouts when
408-
# the response is actually already buffered on the client.
409-
if _csot.get_timeout() and deadline is not None:
410-
conn.set_conn_timeout(max(deadline - time.monotonic(), 0))
370+
# Use the legacy wait_for_read cancellation approach on PyPy due to PYTHON-5011.
371+
if _PYPY:
372+
wait_for_read(conn, deadline)
373+
if _csot.get_timeout() and deadline is not None:
374+
conn.set_conn_timeout(max(deadline - time.monotonic(), 0))
375+
else:
376+
if deadline is not None:
377+
short_timeout = min(max(deadline - time.monotonic(), 0), _POLL_TIMEOUT)
378+
else:
379+
short_timeout = _POLL_TIMEOUT
380+
conn.set_conn_timeout(short_timeout)
381+
411382
chunk_length = conn.conn.recv_into(mv[bytes_read:])
412383
except BLOCKING_IO_ERRORS:
384+
if conn.cancel_context.cancelled:
385+
raise _OperationCancelled("operation cancelled") from None
386+
# We reached the true deadline.
413387
raise socket.timeout("timed out") from None
388+
except socket.timeout:
389+
if conn.cancel_context.cancelled:
390+
raise _OperationCancelled("operation cancelled") from None
391+
continue
414392
except OSError as exc:
393+
if conn.cancel_context.cancelled:
394+
raise _OperationCancelled("operation cancelled") from None
415395
if _errno_from_exception(exc) == errno.EINTR:
416396
continue
417397
raise
418398
if chunk_length == 0:
419399
raise OSError("connection closed")
420400

421401
bytes_read += chunk_length
402+
finally:
403+
conn.set_conn_timeout(orig_timeout)
422404

423-
return mv
405+
return mv

0 commit comments

Comments
 (0)