@@ -4543,6 +4543,7 @@ private async Task<Response<ShareFileUploadInfo>> UploadRangeFromUriInternal(
4543
4543
/// A <see cref="RequestFailedException"/> will be thrown if
4544
4544
/// a failure occurs.
4545
4545
/// </remarks>
4546
+ [ ForwardsClientCalls ]
4546
4547
public virtual Response< ShareFileUploadInfo > Upload (
4547
4548
Stream stream ,
4548
4549
ShareFileUploadOptions options ,
@@ -4583,6 +4584,7 @@ public virtual Response<ShareFileUploadInfo> Upload(
4583
4584
/// A <see cref="RequestFailedException"/> will be thrown if
4584
4585
/// a failure occurs.
4585
4586
/// </remarks>
4587
+ [ ForwardsClientCalls ]
4586
4588
public virtual async Task< Response < ShareFileUploadInfo > > UploadAsync (
4587
4589
Stream stream ,
4588
4590
ShareFileUploadOptions options ,
@@ -4833,115 +4835,89 @@ internal async Task<Response<ShareFileUploadInfo>> UploadInternal(
4833
4835
bool async ,
4834
4836
CancellationToken cancellationToken )
4835
4837
{
4836
- Errors . VerifyStreamPosition ( content , nameof ( content ) ) ;
4838
+ var uploader = GetPartitionedUploader(
4839
+ new StorageTransferOptions
4840
+ {
4841
+ // shares can't suppot parallel upload
4842
+ MaximumConcurrency = 1 ,
4843
+ MaximumTransferSize = singleRangeThreshold ,
4844
+ InitialTransferSize = singleRangeThreshold
4845
+ } ,
4846
+ hashingOptions ,
4847
+ operationName : $ "{ nameof ( ShareFileClient ) } .{ nameof ( Upload ) } ") ;
4848
+
4849
+ return await uploader. UploadInternal (
4850
+ content ,
4851
+ expectedContentLength : default ,
4852
+ new ShareFileUploadData
4853
+ {
4854
+ Conditions = conditions ,
4855
+ } ,
4856
+ progressHandler ,
4857
+ async,
4858
+ cancellationToken )
4859
+ . ConfigureAwait ( false ) ;
4860
+ }
4861
+ #endregion Upload
4837
4862
4838
- // partitioned uploads don't support pre-calculated hashes
4839
- if ( hashingOptions ? . PrecalculatedHash != default )
4840
- {
4841
- throw Errors . PrecalculatedHashNotSupportedOnSplit ( ) ;
4842
- }
4863
+ #region PartitionedUploader
4864
+ internal class ShareFileUploadData
4865
+ {
4866
+ public ShareFileRequestConditions Conditions { get ; set ; }
4867
+ public Response< ShareFileUploadInfo > LastUploadRangeResponse { get ; set ; }
4868
+ }
4843
4869
4844
- DiagnosticScope scope = ClientConfiguration . ClientDiagnostics . CreateScope ( $ "{ nameof ( ShareFileClient ) } .{ nameof ( Upload ) } ") ;
4845
- try
4870
+ internal PartitionedUploader< ShareFileUploadData , ShareFileUploadInfo> GetPartitionedUploader (
4871
+ StorageTransferOptions transferOptions ,
4872
+ UploadTransactionalHashingOptions hashingOptions ,
4873
+ ArrayPool < byte > arrayPool = null ,
4874
+ string operationName = null )
4875
+ => new PartitionedUploader < ShareFileUploadData , ShareFileUploadInfo > (
4876
+ GetPartitionedUploaderBehaviors ( this ) ,
4877
+ transferOptions ,
4878
+ hashingOptions ,
4879
+ arrayPool ,
4880
+ operationName ) ;
4881
+
4882
+ // static because it makes mocking easier in tests
4883
+ internal static PartitionedUploader< ShareFileUploadData , ShareFileUploadInfo> . Behaviors GetPartitionedUploaderBehaviors ( ShareFileClient client )
4884
+ => new PartitionedUploader < ShareFileUploadData , ShareFileUploadInfo > . Behaviors
4846
4885
{
4847
- scope . Start ( ) ;
4848
-
4849
- // Try to upload the file as a single range
4850
- Debug . Assert ( singleRangeThreshold <= Constants . File . MaxFileUpdateRange ) ;
4851
- var length = content ? . Length - content ? . Position ;
4852
- if ( length <= singleRangeThreshold )
4886
+ SingleUpload = async ( stream , data , progressHandler , hashingOptions , operationName , async , cancellationToken ) =>
4853
4887
{
4854
- return await UploadRangeInternal (
4855
- new HttpRange ( 0 , length ) ,
4856
- content ,
4888
+ return await client . UploadRangeInternal (
4889
+ new HttpRange ( offset : 0 , length : stream . Length ) ,
4890
+ stream ,
4857
4891
new ShareFileUploadRangeOptions
4858
4892
{
4859
- TransactionalHashingOptions = hashingOptions ,
4893
+ Conditions = data . Conditions ,
4860
4894
ProgressHandler = progressHandler ,
4861
- Conditions = conditions
4895
+ TransactionalHashingOptions = hashingOptions ,
4862
4896
} ,
4863
4897
async,
4864
4898
cancellationToken )
4865
4899
. ConfigureAwait ( false ) ;
4866
- }
4867
-
4868
- // Otherwise naively split the file into ranges and upload them individually
4869
- var response = default ( Response < ShareFileUploadInfo > ) ;
4870
- var pool = default ( MemoryPool < byte > ) ;
4871
- // erase potential precalculated hash now that we're splitting; we'll have to recalculate.
4872
- hashingOptions = hashingOptions == default
4873
- ? default
4874
- : new UploadTransactionalHashingOptions
4875
- {
4876
- Algorithm = hashingOptions . Algorithm
4877
- } ;
4878
-
4879
- long initalPosition = content . Position ;
4880
-
4881
- try
4900
+ } ,
4901
+ UploadPartition = async ( stream , offset , data , progressHandler , hashingOptions , async , cancellationToken ) =>
4882
4902
{
4883
- pool = ( singleRangeThreshold < MemoryPool < byte > . Shared . MaxBufferSize ) ?
4884
- MemoryPool < byte > . Shared :
4885
- new StorageMemoryPool ( singleRangeThreshold , 1 ) ;
4886
- for ( ; ; )
4887
- {
4888
- // Get the next chunk of content
4889
- var parentPosition = content . Position ;
4890
- IMemoryOwner < byte > buffer = pool . Rent ( singleRangeThreshold ) ;
4891
- if ( ! MemoryMarshal . TryGetArray < byte > ( buffer . Memory , out ArraySegment < byte > segment ) )
4903
+ data . LastUploadRangeResponse = await client . UploadRangeInternal (
4904
+ new HttpRange ( offset : offset , length : stream . Length ) ,
4905
+ stream ,
4906
+ new ShareFileUploadRangeOptions
4892
4907
{
4893
- throw Errors . UnableAccessArray ( ) ;
4894
- }
4895
- var count = async ?
4896
- await content . ReadAsync ( segment . Array , 0 , singleRangeThreshold , cancellationToken ) . ConfigureAwait ( false ) :
4897
- content . Read ( segment . Array , 0 , singleRangeThreshold ) ;
4898
-
4899
- // Stop when we've exhausted the content
4900
- if ( count <= 0 )
4901
- { break ; }
4902
-
4903
- // Upload the chunk
4904
- var partition = new StreamPartition (
4905
- buffer . Memory ,
4906
- parentPosition ,
4907
- count ,
4908
- ( ) => buffer . Dispose ( ) ,
4909
- cancellationToken ) ;
4910
- response = await UploadRangeInternal (
4911
- new HttpRange ( partition . ParentPosition - initalPosition , partition . Length ) ,
4912
- partition ,
4913
- new ShareFileUploadRangeOptions
4914
- {
4915
- TransactionalHashingOptions = hashingOptions ,
4916
- ProgressHandler = progressHandler ,
4917
- Conditions = conditions
4918
- } ,
4919
- async,
4920
- cancellationToken )
4921
- . ConfigureAwait ( false ) ;
4922
- }
4923
- }
4924
- finally
4925
- {
4926
- if ( pool is StorageMemoryPool )
4927
- {
4928
- pool . Dispose ( ) ;
4929
- }
4930
- }
4931
- return response ;
4932
- }
4933
- catch ( Exception ex )
4934
- {
4935
- ClientConfiguration . Pipeline . LogException ( ex ) ;
4936
- scope . Failed ( ex ) ;
4937
- throw ;
4938
- }
4939
- finally
4940
- {
4941
- scope . Dispose ( ) ;
4942
- }
4943
- }
4944
- #endregion Upload
4908
+ Conditions = data . Conditions ,
4909
+ ProgressHandler = progressHandler ,
4910
+ TransactionalHashingOptions = hashingOptions ,
4911
+ } ,
4912
+ async,
4913
+ cancellationToken )
4914
+ . ConfigureAwait ( false ) ;
4915
+ } ,
4916
+ CommitPartitionedUpload = ( partitions , data , async , cancellationToken ) => Task . FromResult ( data . LastUploadRangeResponse ) ,
4917
+ Scope = operationName => client . ClientConfiguration . ClientDiagnostics . CreateScope ( operationName ??
4918
+ $ "{ nameof ( Azure ) } .{ nameof ( Storage ) } .{ nameof ( Files ) } .{ nameof ( Shares ) } .{ nameof ( ShareFileClient ) } .{ nameof ( ShareFileClient . Upload ) } ")
4919
+ } ;
4920
+ #endregion
4945
4921
4946
4922
#region GetRangeList
4947
4923
/// <summary>
0 commit comments