
                             S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKJr  SSKJ	r	  SSKJ
r
   " S	 S
\
R                  5      rg)zJImplements a file wrapper used for in-flight retries of streaming uploads.    )absolute_import)division)unicode_literalsN)errors)	hash_util)upload_streamc                      ^  \ rS rSrSr  SU 4S jjrS rS rS rS r	S r
SU 4S	 jjr\R                  4S
 jrS rSrU =r$ )BufferedUploadStream   zHSupports limited seeking within a non-seekable stream by buffering data.c                    > [         TU ]  USUUS9  [        R                  " 5       U l        X l        SU l        SU l        SU l        [        R                  " U R                  5      U l        g)a  Initializes a FilePart instance.

Args:
  stream (io.IOBase): The underlying stream wrapped by this class.
  max_buffer_size: Maximum size of the internal buffer. This should be >= to
      the chunk size used by the API to execute streaming uploads to ensure
      that at least one full chunk write can be repeated in the event of a
      server error.
  digesters (dict[util.HashAlgorithm, hashlib hash object]|None): See super
    class.
  progress_callback (func[int]|None): See super class.
N)streamlength	digestersprogress_callbackr   )super__init__collectionsdeque_buffer_max_buffer_size_buffer_start	_position_buffer_endr   copy_digesters
_digesters_checkpoint_digesters)selfr   max_buffer_sizer   r   	__class__s        @lib/googlecloudsdk/command_lib/storage/buffered_upload_stream.pyr   BufferedUploadStream.__init__!   sk    " 
)T#+	 $ - $$&DL+DDND!*!9!9$//!JD    c                     U R                   $ Nr   r   s    r    _get_absolute_position+BufferedUploadStream._get_absolute_position@   s    >>r"   c                     Xl         g r$   r%   )r   offsets     r    _update_absolute_position.BufferedUploadStream._update_absolute_positionC   s    Nr"   c                    / nUnU R                   U R                  :  a  U R                  nU R                   H  nU[	        U5      -   U R                   :  aW  U R                   U-
  n[	        U5      U-
  n[        Xs5      nUR                  XVUU-    5        X8-  nU =R                   U-  sl         U[	        U5      -  nM     SR                  U5      $ )a  Get any buffered data required to complete a read.

If a backward seek has not happened, the buffer will never contain any
information needed to complete a read call. Return the empty string in
these cases.

If the current position is before the end of the buffer, some of the
requested bytes will be in the buffer. For example, if our position is 1,
five bytes are being read, and the buffer contains b'0123', we will return
b'123'. Two additional bytes will be read from the stream at a later stage.

Args:
  amount (int): The total number of bytes to be read

Returns:
  A byte string, the length of which is equal to `amount` if there are
  enough buffered bytes to complete the read, or less than `amount` if there
  are not.
r"   )r   r   r   r   lenminappendjoin)	r   amountbuffered_databytes_remainingposition_in_bufferdataoffset_from_positionbytes_to_read_this_block	read_sizes	            r    _read_from_buffer&BufferedUploadStream._read_from_bufferF   s    ( MO~~(((--,,$D	)T^^;!%2D!D
%(Y1E%E
"2D)


t9M$-:.  / 0

&/
..I
%.c$i'  88M""r"   c                     g)a  Disables parent class digester checkpointing behavior.

To guarantee that seeks within the buffer are possible, we need to ensure
that the checkpoint is aligned with the buffer's start_byte. This is not
possible if we save digester checkpoints when the parent class does so.
N r&   s    r    _save_digesters_checkpoint/BufferedUploadStream._save_digesters_checkpointk   s     	r"   c                    U(       Gan  U R                   R                  U5        U =R                  [        U5      -  sl        SnU R                  U R                  -
  U R
                  :  Ga
  U R                   R                  5       nU =R                  [        U5      -  sl        U(       a  U R
                  U R                  U R                  -
  -
  nUS:  a3  U R                   R                  X#* S 5        U =R                  U-  sl        [        R                  " U R                  US[        U5      U-
   5        U R                  U l        U R                  U R                  -
  U R
                  :  a  GM	  ggg)aX  Adds data to the buffer, respecting max_buffer_size.

The buffer can consist of many different blocks of data, e.g.

  [b'0', b'12', b'3']

With a maximum size of 4, if we read two bytes, we must discard the oldest
data and keep half of the second-oldest block:

  [b'2', b'3', b'45']

Args:
  data (bytes): the data being added to the buffer.
N   )r   r0   r   r.   r   r   popleft
appendleftr   update_digestersr   _checkpoint_absolute_index)r   r6   oldest_datarefill_amounts       r    _store_data BufferedUploadStream._store_datat   s:    
ll$
#d)#kt111D4I4IIll**,c+..//!3!335-aLL##K$@A-/ 
$
$((;3{+m;<> -1,>,>$
) t111D4I4III	 r"   c                 T  > USL =(       d    US:  nU(       a  U R                   nOUnU R                  U5      nU[        U5      -  nU(       a  [        TU ]  S5      nOU(       a  [        TU ]  U5      nOSnU =R
                  [        U5      -  sl        U R                  U5        XE-   $ )zReads from the wrapped stream.

Args:
  size: The amount of bytes to read. If omitted or negative, the entire
      stream will be read and returned.

Returns:
  Bytes from the wrapped stream.
Nr   r"   )r   r:   r.   r   	_get_datar   rH   )r   sizeread_all_bytesr4   r6   new_datar   s         r    rL   BufferedUploadStream._get_data   s     T\-TAXN--oo!!/2Ds4y Oy$1"5h	y$1/BhhNNc(m#NX?r"   c                    U[         R                  :X  a[  XR                  :  d  XR                  :  a:  [        R
                  " SR                  XR                  U R                  5      5      eUnOU[         R                  :X  a  [        U5      U R                  :  a/  [        R
                  " SR                  XR                  5      5      eU R                  U R                  5      (       a#   U R                  U R                  5      (       a  M#  U R                  U-   nO%[        R
                  " SR                  X!5      5      eU R                  U5        X0l        g)z!Seeks within the buffered stream.zUnable to recover from an upload error because limited buffering is available for streaming uploads. Offset {} was requested, but only data from {} to {} is buffered.zNInvalid SEEK_END offset {} on streaming upload. Only {} bytes can be buffered.z;Invalid seek mode on streaming upload. Mode: {}, offset: {}N)osSEEK_SETr   r   r   ErrorformatSEEK_ENDabsr   readr   _catch_up_digesters)r   r*   whencenew_positions       r    seekBufferedUploadStream.seek   s   	$$	$1A1A(All44:F**D,<,<5>? 	?
 l	2;;	 
Vt,,	,ll  &v/D/D EG 	G IId++,, IId++,,^^f,lLL
G
N
N  	\*!Nr"   c                     g)aY  Indicates that this stream is not seekable.

Needed so that boto3 can correctly identify how to treat this stream.
The library attempts to seek to the beginning after an upload completes,
which is not always possible.

Apitools does not check the return value of this method, so it will not
raise issues for resumable uploads.

Returns:
  False
Fr=   r&   s    r    seekableBufferedUploadStream.seekable   s     r"   )r   r   r   rE   r   r   r   )NN)rK   )__name__
__module____qualname____firstlineno____doc__r   r'   r+   r:   r>   rH   rL   rR   rS   r\   r_   __static_attributes____classcell__)r   s   @r    r
   r
      sM    P
 !%	K>##J	"?H@ !# "8 r"   r
   )re   
__future__r   r   r   r   rR   "googlecloudsdk.command_lib.storager   r   r   UploadStreamr
   r=   r"   r    <module>rk      s7     Q &  '  	 5 8 <C=55 Cr"   