Skip to content

Commit 52d355d

Browse files
Progress Reporting Blob Downloads (Azure#26838)
* added progress to base download * tests * downloadTo and tests * exportapi * changelog * null safety Co-authored-by: jschrepp-MSFT <41338290+jschrepp-MSFT@users.noreply.github.com>
1 parent 2c4505a commit 52d355d

File tree

41 files changed

+7979
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+7979
-21
lines changed

sdk/storage/Azure.Storage.Blobs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 12.11.0-beta.4 (Unreleased)
44

55
### Features Added
6+
- Added support for progress reporting with DownloadToAsync().
67

78
### Breaking Changes
89

sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ public partial class BlobDownloadOptions
507507
{
508508
public BlobDownloadOptions() { }
509509
public Azure.Storage.Blobs.Models.BlobRequestConditions Conditions { get { throw null; } set { } }
510+
public System.IProgress<long> ProgressHandler { get { throw null; } set { } }
510511
public Azure.HttpRange Range { get { throw null; } set { } }
511512
public Azure.Storage.DownloadTransactionalHashingOptions TransactionalHashingOptions { get { throw null; } set { } }
512513
}
@@ -527,6 +528,7 @@ public partial class BlobDownloadToOptions
527528
{
528529
public BlobDownloadToOptions() { }
529530
public Azure.Storage.Blobs.Models.BlobRequestConditions Conditions { get { throw null; } set { } }
531+
public System.IProgress<long> ProgressHandler { get { throw null; } set { } }
530532
public Azure.Storage.DownloadTransactionalHashingOptions TransactionalHashingOptions { get { throw null; } set { } }
531533
public Azure.Storage.StorageTransferOptions TransferOptions { get { throw null; } set { } }
532534
}

sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,8 @@ private async Task<Response<BlobDownloadStreamingResult>> DownloadStreamingInter
13021302
ClientConfiguration.Pipeline.ResponseClassifier,
13031303
Constants.MaxReliabilityRetries);
13041304

1305+
stream = stream.WithNoDispose().WithProgress(options?.ProgressHandler);
1306+
13051307
/* NOTE: we do not currently support both features together. This remains here for the
13061308
* potential future where we do.
13071309
* Comparing hash results comes BEFORE decryption.
@@ -2063,7 +2065,7 @@ public virtual Response DownloadTo(
20632065
return StagedDownloadAsync(
20642066
destination,
20652067
options?.Conditions,
2066-
//options.ProgressHandler, // TODO: #8506
2068+
options?.ProgressHandler,
20672069
options?.TransferOptions ?? default,
20682070
options?.TransactionalHashingOptions,
20692071
async: false,
@@ -2102,7 +2104,7 @@ public virtual Response DownloadTo(
21022104
return StagedDownloadAsync(
21032105
destination,
21042106
options?.Conditions,
2105-
//options.ProgressHandler, // TODO: #8506
2107+
options?.ProgressHandler,
21062108
options?.TransferOptions ?? default,
21072109
options?.TransactionalHashingOptions,
21082110
async: false,
@@ -2140,7 +2142,7 @@ public virtual async Task<Response> DownloadToAsync(
21402142
return await StagedDownloadAsync(
21412143
destination,
21422144
options?.Conditions,
2143-
//options.ProgressHandler, // TODO: #8506
2145+
options?.ProgressHandler,
21442146
options?.TransferOptions ?? default,
21452147
options?.TransactionalHashingOptions,
21462148
async: true,
@@ -2179,7 +2181,7 @@ public virtual async Task<Response> DownloadToAsync(
21792181
return await StagedDownloadAsync(
21802182
destination,
21812183
options?.Conditions,
2182-
//options.ProgressHandler, // TODO: #8506
2184+
options?.ProgressHandler,
21832185
options?.TransferOptions ?? default,
21842186
options?.TransactionalHashingOptions,
21852187
async: true,
@@ -2393,6 +2395,10 @@ public virtual async Task<Response> DownloadToAsync(
23932395
/// Optional <see cref="BlobRequestConditions"/> to add conditions on
23942396
/// the creation of this new block blob.
23952397
/// </param>
2398+
/// <param name="progressHandler">
2399+
/// Optional <see cref="IProgress{Long}"/> to provide
2400+
/// progress updates about data transfers.
2401+
/// </param>
23962402
/// <param name="transferOptions">
23972403
/// Optional <see cref="StorageTransferOptions"/> to configure
23982404
/// parallel transfer behavior.
@@ -2417,17 +2423,13 @@ public virtual async Task<Response> DownloadToAsync(
24172423
internal async Task<Response> StagedDownloadAsync(
24182424
Stream destination,
24192425
BlobRequestConditions conditions = default,
2420-
///// <param name="progressHandler">
2421-
///// Optional <see cref="IProgress{Long}"/> to provide
2422-
///// progress updates about data transfers.
2423-
///// </param>
2424-
//IProgress<long> progressHandler, // TODO: #8506
2426+
IProgress<long> progressHandler = default,
24252427
StorageTransferOptions transferOptions = default,
24262428
DownloadTransactionalHashingOptions hashingOptions = default,
24272429
bool async = true,
24282430
CancellationToken cancellationToken = default)
24292431
{
2430-
PartitionedDownloader downloader = new PartitionedDownloader(this, transferOptions, hashingOptions);
2432+
PartitionedDownloader downloader = new PartitionedDownloader(this, transferOptions, hashingOptions, progressHandler);
24312433

24322434
if (UsingClientSideEncryption)
24332435
{

sdk/storage/Azure.Storage.Blobs/src/Models/BlobDownloadOptions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public class BlobDownloadOptions
2323
/// </summary>
2424
public BlobRequestConditions Conditions { get; set; }
2525

26+
/// <summary>
27+
/// Optional <see cref="IProgress{Long}"/> to provide
28+
/// progress updates about data transfers.
29+
/// </summary>
30+
public IProgress<long> ProgressHandler { get; set; }
31+
2632
/// <summary>
2733
/// Optional transactional hashing options.
2834
/// Range must be provided explicitly stating a range withing Azure
@@ -49,6 +55,7 @@ private BlobDownloadOptions(BlobDownloadOptions deepCopySource)
4955

5056
Range = new HttpRange(offset: deepCopySource.Range.Offset, length: deepCopySource.Range.Length);
5157
Conditions = BlobRequestConditions.CloneOrDefault(deepCopySource.Conditions);
58+
ProgressHandler = deepCopySource.ProgressHandler;
5259
// can't access an internal deep copy in Storage.Common
5360
TransactionalHashingOptions = deepCopySource.TransactionalHashingOptions == default
5461
? default

sdk/storage/Azure.Storage.Blobs/src/Models/BlobDownloadToOptions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ public class BlobDownloadToOptions
1616
/// </summary>
1717
public BlobRequestConditions Conditions { get; set; }
1818

19-
///// <summary>
20-
///// Progress handler for tracking download progress.
21-
///// </summary>
22-
// public IProgress<long> ProgressHandler { get; set; }
19+
/// <summary>
20+
/// Progress handler for tracking download progress.
21+
/// </summary>
22+
public IProgress<long> ProgressHandler { get; set; }
2323

2424
/// <summary>
2525
/// Transfer options for managing individual read requests.

sdk/storage/Azure.Storage.Blobs/src/PartitionedDownloader.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@ internal class PartitionedDownloader
3939

4040
private readonly DownloadTransactionalHashingOptions _hashingOptions;
4141

42+
private readonly IProgress<long> _progress;
43+
4244
public PartitionedDownloader(
4345
BlobBaseClient client,
4446
StorageTransferOptions transferOptions = default,
45-
DownloadTransactionalHashingOptions hashingOptions = default)
47+
DownloadTransactionalHashingOptions hashingOptions = default,
48+
IProgress<long> progress = default)
4649
{
4750
_client = client;
4851

@@ -86,6 +89,15 @@ public PartitionedDownloader(
8689
}
8790

8891
_hashingOptions = hashingOptions;
92+
_progress = progress;
93+
94+
/* Unlike partitioned upload, download cannot tell ahead of time if it will split and/or parallelize
95+
* after first call. Instead of applying progress handling to initial download stream after-the-fact,
96+
* wrap a given progress handler in an aggregator upfront and accept the overhead. */
97+
if (_progress != null && _progress is not AggregatingProgressIncrementer)
98+
{
99+
_progress = new AggregatingProgressIncrementer(_progress);
100+
}
89101
}
90102

