15
15
"""Internal network layer helper methods."""
16
16
from __future__ import annotations
17
17
18
- import asyncio
19
18
import datetime
20
- import errno
21
19
import logging
22
- import socket
23
20
import time
24
21
from typing import (
25
22
TYPE_CHECKING ,
40
37
NotPrimaryError ,
41
38
OperationFailure ,
42
39
ProtocolError ,
43
- _OperationCancelled ,
44
40
)
45
41
from pymongo .logger import _COMMAND_LOGGER , _CommandStatusMessage , _debug_log
46
42
from pymongo .message import _UNPACK_REPLY , _OpMsg , _OpReply
47
43
from pymongo .monitoring import _is_speculative_authenticate
48
44
from pymongo .network_layer import (
49
- _POLL_TIMEOUT ,
50
45
_UNPACK_COMPRESSION_HEADER ,
51
46
_UNPACK_HEADER ,
52
- BLOCKING_IO_ERRORS ,
47
+ async_receive_data ,
53
48
async_sendall ,
54
49
)
55
- from pymongo .socket_checker import _errno_from_exception
56
50
57
51
if TYPE_CHECKING :
58
52
from bson import CodecOptions
@@ -318,9 +312,7 @@ async def receive_message(
318
312
else :
319
313
deadline = None
320
314
# Ignore the response's request id.
321
- length , _ , response_to , op_code = _UNPACK_HEADER (
322
- await _receive_data_on_socket (conn , 16 , deadline )
323
- )
315
+ length , _ , response_to , op_code = _UNPACK_HEADER (await async_receive_data (conn , 16 , deadline ))
324
316
# No request_id for exhaust cursor "getMore".
325
317
if request_id is not None :
326
318
if request_id != response_to :
@@ -336,11 +328,11 @@ async def receive_message(
336
328
)
337
329
if op_code == 2012 :
338
330
op_code , _ , compressor_id = _UNPACK_COMPRESSION_HEADER (
339
- await _receive_data_on_socket (conn , 9 , deadline )
331
+ await async_receive_data (conn , 9 , deadline )
340
332
)
341
- data = decompress (await _receive_data_on_socket (conn , length - 25 , deadline ), compressor_id )
333
+ data = decompress (await async_receive_data (conn , length - 25 , deadline ), compressor_id )
342
334
else :
343
- data = await _receive_data_on_socket (conn , length - 16 , deadline )
335
+ data = await async_receive_data (conn , length - 16 , deadline )
344
336
345
337
try :
346
338
unpack_reply = _UNPACK_REPLY [op_code ]
@@ -349,66 +341,3 @@ async def receive_message(
349
341
f"Got opcode { op_code !r} but expected { _UNPACK_REPLY .keys ()!r} "
350
342
) from None
351
343
return unpack_reply (data )
352
-
353
-
354
- async def wait_for_read (conn : AsyncConnection , deadline : Optional [float ]) -> None :
355
- """Block until at least one byte is read, or a timeout, or a cancel."""
356
- sock = conn .conn
357
- timed_out = False
358
- # Check if the connection's socket has been manually closed
359
- if sock .fileno () == - 1 :
360
- return
361
- while True :
362
- # SSLSocket can have buffered data which won't be caught by select.
363
- if hasattr (sock , "pending" ) and sock .pending () > 0 :
364
- readable = True
365
- else :
366
- # Wait up to 500ms for the socket to become readable and then
367
- # check for cancellation.
368
- if deadline :
369
- remaining = deadline - time .monotonic ()
370
- # When the timeout has expired perform one final check to
371
- # see if the socket is readable. This helps avoid spurious
372
- # timeouts on AWS Lambda and other FaaS environments.
373
- if remaining <= 0 :
374
- timed_out = True
375
- timeout = max (min (remaining , _POLL_TIMEOUT ), 0 )
376
- else :
377
- timeout = _POLL_TIMEOUT
378
- readable = conn .socket_checker .select (sock , read = True , timeout = timeout )
379
- if conn .cancel_context .cancelled :
380
- raise _OperationCancelled ("operation cancelled" )
381
- if readable :
382
- return
383
- if timed_out :
384
- raise socket .timeout ("timed out" )
385
- await asyncio .sleep (0 )
386
-
387
-
388
- async def _receive_data_on_socket (
389
- conn : AsyncConnection , length : int , deadline : Optional [float ]
390
- ) -> memoryview :
391
- buf = bytearray (length )
392
- mv = memoryview (buf )
393
- bytes_read = 0
394
- while bytes_read < length :
395
- try :
396
- await wait_for_read (conn , deadline )
397
- # CSOT: Update timeout. When the timeout has expired perform one
398
- # final non-blocking recv. This helps avoid spurious timeouts when
399
- # the response is actually already buffered on the client.
400
- if _csot .get_timeout () and deadline is not None :
401
- conn .set_conn_timeout (max (deadline - time .monotonic (), 0 ))
402
- chunk_length = conn .conn .recv_into (mv [bytes_read :])
403
- except BLOCKING_IO_ERRORS :
404
- raise socket .timeout ("timed out" ) from None
405
- except OSError as exc :
406
- if _errno_from_exception (exc ) == errno .EINTR :
407
- continue
408
- raise
409
- if chunk_length == 0 :
410
- raise OSError ("connection closed" )
411
-
412
- bytes_read += chunk_length
413
-
414
- return mv
0 commit comments