11module AzStorage
22
3- using AbstractStorage, AzSessions, AzStorage_jll, Base64, Dates, DelimitedFiles, XML, HTTP, Serialization, Sockets
3+ using AbstractStorage, AzSessions, AzStorage_jll, Base64, Dates, DelimitedFiles, XML, HTTP, Printf, ProgressMeter, Serialization, Sockets
44
55# https://docs.microsoft.com/en-us/rest/api/storageservices/common-rest-api-error-codes
66# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/request-limits-and-throttling
265265
266266function authinfo! (session:: AzSessions.AzVMSession , _token, refresh_token, expiry)
267267 session. expiry = unix2datetime (expiry[1 ])
268- session. token = unsafe_string (point (_token))
268+ session. token = unsafe_string (pointer (_token))
269269end
270270
271271"""
@@ -726,37 +726,43 @@ copy a blob to a local file, a local file to a blob, or a blob to a blob.
726726
727727## local file to blob
728728```
729- cp("localfile.txt", AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt")
729+ cp("localfile.txt", AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt"; buffersize=2_000_000_000, show_progress=false )
730730```
731731
732732## blob to local file
733733```
734- cp(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt", "localfile.txt", buffersize=2_000_000_000)
734+ cp(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt", "localfile.txt", buffersize=2_000_000_000, show_progress=false )
735735```
736- `buffersize` is the memory buffer size (in bytes) used in the copy algorithm, and defaults to `2_000_000_000` bytes (2GB).
737-
736+ `buffersize` is the memory buffer size (in bytes) used in the copy algorithm, and defaults to `2_000_000_000` bytes (2GB). Note that
737+ half of this memory is used to buffer reads, and the other half is used to buffer writes. Set `show_progress=true` to display a
738+ progress bar for the copy operation.
738739## blob to blob
739740```
740741cp(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob_in.txt", AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob_out.txt")
741742```
742743"""
743- function Base. cp (in:: AbstractString , outc:: AzContainer , outb:: AbstractString ; buffersize= 2_000_000_000 )
744+ function Base. cp (in:: AbstractString , outc:: AzContainer , outb:: AbstractString ; buffersize= 2_000_000_000 , show_progress = false )
744745 if Sys. iswindows ()
745746 bytes = read! (in, Vector {UInt8} (undef, filesize (in)))
746747 write (outc, outb, bytes)
747748 else
748749 n = filesize (in)
749- _nblocks = nblocks (outc. nthreads, n, div (buffersize, outc. nthreads))
750+ _buffersize = div (buffersize, 2 )
751+ _nblocks = nblocks (outc. nthreads, n, div (_buffersize, outc. nthreads))
750752 _blockids = blockids (_nblocks)
751753 nominal_bytes_per_block,remaining_bytes_per_block = divrem (n, _nblocks)
752- nblocks_per_buffer,remaining_blocks_per_buffer = divrem (buffersize , nominal_bytes_per_block)
754+ nblocks_per_buffer,remaining_blocks_per_buffer = divrem (_buffersize , nominal_bytes_per_block)
753755 nblocks_per_buffer += remaining_blocks_per_buffer > 0 ? 1 : 0
754756
755- buffer = Vector {UInt8} (undef, nblocks_per_buffer* (nominal_bytes_per_block + 1 ))
757+ buffer_read,buffer_write = ntuple (_ -> Vector {UInt8} (undef, nblocks_per_buffer* (nominal_bytes_per_block + 1 )), 2 )
756758
759+ tsk_write = @async nothing
757760 i2byte = nbytes_buffer = 0
758761 i1block = 1
759762 io = open (in, " r" )
763+ iter = 1 : _nblocks
764+ speed_read,speed_write = 0.0 ,0.0
765+ progress = Progress (length (iter); enabled= show_progress, desc= " read/write = 0.00/0.00 MB/s" )
760766 for iblock = 1 : _nblocks
761767 i1byte = i2byte + 1
762768
@@ -768,28 +774,59 @@ function Base.cp(in::AbstractString, outc::AzContainer, outb::AbstractString; bu
768774
769775 nbytes_buffer += i2byte - i1byte + 1
770776
771- if iblock == _nblocks || nbytes_buffer >= buffersize
772- _buffer = @view buffer[1 : nbytes_buffer]
773- read! (io, _buffer)
774- writebytes_block (outc, outb, _buffer, _blockids[i1block: iblock])
777+ if iblock == _nblocks || nbytes_buffer >= _buffersize
778+ _buffer_read = @view buffer_read[1 : nbytes_buffer]
779+ t_read = @elapsed read! (io, _buffer_read)
780+ speed_read = (nbytes_buffer / 1_000_000 ) / t_read
781+
782+ wait (tsk_write)
783+ buffer_read,buffer_write = buffer_write,buffer_read
784+
785+ nbytes_buffer_write,i1block_write,iblock_write = nbytes_buffer,i1block,iblock
786+ _buffer_write = @view buffer_write[1 : nbytes_buffer_write]
787+ tsk_write = @async begin
788+ t_write = @elapsed writebytes_block (outc, outb, _buffer_write, _blockids[i1block_write: iblock_write])
789+ speed_write = (nbytes_buffer_write / 1_000_000 ) / t_write
790+ end
775791 i1block = iblock + 1
776792 nbytes_buffer = 0
777793 end
794+ progress. core. desc = @sprintf " read/write = %.2f/%.2f MB/s" speed_read speed_write
795+ next! (progress)
778796 end
797+ wait (tsk_write)
779798 putblocklist (outc, outb, _blockids)
780799 end
781800end
782801
783- function Base. cp (inc:: AzContainer , inb:: AbstractString , out:: AbstractString ; buffersize= 2_000_000_000 )
802+ function Base. cp (inc:: AzContainer , inb:: AbstractString , out:: AbstractString ; buffersize= 2_000_000_000 , show_progress = false )
784803 n = filesize (inc, inb)
785804 io = open (out, " w" )
786- buffer = Vector {UInt8} (undef, min (buffersize, n))
787- for i1 = 0 : buffersize: n- 1
788- _buffersize = min (buffersize, n - i1)
789- _buffer = buffersize == _buffersize ? buffer : view (buffer, 1 : _buffersize)
790- read! (inc, inb, _buffer, offset= i1)
791- write (io, _buffer)
805+ _buffersize = div (buffersize, 2 )
806+ buffer_read,buffer_write = ntuple (_-> Vector {UInt8} (undef, min (_buffersize, n)), 2 )
807+ tsk_write = @async nothing
808+ speed_read,speed_write = 0.0 ,0.0
809+ iter = 0 : _buffersize: n- 1
810+ progress = Progress (length (iter); enabled= show_progress, desc= " read/write = 0.00/0.00 MB/s" )
811+ for i1 = iter
812+ __buffersize = min (_buffersize, n - i1)
813+ _buffer_read = _buffersize == __buffersize ? buffer_read : view (buffer_read, 1 : __buffersize)
814+ t_read = @elapsed read! (inc, inb, _buffer_read, offset= i1)
815+ speed_read = (__buffersize / 1_000_000 ) / t_read
816+
817+ wait (tsk_write)
818+ buffer_read,buffer_write = buffer_write,buffer_read
819+
820+ __buffersize_write = __buffersize
821+ _buffer_write = _buffersize == __buffersize ? buffer_write : view (buffer_write, 1 : __buffersize_write)
822+ tsk_write = @async begin
823+ t_write = @elapsed write (io, _buffer_write)
824+ speed_write = (__buffersize_write / 1_000_000 ) / t_write
825+ end
826+ progress. core. desc = @sprintf " read/write = %.2f/%.2f MB/s" speed_read speed_write
827+ next! (progress)
792828 end
829+ wait (tsk_write)
793830 close (io)
794831end
795832
@@ -807,14 +844,16 @@ copy a blob to a local file, a local file to a blob, or a blob to a blob.
807844
808845## local file to blob
809846```
810- cp("localfile.txt", open(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt"))
847+ cp("localfile.txt", open(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt"); buffersize=2_000_000_000, show_progress=false )
811848```
812849
813850## blob to local file
814851```
815- cp(open(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt"), "localfile.txt"; buffersize=2_000_000_000)
852+ cp(open(AzContainer("mycontainer";storageaccount="mystorageaccount"), "remoteblob.txt"), "localfile.txt"; buffersize=2_000_000_000, show_progress=false )
816853```
817- `buffersize` is the memory buffer size (in bytes) used in the copy algorithm, and defaults to `2_000_000_000` bytes (2GB).
854+ `buffersize` is the memory buffer size (in bytes) used in the copy algorithm, and defaults to `2_000_000_000` bytes (2GB). Note that
855+ half of this memory is used to buffer reads, and the other half is used to buffer writes. Set `show_progress=true` to display a
856+ progress bar for the copy operation.
818857
819858## blob to blob
820859```
0 commit comments