91103
public async Task<Response> DownloadToAsync(
@@ -111,7 +123,8 @@ public async Task<Response> DownloadToAsync(
111123
{
112124
Range = initialRange,
113125
Conditions = conditions,
114-
TransactionalHashingOptions = _hashingOptions
126+
TransactionalHashingOptions = _hashingOptions,
127+
ProgressHandler = _progress,
115128
},
116129
cancellationToken);
117130

@@ -127,7 +140,8 @@ public async Task<Response> DownloadToAsync(
127140
{
128141
Range = default,
129142
Conditions = conditions,
130-
TransactionalHashingOptions = _hashingOptions
143+
TransactionalHashingOptions = _hashingOptions,
144+
ProgressHandler = _progress,
131145
},
132146
cancellationToken)
133147
.ConfigureAwait(false);
@@ -183,7 +197,8 @@ await CopyToAsync(
183197
{
184198
Range = httpRange,
185199
Conditions = conditionsWithEtag,
186-
TransactionalHashingOptions = _hashingOptions
200+
TransactionalHashingOptions = _hashingOptions,
201+
ProgressHandler = _progress,
187202
},
188203
cancellationToken));
189204

@@ -265,7 +280,8 @@ public Response DownloadTo(
265280
{
266281
Range = initialRange,
267282
Conditions = conditions,
268-
TransactionalHashingOptions = _hashingOptions
283+
TransactionalHashingOptions = _hashingOptions,
284+
ProgressHandler = _progress,
269285
},
270286
cancellationToken);
271287
}
@@ -276,7 +292,8 @@ public Response DownloadTo(
276292
{
277293
Range = default,
278294
Conditions = conditions,
279-
TransactionalHashingOptions = _hashingOptions
295+
TransactionalHashingOptions = _hashingOptions,
296+
ProgressHandler = _progress,
280297
},
281298
cancellationToken);
282299
}
@@ -316,7 +333,8 @@ public Response DownloadTo(
316333
{
317334
Range = httpRange,
318335
Conditions = conditionsWithEtag,
319-
TransactionalHashingOptions = _hashingOptions
336+
TransactionalHashingOptions = _hashingOptions,
337+
ProgressHandler = _progress,
320338
},
321339
cancellationToken);
322340
CopyTo(result.Value, destination, cancellationToken);

0 commit comments

Comments
 (0)